All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/12] gpio: Tight IRQ chip integration and Tegra186 support
@ 2017-04-03 16:05 Thierry Reding
  2017-04-03 16:05 ` [PATCH 02/12] gpio: Implement tighter IRQ chip integration Thierry Reding
                   ` (5 more replies)
  0 siblings, 6 replies; 20+ messages in thread
From: Thierry Reding @ 2017-04-03 16:05 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Alexandre Courbot, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA

From: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

Hi Linus,

here's a first draft of patches to make GPIOLIB_IRQCHIP flexible enough
to support the Tegra186 use-case. Instead of just fixing the bugs that I
had pointed out earlier, this goes one step further and completely
integrates IRQ chip registration into GPIO chip registration. The idea
is that drivers will initialize a set of fields (collected in a new
struct gpio_irq_chip) before calling gpiochip_add() (or derivatives) and
gpiolib will internally set up an IRQ domain and register the IRQ chip.

Currently this makes use of the new infrastructure only in the Tegra186
driver, but I plan to convert a couple of others once we can agree that
this is a direction that you're comfortable with.

Thierry

Thierry Reding (12):
  gpio: Use unsigned int for interrupt numbers
  gpio: Implement tighter IRQ chip integration
  gpio: Move irq_nested into struct gpio_irq_chip
  gpio: Move irqdomain into struct gpio_irq_chip
  gpio: Move irqchip into struct gpio_irq_chip
  gpio: Move irq_valid_mask into struct gpio_irq_chip
  gpio: Move lock_key into struct gpio_irq_chip
  gpio: Move irq_chained_parent to struct gpio_irq_chip
  gpio: Move irq_default_type to struct gpio_irq_chip
  gpio: Move irq_handler to struct gpio_irq_chip
  gpio: Move irq_base to struct gpio_irq_chip
  gpio: Add Tegra186 support

 Documentation/gpio/driver.txt              |   6 +-
 drivers/bcma/driver_gpio.c                 |   2 +-
 drivers/gpio/Kconfig                       |   9 +
 drivers/gpio/Makefile                      |   1 +
 drivers/gpio/gpio-104-dio-48e.c            |   2 +-
 drivers/gpio/gpio-104-idi-48.c             |   2 +-
 drivers/gpio/gpio-104-idio-16.c            |   2 +-
 drivers/gpio/gpio-adnp.c                   |   2 +-
 drivers/gpio/gpio-altera.c                 |   4 +-
 drivers/gpio/gpio-aspeed.c                 |   6 +-
 drivers/gpio/gpio-ath79.c                  |   2 +-
 drivers/gpio/gpio-brcmstb.c                |   2 +-
 drivers/gpio/gpio-crystalcove.c            |   2 +-
 drivers/gpio/gpio-dln2.c                   |   2 +-
 drivers/gpio/gpio-ftgpio010.c              |   2 +-
 drivers/gpio/gpio-intel-mid.c              |   2 +-
 drivers/gpio/gpio-lynxpoint.c              |   2 +-
 drivers/gpio/gpio-max732x.c                |   2 +-
 drivers/gpio/gpio-mcp23s08.c               |   2 +-
 drivers/gpio/gpio-merrifield.c             |   2 +-
 drivers/gpio/gpio-mockup.c                 |  10 +-
 drivers/gpio/gpio-omap.c                   |   2 +-
 drivers/gpio/gpio-pca953x.c                |   2 +-
 drivers/gpio/gpio-pcf857x.c                |   2 +-
 drivers/gpio/gpio-pci-idio-16.c            |   2 +-
 drivers/gpio/gpio-pl061.c                  |   2 +-
 drivers/gpio/gpio-rcar.c                   |   2 +-
 drivers/gpio/gpio-reg.c                    |   4 +-
 drivers/gpio/gpio-stmpe.c                  |   6 +-
 drivers/gpio/gpio-tc3589x.c                |   2 +-
 drivers/gpio/gpio-tegra186.c               | 625 +++++++++++++++++++++++++++++
 drivers/gpio/gpio-vf610.c                  |   2 +-
 drivers/gpio/gpio-wcove.c                  |   2 +-
 drivers/gpio/gpio-ws16c48.c                |   2 +-
 drivers/gpio/gpio-xgene-sb.c               |   2 +-
 drivers/gpio/gpio-xlp.c                    |   2 +-
 drivers/gpio/gpio-zx.c                     |   2 +-
 drivers/gpio/gpio-zynq.c                   |   2 +-
 drivers/gpio/gpiolib.c                     | 232 ++++++++---
 drivers/pinctrl/bcm/pinctrl-bcm2835.c      |   4 +-
 drivers/pinctrl/bcm/pinctrl-iproc-gpio.c   |   2 +-
 drivers/pinctrl/intel/pinctrl-baytrail.c   |   6 +-
 drivers/pinctrl/intel/pinctrl-cherryview.c |   6 +-
 drivers/pinctrl/intel/pinctrl-intel.c      |   2 +-
 drivers/pinctrl/nomadik/pinctrl-nomadik.c  |   4 +-
 drivers/pinctrl/pinctrl-amd.c              |   2 +-
 drivers/pinctrl/pinctrl-at91.c             |   2 +-
 drivers/pinctrl/pinctrl-coh901.c           |   2 +-
 drivers/pinctrl/pinctrl-oxnas.c            |   2 +-
 drivers/pinctrl/pinctrl-pic32.c            |   2 +-
 drivers/pinctrl/pinctrl-pistachio.c        |   2 +-
 drivers/pinctrl/pinctrl-st.c               |   2 +-
 drivers/pinctrl/pinctrl-sx150x.c           |   2 +-
 drivers/pinctrl/qcom/pinctrl-msm.c         |   2 +-
 drivers/pinctrl/sirf/pinctrl-atlas7.c      |   2 +-
 drivers/pinctrl/sirf/pinctrl-sirf.c        |   2 +-
 drivers/pinctrl/spear/pinctrl-plgpio.c     |   2 +-
 include/linux/gpio/driver.h                |  81 ++--
 58 files changed, 943 insertions(+), 147 deletions(-)
 create mode 100644 drivers/gpio/gpio-tegra186.c

-- 
2.12.0

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 01/12] gpio: Use unsigned int for interrupt numbers
       [not found] ` <20170403160532.20282-1-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2017-04-03 16:05   ` Thierry Reding
       [not found]     ` <20170403160532.20282-2-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  2017-04-03 16:05   ` [PATCH 03/12] gpio: Move irq_nested into struct gpio_irq_chip Thierry Reding
                     ` (7 subsequent siblings)
  8 siblings, 1 reply; 20+ messages in thread
From: Thierry Reding @ 2017-04-03 16:05 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Alexandre Courbot, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA

From: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

Interrupt numbers are never negative, zero serves as the special invalid
value.

Signed-off-by: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 drivers/gpio/gpiolib.c      | 6 +++---
 include/linux/gpio/driver.h | 6 +++---
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 4aa1e78f0f0b..7a0df48e09da 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1515,7 +1515,7 @@ static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
  */
 static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
 					  struct irq_chip *irqchip,
-					  int parent_irq,
+					  unsigned int parent_irq,
 					  irq_flow_handler_t parent_handler)
 {
 	unsigned int offset;
@@ -1564,7 +1564,7 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
  */
 void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
 				  struct irq_chip *irqchip,
-				  int parent_irq,
+				  unsigned int parent_irq,
 				  irq_flow_handler_t parent_handler)
 {
 	gpiochip_set_cascaded_irqchip(gpiochip, irqchip, parent_irq,
@@ -1581,7 +1581,7 @@ EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip);
  */
 void gpiochip_set_nested_irqchip(struct gpio_chip *gpiochip,
 				 struct irq_chip *irqchip,
-				 int parent_irq)
+				 unsigned int parent_irq)
 {
 	if (!gpiochip->irq_nested) {
 		chip_err(gpiochip, "tried to nest a chained gpiochip\n");
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 846f3b989480..393582867afd 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -168,7 +168,7 @@ struct gpio_chip {
 	unsigned int		irq_base;
 	irq_flow_handler_t	irq_handler;
 	unsigned int		irq_default_type;
-	int			irq_chained_parent;
+	unsigned int		irq_chained_parent;
 	bool			irq_nested;
 	bool			irq_need_valid_mask;
 	unsigned long		*irq_valid_mask;
@@ -244,12 +244,12 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,
 
 void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
 		struct irq_chip *irqchip,
-		int parent_irq,
+		unsigned int parent_irq,
 		irq_flow_handler_t parent_handler);
 
 void gpiochip_set_nested_irqchip(struct gpio_chip *gpiochip,
 		struct irq_chip *irqchip,
-		int parent_irq);
+		unsigned int parent_irq);
 
 int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 			     struct irq_chip *irqchip,
-- 
2.12.0

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 02/12] gpio: Implement tighter IRQ chip integration
  2017-04-03 16:05 [PATCH 00/12] gpio: Tight IRQ chip integration and Tegra186 support Thierry Reding
@ 2017-04-03 16:05 ` Thierry Reding
       [not found] ` <20170403160532.20282-1-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 20+ messages in thread
From: Thierry Reding @ 2017-04-03 16:05 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Alexandre Courbot, linux-gpio, linux-tegra

From: Thierry Reding <treding@nvidia.com>

Currently GPIO drivers are required to a GPIO chip and the corresponding
IRQ chip separately, which can result in a lot of boilerplate. Introduce
a new struct gpio_irq_chip, embedded in a struct gpio_chip, that drivers
can fill in if they want the GPIO core to automatically register the IRQ
chip associated with a GPIO chip.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/gpio/gpiolib.c      | 157 ++++++++++++++++++++++++++++++++++++++++++--
 include/linux/gpio/driver.h |  39 +++++++++++
 2 files changed, 192 insertions(+), 4 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 7a0df48e09da..d403a0572d4b 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -72,6 +72,7 @@ static LIST_HEAD(gpio_lookup_list);
 LIST_HEAD(gpio_devices);
 
 static void gpiochip_free_hogs(struct gpio_chip *chip);
+static int gpiochip_add_irqchip(struct gpio_chip *gpiochip);
 static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
 static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip);
 static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip);
@@ -1240,6 +1241,10 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
 	if (status)
 		goto err_remove_from_list;
 
+	status = gpiochip_add_irqchip(chip);
+	if (status)
+		goto err_remove_chip;
+
 	status = of_gpiochip_add(chip);
 	if (status)
 		goto err_remove_chip;
@@ -1602,10 +1607,16 @@ EXPORT_SYMBOL_GPL(gpiochip_set_nested_irqchip);
  * gpiochip by assigning the gpiochip as chip data, and using the irqchip
  * stored inside the gpiochip.
  */
-static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
-			    irq_hw_number_t hwirq)
+int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
+		     irq_hw_number_t hwirq)
 {
 	struct gpio_chip *chip = d->host_data;
+	struct irq_chip *irqchip;
+
+	if (chip->irq.chip)
+		irqchip = chip->irq.chip;
+	else
+		irqchip = chip->irqchip;
 
 	irq_set_chip_data(irq, chip);
 	/*
@@ -1613,7 +1624,7 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
 	 * category than their parents, so it won't report false recursion.
 	 */
 	irq_set_lockdep_class(irq, chip->lock_key);
-	irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler);
+	irq_set_chip_and_handler(irq, irqchip, chip->irq_handler);
 	/* Chips that use nested thread handlers have them marked */
 	if (chip->irq_nested)
 		irq_set_nested_thread(irq, 1);
@@ -1628,8 +1639,9 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(gpiochip_irq_map);
 
-static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)
+void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)
 {
 	struct gpio_chip *chip = d->host_data;
 
@@ -1638,6 +1650,7 @@ static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)
 	irq_set_chip_and_handler(irq, NULL, NULL);
 	irq_set_chip_data(irq, NULL);
 }
+EXPORT_SYMBOL_GPL(gpiochip_irq_unmap);
 
 static const struct irq_domain_ops gpiochip_domain_ops = {
 	.map	= gpiochip_irq_map,
@@ -1677,6 +1690,127 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
 }
 
 /**
+ * gpiochip_add_irqchip() - adds an IRQ chip to a GPIO chip
+ * @gpiochip: the GPIO chip to add the IRQ chip to
+ */
+static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
+{
+	struct irq_chip *irqchip = gpiochip->irq.chip;
+	const struct irq_domain_ops *ops;
+	struct device_node *np;
+	unsigned int type;
+	unsigned int i;
+
+	if (!irqchip)
+		return 0;
+
+	if (gpiochip->irq.parent_handler && gpiochip->can_sleep) {
+		chip_err(gpiochip, "you cannot have chained interrupts on a "
+			 "chip that may sleep\n");
+		return -EINVAL;
+	}
+
+	type = gpiochip->irq.default_type;
+	np = gpiochip->parent->of_node;
+
+#ifdef CONFIG_OF_GPIO
+	/*
+	 * If the gpiochip has an assigned OF node this takes precedence
+	 * FIXME: get rid of this and use gpiochip->parent->of_node
+	 * everywhere
+	 */
+	if (gpiochip->of_node)
+		np = gpiochip->of_node;
+#endif
+
+	/*
+	 * Specifying a default trigger is a terrible idea if DT or ACPI is
+	 * used to configure the interrupts, as you may end up with
+	 * conflicting triggers. Tell the user, and reset to NONE.
+	 */
+	if (WARN(np && type != IRQ_TYPE_NONE,
+		 "%s: Ignoring %u default trigger\n", np->full_name, type))
+		type = IRQ_TYPE_NONE;
+
+	if (has_acpi_companion(gpiochip->parent) && type != IRQ_TYPE_NONE) {
+		acpi_handle_warn(ACPI_HANDLE(gpiochip->parent),
+				 "Ignoring %u default trigger\n", type);
+		type = IRQ_TYPE_NONE;
+	}
+
+	gpiochip->irq_handler = gpiochip->irq.handler;
+	gpiochip->lock_key = gpiochip->irq.lock_key;
+
+	gpiochip->to_irq = gpiochip_to_irq;
+	gpiochip->irq_default_type = type;
+
+	if (gpiochip->irq.domain_ops)
+		ops = gpiochip->irq.domain_ops;
+	else
+		ops = &gpiochip_domain_ops;
+
+	gpiochip->irqdomain = irq_domain_add_simple(np, gpiochip->ngpio,
+						    gpiochip->irq.first,
+						    ops, gpiochip);
+	if (!gpiochip->irqdomain)
+		return -EINVAL;
+
+	/*
+	 * It is possible for a driver to override this, but only if the
+	 * alternative functions are both implemented.
+	 */
+	if (!irqchip->irq_request_resources &&
+	    !irqchip->irq_release_resources) {
+		irqchip->irq_request_resources = gpiochip_irq_reqres;
+		irqchip->irq_release_resources = gpiochip_irq_relres;
+	}
+
+	if (gpiochip->irq.parent_handler) {
+		void *data = gpiochip->irq.parent_handler_data ?: gpiochip;
+
+		for (i = 0; i < gpiochip->irq.num_parents; i++) {
+			/*
+			 * The parent IRQ chip is already using the chip_data
+			 * for this IRQ chip, so our callbacks simply use the
+			 * handler_data.
+			 */
+			irq_set_chained_handler_and_data(gpiochip->irq.parents[i],
+							 gpiochip->irq.parent_handler,
+							 data);
+		}
+
+		gpiochip->irq_nested = false;
+	} else {
+		gpiochip->irq_nested = true;
+	}
+
+	/*
+	 * Prepare the mapping since the IRQ chip shall be orthogonal to any
+	 * GPIO chip calls.
+	 */
+	for (i = 0; i < gpiochip->ngpio; i++) {
+		unsigned int irq;
+
+		if (!gpiochip_irqchip_irq_valid(gpiochip, i))
+			continue;
+
+		irq = irq_create_mapping(gpiochip->irqdomain, i);
+		if (!irq) {
+			chip_err(gpiochip,
+				 "failed to create IRQ mapping for GPIO#%u\n",
+				 i);
+			continue;
+		}
+
+		irq_set_parent(irq, gpiochip->irq.map[i]);
+	}
+
+	acpi_gpiochip_request_interrupts(gpiochip);
+
+	return 0;
+}
+
+/**
  * gpiochip_irqchip_remove() - removes an irqchip added to a gpiochip
  * @gpiochip: the gpiochip to remove the irqchip from
  *
@@ -1693,6 +1827,16 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 		irq_set_handler_data(gpiochip->irq_chained_parent, NULL);
 	}
 
+	if (gpiochip->irq.chip) {
+		struct gpio_irq_chip *irq = &gpiochip->irq;
+		unsigned int i;
+
+		for (i = 0; i < irq->num_parents; i++) {
+			irq_set_chained_handler(irq->parents[i], NULL);
+			irq_set_handler_data(irq->parents[i], NULL);
+		}
+	}
+
 	/* Remove all IRQ mappings and delete the domain */
 	if (gpiochip->irqdomain) {
 		for (offset = 0; offset < gpiochip->ngpio; offset++) {
@@ -1835,6 +1979,11 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
 
 #else /* CONFIG_GPIOLIB_IRQCHIP */
 
+static inline int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
+{
+	return 0;
+}
+
 static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {}
 static inline int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)
 {
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 393582867afd..223645a1d80f 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -19,6 +19,39 @@ struct module;
 
 #ifdef CONFIG_GPIOLIB
 
+#ifdef CONFIG_GPIOLIB_IRQCHIP
+/**
+ * struct gpio_irq_chip - GPIO interrupt controller
+ * @chip: GPIO IRQ chip implementation, provided by GPIO driver
+ * @first: if not dynamically assigned, the base (first) IRQ to allocate GPIO
+ *         chip IRQs from
+ * @domain_ops: table of interrupt domain operations for this IRQ chip
+ * @handler: the interrupt handler for the GPIO chip's parent interrupts
+ * @lock_key: per GPIO IRQ chip lockdep class
+ * @default_type: default IRQ triggering type applied during GPIO driver
+ *                initialization, provided by GPIO driver
+ * @parent_handler: the interrupt handler for the GPIO chip's parent
+ *                  interrupts, may be NULL if the parent interrupts are
+ *                  nested rather than cascaded
+ * @num_parents: the number of interrupt parents of a GPIO chip
+ * @parents: a list of interrupt parents of a GPIO chip
+ * @map: a list of interrupt parents for each line of a GPIO chip
+ */
+struct gpio_irq_chip {
+	struct irq_chip *chip;
+	unsigned int first;
+	const struct irq_domain_ops *domain_ops;
+	irq_flow_handler_t handler;
+	struct lock_class_key *lock_key;
+	unsigned int default_type;
+	irq_flow_handler_t parent_handler;
+	void *parent_handler_data;
+	unsigned int num_parents;
+	unsigned int *parents;
+	unsigned int *map;
+};
+#endif
+
 /**
  * struct gpio_chip - abstract a GPIO controller
  * @label: a functional name for the GPIO device, such as a part
@@ -173,6 +206,8 @@ struct gpio_chip {
 	bool			irq_need_valid_mask;
 	unsigned long		*irq_valid_mask;
 	struct lock_class_key	*lock_key;
+
+	struct gpio_irq_chip	irq;
 #endif
 
 #if defined(CONFIG_OF_GPIO)
@@ -242,6 +277,10 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,
 
 #ifdef CONFIG_GPIOLIB_IRQCHIP
 
+int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
+		     irq_hw_number_t hwirq);
+void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq);
+
 void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
 		struct irq_chip *irqchip,
 		unsigned int parent_irq,
-- 
2.12.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 03/12] gpio: Move irq_nested into struct gpio_irq_chip
       [not found] ` <20170403160532.20282-1-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  2017-04-03 16:05   ` [PATCH 01/12] gpio: Use unsigned int for interrupt numbers Thierry Reding
@ 2017-04-03 16:05   ` Thierry Reding
  2017-04-03 16:05   ` [PATCH 04/12] gpio: Move irqdomain " Thierry Reding
                     ` (6 subsequent siblings)
  8 siblings, 0 replies; 20+ messages in thread
From: Thierry Reding @ 2017-04-03 16:05 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Alexandre Courbot, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA

From: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

In order to consolidate the multiple ways to associate an IRQ chip with
a GPIO chip, move more fields into the new struct gpio_irq_chip.

Signed-off-by: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 drivers/gpio/gpiolib.c      | 12 ++++++------
 include/linux/gpio/driver.h |  4 ++--
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index d403a0572d4b..5aa920cb4653 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1588,7 +1588,7 @@ void gpiochip_set_nested_irqchip(struct gpio_chip *gpiochip,
 				 struct irq_chip *irqchip,
 				 unsigned int parent_irq)
 {
-	if (!gpiochip->irq_nested) {
+	if (!gpiochip->irq.nested) {
 		chip_err(gpiochip, "tried to nest a chained gpiochip\n");
 		return;
 	}
@@ -1626,7 +1626,7 @@ int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
 	irq_set_lockdep_class(irq, chip->lock_key);
 	irq_set_chip_and_handler(irq, irqchip, chip->irq_handler);
 	/* Chips that use nested thread handlers have them marked */
-	if (chip->irq_nested)
+	if (chip->irq.nested)
 		irq_set_nested_thread(irq, 1);
 	irq_set_noprobe(irq);
 
@@ -1645,7 +1645,7 @@ void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)
 {
 	struct gpio_chip *chip = d->host_data;
 
-	if (chip->irq_nested)
+	if (chip->irq.nested)
 		irq_set_nested_thread(irq, 0);
 	irq_set_chip_and_handler(irq, NULL, NULL);
 	irq_set_chip_data(irq, NULL);
@@ -1779,9 +1779,9 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
 							 data);
 		}
 
-		gpiochip->irq_nested = false;
+		gpiochip->irq.nested = false;
 	} else {
-		gpiochip->irq_nested = true;
+		gpiochip->irq.nested = true;
 	}
 
 	/*
@@ -1904,7 +1904,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 		pr_err("missing gpiochip .dev parent pointer\n");
 		return -EINVAL;
 	}
-	gpiochip->irq_nested = nested;
+	gpiochip->irq.nested = nested;
 	of_node = gpiochip->parent->of_node;
 #ifdef CONFIG_OF_GPIO
 	/*
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 223645a1d80f..07d93ffb49af 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -36,6 +36,7 @@ struct module;
  * @num_parents: the number of interrupt parents of a GPIO chip
  * @parents: a list of interrupt parents of a GPIO chip
  * @map: a list of interrupt parents for each line of a GPIO chip
+ * @nested: True if set the interrupt handling is nested.
  */
 struct gpio_irq_chip {
 	struct irq_chip *chip;
@@ -49,6 +50,7 @@ struct gpio_irq_chip {
 	unsigned int num_parents;
 	unsigned int *parents;
 	unsigned int *map;
+	bool nested;
 };
 #endif
 
@@ -124,7 +126,6 @@ struct gpio_irq_chip {
  * @irq_chained_parent: GPIO IRQ chip parent/bank linux irq number,
  *	provided by GPIO driver for chained interrupt (not for nested
  *	interrupts).
- * @irq_nested: True if set the interrupt handling is nested.
  * @irq_need_valid_mask: If set core allocates @irq_valid_mask with all
  *	bits set to one
  * @irq_valid_mask: If not %NULL holds bitmask of GPIOs which are valid to
@@ -202,7 +203,6 @@ struct gpio_chip {
 	irq_flow_handler_t	irq_handler;
 	unsigned int		irq_default_type;
 	unsigned int		irq_chained_parent;
-	bool			irq_nested;
 	bool			irq_need_valid_mask;
 	unsigned long		*irq_valid_mask;
 	struct lock_class_key	*lock_key;
-- 
2.12.0

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 04/12] gpio: Move irqdomain into struct gpio_irq_chip
       [not found] ` <20170403160532.20282-1-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  2017-04-03 16:05   ` [PATCH 01/12] gpio: Use unsigned int for interrupt numbers Thierry Reding
  2017-04-03 16:05   ` [PATCH 03/12] gpio: Move irq_nested into struct gpio_irq_chip Thierry Reding
@ 2017-04-03 16:05   ` Thierry Reding
  2017-04-03 16:05   ` [PATCH 07/12] gpio: Move lock_key " Thierry Reding
                     ` (5 subsequent siblings)
  8 siblings, 0 replies; 20+ messages in thread
From: Thierry Reding @ 2017-04-03 16:05 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Alexandre Courbot, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA

From: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

In order to consolidate the multiple ways to associate an IRQ chip with
a GPIO chip, move more fields into the new struct gpio_irq_chip.

Signed-off-by: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 Documentation/gpio/driver.txt              |  2 +-
 drivers/bcma/driver_gpio.c                 |  2 +-
 drivers/gpio/gpio-104-dio-48e.c            |  2 +-
 drivers/gpio/gpio-104-idi-48.c             |  2 +-
 drivers/gpio/gpio-104-idio-16.c            |  2 +-
 drivers/gpio/gpio-adnp.c                   |  2 +-
 drivers/gpio/gpio-altera.c                 |  4 ++--
 drivers/gpio/gpio-aspeed.c                 |  2 +-
 drivers/gpio/gpio-ath79.c                  |  2 +-
 drivers/gpio/gpio-brcmstb.c                |  2 +-
 drivers/gpio/gpio-crystalcove.c            |  2 +-
 drivers/gpio/gpio-dln2.c                   |  2 +-
 drivers/gpio/gpio-ftgpio010.c              |  2 +-
 drivers/gpio/gpio-intel-mid.c              |  2 +-
 drivers/gpio/gpio-lynxpoint.c              |  2 +-
 drivers/gpio/gpio-max732x.c                |  2 +-
 drivers/gpio/gpio-mcp23s08.c               |  2 +-
 drivers/gpio/gpio-merrifield.c             |  2 +-
 drivers/gpio/gpio-omap.c                   |  2 +-
 drivers/gpio/gpio-pca953x.c                |  2 +-
 drivers/gpio/gpio-pcf857x.c                |  2 +-
 drivers/gpio/gpio-pci-idio-16.c            |  2 +-
 drivers/gpio/gpio-pl061.c                  |  2 +-
 drivers/gpio/gpio-rcar.c                   |  2 +-
 drivers/gpio/gpio-reg.c                    |  4 ++--
 drivers/gpio/gpio-stmpe.c                  |  2 +-
 drivers/gpio/gpio-tc3589x.c                |  2 +-
 drivers/gpio/gpio-vf610.c                  |  2 +-
 drivers/gpio/gpio-wcove.c                  |  2 +-
 drivers/gpio/gpio-ws16c48.c                |  2 +-
 drivers/gpio/gpio-xgene-sb.c               |  2 +-
 drivers/gpio/gpio-xlp.c                    |  2 +-
 drivers/gpio/gpio-zx.c                     |  2 +-
 drivers/gpio/gpio-zynq.c                   |  2 +-
 drivers/gpio/gpiolib.c                     | 34 ++++++++++++++++--------------
 drivers/pinctrl/bcm/pinctrl-bcm2835.c      |  4 ++--
 drivers/pinctrl/bcm/pinctrl-iproc-gpio.c   |  2 +-
 drivers/pinctrl/intel/pinctrl-baytrail.c   |  2 +-
 drivers/pinctrl/intel/pinctrl-cherryview.c |  2 +-
 drivers/pinctrl/intel/pinctrl-intel.c      |  2 +-
 drivers/pinctrl/nomadik/pinctrl-nomadik.c  |  4 ++--
 drivers/pinctrl/pinctrl-amd.c              |  2 +-
 drivers/pinctrl/pinctrl-at91.c             |  2 +-
 drivers/pinctrl/pinctrl-coh901.c           |  2 +-
 drivers/pinctrl/pinctrl-oxnas.c            |  2 +-
 drivers/pinctrl/pinctrl-pic32.c            |  2 +-
 drivers/pinctrl/pinctrl-pistachio.c        |  2 +-
 drivers/pinctrl/pinctrl-st.c               |  2 +-
 drivers/pinctrl/pinctrl-sx150x.c           |  2 +-
 drivers/pinctrl/qcom/pinctrl-msm.c         |  2 +-
 drivers/pinctrl/sirf/pinctrl-atlas7.c      |  2 +-
 drivers/pinctrl/sirf/pinctrl-sirf.c        |  2 +-
 drivers/pinctrl/spear/pinctrl-plgpio.c     |  2 +-
 include/linux/gpio/driver.h                |  6 +++---
 54 files changed, 77 insertions(+), 75 deletions(-)

diff --git a/Documentation/gpio/driver.txt b/Documentation/gpio/driver.txt
index fc1d2f83564d..dcf6af1d9e56 100644
--- a/Documentation/gpio/driver.txt
+++ b/Documentation/gpio/driver.txt
@@ -254,7 +254,7 @@ GPIO irqchips usually fall in one of two categories:
 	static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
 		unsigned long wa_lock_flags;
 		raw_spin_lock_irqsave(&bank->wa_lock, wa_lock_flags);
-		generic_handle_irq(irq_find_mapping(bank->chip.irqdomain, bit));
+		generic_handle_irq(irq_find_mapping(bank->chip.irq.domain, bit));
 		raw_spin_unlock_irqrestore(&bank->wa_lock, wa_lock_flags);
 
 * GENERIC CHAINED GPIO irqchips: these are the same as "CHAINED GPIO irqchips",
diff --git a/drivers/bcma/driver_gpio.c b/drivers/bcma/driver_gpio.c
index 7bde8d7a2816..3ad8a7309c00 100644
--- a/drivers/bcma/driver_gpio.c
+++ b/drivers/bcma/driver_gpio.c
@@ -113,7 +113,7 @@ static irqreturn_t bcma_gpio_irq_handler(int irq, void *dev_id)
 		return IRQ_NONE;
 
 	for_each_set_bit(gpio, &irqs, gc->ngpio)
-		generic_handle_irq(irq_find_mapping(gc->irqdomain, gpio));
+		generic_handle_irq(irq_find_mapping(gc->irq.domain, gpio));
 	bcma_chipco_gpio_polarity(cc, irqs, val & irqs);
 
 	return IRQ_HANDLED;
diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c
index 61b50c40b87b..fbff7026e9e9 100644
--- a/drivers/gpio/gpio-104-dio-48e.c
+++ b/drivers/gpio/gpio-104-dio-48e.c
@@ -326,7 +326,7 @@ static irqreturn_t dio48e_irq_handler(int irq, void *dev_id)
 	unsigned long gpio;
 
 	for_each_set_bit(gpio, &irq_mask, 2)
-		generic_handle_irq(irq_find_mapping(chip->irqdomain,
+		generic_handle_irq(irq_find_mapping(chip->irq.domain,
 			19 + gpio*24));
 
 	raw_spin_lock(&dio48egpio->lock);
diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c
index 337c048168d8..e2e234e99dfa 100644
--- a/drivers/gpio/gpio-104-idi-48.c
+++ b/drivers/gpio/gpio-104-idi-48.c
@@ -209,7 +209,7 @@ static irqreturn_t idi_48_irq_handler(int irq, void *dev_id)
 		for_each_set_bit(bit_num, &irq_mask, 8) {
 			gpio = bit_num + boundary * 8;
 
-			generic_handle_irq(irq_find_mapping(chip->irqdomain,
+			generic_handle_irq(irq_find_mapping(chip->irq.domain,
 				gpio));
 		}
 	}
diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-16.c
index 5281e1cedb01..1e82d462581e 100644
--- a/drivers/gpio/gpio-104-idio-16.c
+++ b/drivers/gpio/gpio-104-idio-16.c
@@ -199,7 +199,7 @@ static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
 	int gpio;
 
 	for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
-		generic_handle_irq(irq_find_mapping(chip->irqdomain, gpio));
+		generic_handle_irq(irq_find_mapping(chip->irq.domain, gpio));
 
 	raw_spin_lock(&idio16gpio->lock);
 
diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c
index 89863ea25de1..9d143ae4219f 100644
--- a/drivers/gpio/gpio-adnp.c
+++ b/drivers/gpio/gpio-adnp.c
@@ -323,7 +323,7 @@ static irqreturn_t adnp_irq(int irq, void *data)
 
 		for_each_set_bit(bit, &pending, 8) {
 			unsigned int child_irq;
-			child_irq = irq_find_mapping(adnp->gpio.irqdomain,
+			child_irq = irq_find_mapping(adnp->gpio.irq.domain,
 						     base + bit);
 			handle_nested_irq(child_irq);
 		}
diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c
index 17485dc20384..16a8814d56e9 100644
--- a/drivers/gpio/gpio-altera.c
+++ b/drivers/gpio/gpio-altera.c
@@ -211,7 +211,7 @@ static void altera_gpio_irq_edge_handler(struct irq_desc *desc)
 	altera_gc = gpiochip_get_data(irq_desc_get_handler_data(desc));
 	chip = irq_desc_get_chip(desc);
 	mm_gc = &altera_gc->mmchip;
-	irqdomain = altera_gc->mmchip.gc.irqdomain;
+	irqdomain = altera_gc->mmchip.gc.irq.domain;
 
 	chained_irq_enter(chip, desc);
 
@@ -239,7 +239,7 @@ static void altera_gpio_irq_leveL_high_handler(struct irq_desc *desc)
 	altera_gc = gpiochip_get_data(irq_desc_get_handler_data(desc));
 	chip = irq_desc_get_chip(desc);
 	mm_gc = &altera_gc->mmchip;
-	irqdomain = altera_gc->mmchip.gc.irqdomain;
+	irqdomain = altera_gc->mmchip.gc.irq.domain;
 
 	chained_irq_enter(chip, desc);
 
diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c
index fb16cc771c0d..b1f029154d5e 100644
--- a/drivers/gpio/gpio-aspeed.c
+++ b/drivers/gpio/gpio-aspeed.c
@@ -428,7 +428,7 @@ static void aspeed_gpio_irq_handler(struct irq_desc *desc)
 		reg = ioread32(bank_irq_reg(data, bank, GPIO_IRQ_STATUS));
 
 		for_each_set_bit(p, &reg, 32) {
-			girq = irq_find_mapping(gc->irqdomain, i * 32 + p);
+			girq = irq_find_mapping(gc->irq.domain, i * 32 + p);
 			generic_handle_irq(girq);
 		}
 
diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c
index f33d4a5fe671..299e9f7b6b9d 100644
--- a/drivers/gpio/gpio-ath79.c
+++ b/drivers/gpio/gpio-ath79.c
@@ -208,7 +208,7 @@ static void ath79_gpio_irq_handler(struct irq_desc *desc)
 	if (pending) {
 		for_each_set_bit(irq, &pending, gc->ngpio)
 			generic_handle_irq(
-				irq_linear_revmap(gc->irqdomain, irq));
+				irq_linear_revmap(gc->irq.domain, irq));
 	}
 
 	chained_irq_exit(irqchip, desc);
diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c
index e6489143721a..ddb6275d8f07 100644
--- a/drivers/gpio/gpio-brcmstb.c
+++ b/drivers/gpio/gpio-brcmstb.c
@@ -202,7 +202,7 @@ static irqreturn_t brcmstb_gpio_wake_irq_handler(int irq, void *data)
 static void brcmstb_gpio_irq_bank_handler(struct brcmstb_gpio_bank *bank)
 {
 	struct brcmstb_gpio_priv *priv = bank->parent_priv;
-	struct irq_domain *irq_domain = bank->gc.irqdomain;
+	struct irq_domain *irq_domain = bank->gc.irq.domain;
 	void __iomem *reg_base = priv->reg_base;
 	unsigned long status;
 	unsigned long flags;
diff --git a/drivers/gpio/gpio-crystalcove.c b/drivers/gpio/gpio-crystalcove.c
index 2197368cc899..75fea69f853e 100644
--- a/drivers/gpio/gpio-crystalcove.c
+++ b/drivers/gpio/gpio-crystalcove.c
@@ -277,7 +277,7 @@ static irqreturn_t crystalcove_gpio_irq_handler(int irq, void *data)
 
 	for (gpio = 0; gpio < CRYSTALCOVE_GPIO_NUM; gpio++) {
 		if (pending & BIT(gpio)) {
-			virq = irq_find_mapping(cg->chip.irqdomain, gpio);
+			virq = irq_find_mapping(cg->chip.irq.domain, gpio);
 			handle_nested_irq(virq);
 		}
 	}
diff --git a/drivers/gpio/gpio-dln2.c b/drivers/gpio/gpio-dln2.c
index aecb847166f5..1dada68b9a27 100644
--- a/drivers/gpio/gpio-dln2.c
+++ b/drivers/gpio/gpio-dln2.c
@@ -420,7 +420,7 @@ static void dln2_gpio_event(struct platform_device *pdev, u16 echo,
 		return;
 	}
 
-	irq = irq_find_mapping(dln2->gpio.irqdomain, pin);
+	irq = irq_find_mapping(dln2->gpio.irq.domain, pin);
 	if (!irq) {
 		dev_err(dln2->gpio.parent, "pin %d not mapped to IRQ\n", pin);
 		return;
diff --git a/drivers/gpio/gpio-ftgpio010.c b/drivers/gpio/gpio-ftgpio010.c
index e9386f8b67f5..b7896bae83ca 100644
--- a/drivers/gpio/gpio-ftgpio010.c
+++ b/drivers/gpio/gpio-ftgpio010.c
@@ -149,7 +149,7 @@ static void ftgpio_gpio_irq_handler(struct irq_desc *desc)
 	stat = readl(g->base + GPIO_INT_STAT);
 	if (stat)
 		for_each_set_bit(offset, &stat, gc->ngpio)
-			generic_handle_irq(irq_find_mapping(gc->irqdomain,
+			generic_handle_irq(irq_find_mapping(gc->irq.domain,
 							    offset));
 
 	chained_irq_exit(irqchip, desc);
diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c
index b76ecee82c3f..629575ea46a0 100644
--- a/drivers/gpio/gpio-intel-mid.c
+++ b/drivers/gpio/gpio-intel-mid.c
@@ -295,7 +295,7 @@ static void intel_mid_irq_handler(struct irq_desc *desc)
 			mask = BIT(gpio);
 			/* Clear before handling so we can't lose an edge */
 			writel(mask, gedr);
-			generic_handle_irq(irq_find_mapping(gc->irqdomain,
+			generic_handle_irq(irq_find_mapping(gc->irq.domain,
 							    base + gpio));
 		}
 	}
diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c
index fbd393b46ce0..1e557b10d73e 100644
--- a/drivers/gpio/gpio-lynxpoint.c
+++ b/drivers/gpio/gpio-lynxpoint.c
@@ -255,7 +255,7 @@ static void lp_gpio_irq_handler(struct irq_desc *desc)
 			mask = BIT(pin);
 			/* Clear before handling so we don't lose an edge */
 			outl(mask, reg);
-			irq = irq_find_mapping(lg->chip.irqdomain, base + pin);
+			irq = irq_find_mapping(lg->chip.irq.domain, base + pin);
 			generic_handle_irq(irq);
 		}
 	}
diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c
index 4ea4c6a1313b..c1a1260b1e14 100644
--- a/drivers/gpio/gpio-max732x.c
+++ b/drivers/gpio/gpio-max732x.c
@@ -486,7 +486,7 @@ static irqreturn_t max732x_irq_handler(int irq, void *devid)
 
 	do {
 		level = __ffs(pending);
-		handle_nested_irq(irq_find_mapping(chip->gpio_chip.irqdomain,
+		handle_nested_irq(irq_find_mapping(chip->gpio_chip.irq.domain,
 						   level));
 
 		pending &= ~(1 << level);
diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c
index 2a57d024481d..2218a351f88d 100644
--- a/drivers/gpio/gpio-mcp23s08.c
+++ b/drivers/gpio/gpio-mcp23s08.c
@@ -350,7 +350,7 @@ static irqreturn_t mcp23s08_irq(int irq, void *data)
 		    ((gpio_bit_changed || intcap_changed) &&
 			(BIT(i) & mcp->irq_fall) && !gpio_set) ||
 		    defval_changed) {
-			child_irq = irq_find_mapping(mcp->chip.irqdomain, i);
+			child_irq = irq_find_mapping(mcp->chip.irq.domain, i);
 			handle_nested_irq(child_irq);
 		}
 	}
diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c
index 9dbdc3672f5e..72096b6dfd91 100644
--- a/drivers/gpio/gpio-merrifield.c
+++ b/drivers/gpio/gpio-merrifield.c
@@ -358,7 +358,7 @@ static void mrfld_irq_handler(struct irq_desc *desc)
 		for_each_set_bit(gpio, &pending, 32) {
 			unsigned int irq;
 
-			irq = irq_find_mapping(gc->irqdomain, base + gpio);
+			irq = irq_find_mapping(gc->irq.domain, base + gpio);
 			generic_handle_irq(irq);
 		}
 	}
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 5d6a5744352f..80a361df1d5b 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -728,7 +728,7 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
 
 			raw_spin_lock_irqsave(&bank->wa_lock, wa_lock_flags);
 
-			generic_handle_irq(irq_find_mapping(bank->chip.irqdomain,
+			generic_handle_irq(irq_find_mapping(bank->chip.irq.domain,
 							    bit));
 
 			raw_spin_unlock_irqrestore(&bank->wa_lock,
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index b9373785ccf5..97f55203b0d3 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -609,7 +609,7 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid)
 	for (i = 0; i < NBANK(chip); i++) {
 		while (pending[i]) {
 			level = __ffs(pending[i]);
-			handle_nested_irq(irq_find_mapping(chip->gpio_chip.irqdomain,
+			handle_nested_irq(irq_find_mapping(chip->gpio_chip.irq.domain,
 							level + (BANK_SZ * i)));
 			pending[i] &= ~(1 << level);
 			nhandled++;
diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c
index 895af42a4513..f3f9b83b04c1 100644
--- a/drivers/gpio/gpio-pcf857x.c
+++ b/drivers/gpio/gpio-pcf857x.c
@@ -198,7 +198,7 @@ static irqreturn_t pcf857x_irq(int irq, void *data)
 	mutex_unlock(&gpio->lock);
 
 	for_each_set_bit(i, &change, gpio->chip.ngpio)
-		handle_nested_irq(irq_find_mapping(gpio->chip.irqdomain, i));
+		handle_nested_irq(irq_find_mapping(gpio->chip.irq.domain, i));
 
 	return IRQ_HANDLED;
 }
diff --git a/drivers/gpio/gpio-pci-idio-16.c b/drivers/gpio/gpio-pci-idio-16.c
index 7de4f6a2cb49..57d1b7fbf07b 100644
--- a/drivers/gpio/gpio-pci-idio-16.c
+++ b/drivers/gpio/gpio-pci-idio-16.c
@@ -240,7 +240,7 @@ static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
 		return IRQ_NONE;
 
 	for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
-		generic_handle_irq(irq_find_mapping(chip->irqdomain, gpio));
+		generic_handle_irq(irq_find_mapping(chip->irq.domain, gpio));
 
 	raw_spin_lock(&idio16gpio->lock);
 
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index 3d3d6b6645a7..646a5a12dd7b 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -221,7 +221,7 @@ static void pl061_irq_handler(struct irq_desc *desc)
 	pending = readb(pl061->base + GPIOMIS);
 	if (pending) {
 		for_each_set_bit(offset, &pending, PL061_GPIO_NR)
-			generic_handle_irq(irq_find_mapping(gc->irqdomain,
+			generic_handle_irq(irq_find_mapping(gc->irq.domain,
 							    offset));
 	}
 
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index 31ad288846af..aaafc730f86b 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -206,7 +206,7 @@ static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id)
 			  gpio_rcar_read(p, INTMSK))) {
 		offset = __ffs(pending);
 		gpio_rcar_write(p, INTCLR, BIT(offset));
-		generic_handle_irq(irq_find_mapping(p->gpio_chip.irqdomain,
+		generic_handle_irq(irq_find_mapping(p->gpio_chip.irq.domain,
 						    offset));
 		irqs_handled++;
 	}
diff --git a/drivers/gpio/gpio-reg.c b/drivers/gpio/gpio-reg.c
index e85903eddc68..23e771dba4c1 100644
--- a/drivers/gpio/gpio-reg.c
+++ b/drivers/gpio/gpio-reg.c
@@ -103,8 +103,8 @@ static int gpio_reg_to_irq(struct gpio_chip *gc, unsigned offset)
 	struct gpio_reg *r = to_gpio_reg(gc);
 	int irq = r->irqs[offset];
 
-	if (irq >= 0 && r->irqdomain)
-		irq = irq_find_mapping(r->irqdomain, irq);
+	if (irq >= 0 && r->irq.domain)
+		irq = irq_find_mapping(r->irq.domain, irq);
 
 	return irq;
 }
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index 16cbc5702865..5aee24fe0254 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -397,7 +397,7 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
 		while (stat) {
 			int bit = __ffs(stat);
 			int line = bank * 8 + bit;
-			int child_irq = irq_find_mapping(stmpe_gpio->chip.irqdomain,
+			int child_irq = irq_find_mapping(stmpe_gpio->chip.irq.domain,
 							 line);
 
 			handle_nested_irq(child_irq);
diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c
index 433b45ef332e..91a8ef8e7f3f 100644
--- a/drivers/gpio/gpio-tc3589x.c
+++ b/drivers/gpio/gpio-tc3589x.c
@@ -268,7 +268,7 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev)
 		while (stat) {
 			int bit = __ffs(stat);
 			int line = i * 8 + bit;
-			int irq = irq_find_mapping(tc3589x_gpio->chip.irqdomain,
+			int irq = irq_find_mapping(tc3589x_gpio->chip.irq.domain,
 						   line);
 
 			handle_nested_irq(irq);
diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c
index 521fbe338589..e83a3d26aaaf 100644
--- a/drivers/gpio/gpio-vf610.c
+++ b/drivers/gpio/gpio-vf610.c
@@ -122,7 +122,7 @@ static void vf610_gpio_irq_handler(struct irq_desc *desc)
 	for_each_set_bit(pin, &irq_isfr, VF610_GPIO_PER_PORT) {
 		vf610_gpio_writel(BIT(pin), port->base + PORT_ISFR);
 
-		generic_handle_irq(irq_find_mapping(port->gc.irqdomain, pin));
+		generic_handle_irq(irq_find_mapping(port->gc.irq.domain, pin));
 	}
 
 	chained_irq_exit(chip, desc);
diff --git a/drivers/gpio/gpio-wcove.c b/drivers/gpio/gpio-wcove.c
index 97613de5304e..4627d8ed11fc 100644
--- a/drivers/gpio/gpio-wcove.c
+++ b/drivers/gpio/gpio-wcove.c
@@ -321,7 +321,7 @@ static irqreturn_t wcove_gpio_irq_handler(int irq, void *data)
 			offset = (gpio > GROUP0_NR_IRQS) ? 1 : 0;
 			mask = (offset == 1) ? BIT(gpio - GROUP0_NR_IRQS) :
 								BIT(gpio);
-			virq = irq_find_mapping(wg->chip.irqdomain, gpio);
+			virq = irq_find_mapping(wg->chip.irq.domain, gpio);
 			handle_nested_irq(virq);
 			regmap_update_bits(wg->regmap, IRQ_STATUS_BASE + offset,
 								mask, mask);
diff --git a/drivers/gpio/gpio-ws16c48.c b/drivers/gpio/gpio-ws16c48.c
index 87d63695dfcf..631889de1b11 100644
--- a/drivers/gpio/gpio-ws16c48.c
+++ b/drivers/gpio/gpio-ws16c48.c
@@ -332,7 +332,7 @@ static irqreturn_t ws16c48_irq_handler(int irq, void *dev_id)
 			int_id = inb(ws16c48gpio->base + 8 + port);
 			for_each_set_bit(gpio, &int_id, 8)
 				generic_handle_irq(irq_find_mapping(
-					chip->irqdomain, gpio + 8*port));
+					chip->irq.domain, gpio + 8*port));
 		}
 
 		int_pending = inb(ws16c48gpio->base + 6) & 0x7;
diff --git a/drivers/gpio/gpio-xgene-sb.c b/drivers/gpio/gpio-xgene-sb.c
index 033258634b8c..e761fd7c5728 100644
--- a/drivers/gpio/gpio-xgene-sb.c
+++ b/drivers/gpio/gpio-xgene-sb.c
@@ -296,7 +296,7 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)
 	if (!priv->irq_domain)
 		return -ENODEV;
 
-	priv->gc.irqdomain = priv->irq_domain;
+	priv->gc.irq.domain = priv->irq_domain;
 
 	ret = devm_gpiochip_add_data(&pdev->dev, &priv->gc, priv);
 	if (ret) {
diff --git a/drivers/gpio/gpio-xlp.c b/drivers/gpio/gpio-xlp.c
index d857e1d8e731..e74bd43a6974 100644
--- a/drivers/gpio/gpio-xlp.c
+++ b/drivers/gpio/gpio-xlp.c
@@ -225,7 +225,7 @@ static void xlp_gpio_generic_handler(struct irq_desc *desc)
 
 		if (gpio_stat & BIT(gpio % XLP_GPIO_REGSZ))
 			generic_handle_irq(irq_find_mapping(
-						priv->chip.irqdomain, gpio));
+						priv->chip.irq.domain, gpio));
 	}
 	chained_irq_exit(irqchip, desc);
 }
diff --git a/drivers/gpio/gpio-zx.c b/drivers/gpio/gpio-zx.c
index be3a87da8438..5eacad9b2692 100644
--- a/drivers/gpio/gpio-zx.c
+++ b/drivers/gpio/gpio-zx.c
@@ -170,7 +170,7 @@ static void zx_irq_handler(struct irq_desc *desc)
 	writew_relaxed(pending, chip->base + ZX_GPIO_IC);
 	if (pending) {
 		for_each_set_bit(offset, &pending, ZX_GPIO_NR)
-			generic_handle_irq(irq_find_mapping(gc->irqdomain,
+			generic_handle_irq(irq_find_mapping(gc->irq.domain,
 							    offset));
 	}
 
diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c
index 6b4d10d6e10f..ba5e437fbfe8 100644
--- a/drivers/gpio/gpio-zynq.c
+++ b/drivers/gpio/gpio-zynq.c
@@ -505,7 +505,7 @@ static void zynq_gpio_handle_bank_irq(struct zynq_gpio *gpio,
 				      unsigned long pending)
 {
 	unsigned int bank_offset = gpio->p_data->bank_min[bank_num];
-	struct irq_domain *irqdomain = gpio->chip.irqdomain;
+	struct irq_domain *irqdomain = gpio->chip.irq.domain;
 	int offset;
 
 	if (!pending)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 5aa920cb4653..67f8b9c52159 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1525,7 +1525,7 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
 {
 	unsigned int offset;
 
-	if (!gpiochip->irqdomain) {
+	if (!gpiochip->irq.domain) {
 		chip_err(gpiochip, "called %s before setting up irqchip\n",
 			 __func__);
 		return;
@@ -1552,7 +1552,7 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
 	for (offset = 0; offset < gpiochip->ngpio; offset++) {
 		if (!gpiochip_irqchip_irq_valid(gpiochip, offset))
 			continue;
-		irq_set_parent(irq_find_mapping(gpiochip->irqdomain, offset),
+		irq_set_parent(irq_find_mapping(gpiochip->irq.domain, offset),
 			       parent_irq);
 	}
 }
@@ -1686,7 +1686,7 @@ static void gpiochip_irq_relres(struct irq_data *d)
 
 static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-	return irq_find_mapping(chip->irqdomain, offset);
+	return irq_find_mapping(chip->irq.domain, offset);
 }
 
 /**
@@ -1749,10 +1749,10 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
 	else
 		ops = &gpiochip_domain_ops;
 
-	gpiochip->irqdomain = irq_domain_add_simple(np, gpiochip->ngpio,
-						    gpiochip->irq.first,
-						    ops, gpiochip);
-	if (!gpiochip->irqdomain)
+	gpiochip->irq.domain = irq_domain_add_simple(np, gpiochip->ngpio,
+						     gpiochip->irq.first,
+						     ops, gpiochip);
+	if (!gpiochip->irq.domain)
 		return -EINVAL;
 
 	/*
@@ -1794,7 +1794,7 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
 		if (!gpiochip_irqchip_irq_valid(gpiochip, i))
 			continue;
 
-		irq = irq_create_mapping(gpiochip->irqdomain, i);
+		irq = irq_create_mapping(gpiochip->irq.domain, i);
 		if (!irq) {
 			chip_err(gpiochip,
 				 "failed to create IRQ mapping for GPIO#%u\n",
@@ -1818,7 +1818,7 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
  */
 static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 {
-	unsigned int offset;
+	unsigned int offset, irq;
 
 	acpi_gpiochip_free_interrupts(gpiochip);
 
@@ -1838,14 +1838,16 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 	}
 
 	/* Remove all IRQ mappings and delete the domain */
-	if (gpiochip->irqdomain) {
+	if (gpiochip->irq.domain) {
 		for (offset = 0; offset < gpiochip->ngpio; offset++) {
 			if (!gpiochip_irqchip_irq_valid(gpiochip, offset))
 				continue;
-			irq_dispose_mapping(
-				irq_find_mapping(gpiochip->irqdomain, offset));
+
+			irq = irq_find_mapping(gpiochip->irq.domain, offset);
+			irq_dispose_mapping(irq);
 		}
-		irq_domain_remove(gpiochip->irqdomain);
+
+		irq_domain_remove(gpiochip->irq.domain);
 	}
 
 	if (gpiochip->irqchip) {
@@ -1934,10 +1936,10 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 	gpiochip->irq_default_type = type;
 	gpiochip->to_irq = gpiochip_to_irq;
 	gpiochip->lock_key = lock_key;
-	gpiochip->irqdomain = irq_domain_add_simple(of_node,
+	gpiochip->irq.domain = irq_domain_add_simple(of_node,
 					gpiochip->ngpio, first_irq,
 					&gpiochip_domain_ops, gpiochip);
-	if (!gpiochip->irqdomain) {
+	if (!gpiochip->irq.domain) {
 		gpiochip->irqchip = NULL;
 		return -EINVAL;
 	}
@@ -1960,7 +1962,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 	for (offset = 0; offset < gpiochip->ngpio; offset++) {
 		if (!gpiochip_irqchip_irq_valid(gpiochip, offset))
 			continue;
-		irq_base = irq_create_mapping(gpiochip->irqdomain, offset);
+		irq_base = irq_create_mapping(gpiochip->irq.domain, offset);
 		if (!irq_base_set) {
 			/*
 			 * Store the base into the gpiochip to be used when
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
index 85d009112864..d2085252e9a7 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
@@ -384,7 +384,7 @@ static void bcm2835_gpio_irq_handle_bank(struct bcm2835_pinctrl *pc,
 		/* FIXME: no clue why the code looks up the type here */
 		type = pc->irq_type[gpio];
 
-		generic_handle_irq(irq_linear_revmap(pc->gpio_chip.irqdomain,
+		generic_handle_irq(irq_linear_revmap(pc->gpio_chip.irq.domain,
 						     gpio));
 	}
 }
@@ -666,7 +666,7 @@ static void bcm2835_pctl_pin_dbg_show(struct pinctrl_dev *pctldev,
 	enum bcm2835_fsel fsel = bcm2835_pinctrl_fsel_get(pc, offset);
 	const char *fname = bcm2835_functions[fsel];
 	int value = bcm2835_gpio_get_bit(pc, GPLEV0, offset);
-	int irq = irq_find_mapping(chip->irqdomain, offset);
+	int irq = irq_find_mapping(chip->irq.domain, offset);
 
 	seq_printf(s, "function %s in %s; irq %d (%s)",
 		fname, value ? "hi" : "lo",
diff --git a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
index af5e904d4a1e..4eaf8baf2ba1 100644
--- a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
+++ b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
@@ -170,7 +170,7 @@ static void iproc_gpio_irq_handler(struct irq_desc *desc)
 
 		for_each_set_bit(bit, &val, NGPIOS_PER_BANK) {
 			unsigned pin = NGPIOS_PER_BANK * i + bit;
-			int child_irq = irq_find_mapping(gc->irqdomain, pin);
+			int child_irq = irq_find_mapping(gc->irq.domain, pin);
 
 			/*
 			 * Clear the interrupt before invoking the
diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c
index fa3c5758ac67..f49cc7ce68fc 100644
--- a/drivers/pinctrl/intel/pinctrl-baytrail.c
+++ b/drivers/pinctrl/intel/pinctrl-baytrail.c
@@ -1627,7 +1627,7 @@ static void byt_gpio_irq_handler(struct irq_desc *desc)
 		pending = readl(reg);
 		raw_spin_unlock(&vg->lock);
 		for_each_set_bit(pin, &pending, 32) {
-			virq = irq_find_mapping(vg->chip.irqdomain, base + pin);
+			virq = irq_find_mapping(vg->chip.irq.domain, base + pin);
 			generic_handle_irq(virq);
 		}
 	}
diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c
index 83640afd825c..13bd1ced5104 100644
--- a/drivers/pinctrl/intel/pinctrl-cherryview.c
+++ b/drivers/pinctrl/intel/pinctrl-cherryview.c
@@ -1522,7 +1522,7 @@ static void chv_gpio_irq_handler(struct irq_desc *desc)
 		unsigned irq, offset;
 
 		offset = pctrl->intr_lines[intr_line];
-		irq = irq_find_mapping(gc->irqdomain, offset);
+		irq = irq_find_mapping(gc->irq.domain, offset);
 		generic_handle_irq(irq);
 	}
 
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
index 592b465e981e..45dabfd57b9c 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.c
+++ b/drivers/pinctrl/intel/pinctrl-intel.c
@@ -958,7 +958,7 @@ static irqreturn_t intel_gpio_community_irq_handler(struct intel_pinctrl *pctrl,
 			if (padno >= community->npins)
 				break;
 
-			irq = irq_find_mapping(gc->irqdomain,
+			irq = irq_find_mapping(gc->irq.domain,
 					       community->pin_base + padno);
 			generic_handle_irq(irq);
 
diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c
index d318ca055489..487841499ba9 100644
--- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c
+++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c
@@ -413,7 +413,7 @@ nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset)
 	u32 falling = nmk_chip->fimsc & BIT(offset);
 	u32 rising = nmk_chip->rimsc & BIT(offset);
 	int gpio = nmk_chip->chip.base + offset;
-	int irq = irq_find_mapping(nmk_chip->chip.irqdomain, offset);
+	int irq = irq_find_mapping(nmk_chip->chip.irq.domain, offset);
 	struct irq_data *d = irq_get_irq_data(irq);
 
 	if (!rising && !falling)
@@ -815,7 +815,7 @@ static void __nmk_gpio_irq_handler(struct irq_desc *desc, u32 status)
 	while (status) {
 		int bit = __ffs(status);
 
-		generic_handle_irq(irq_find_mapping(chip->irqdomain, bit));
+		generic_handle_irq(irq_find_mapping(chip->irq.domain, bit));
 		status &= ~BIT(bit);
 	}
 
diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c
index 1482d132fbb8..7c8f6bc127f3 100644
--- a/drivers/pinctrl/pinctrl-amd.c
+++ b/drivers/pinctrl/pinctrl-amd.c
@@ -531,7 +531,7 @@ static void amd_gpio_irq_handler(struct irq_desc *desc)
 						(off * 4 + i) * 4);
 				if ((pin_reg & BIT(INTERRUPT_STS_OFF)) ||
 					(pin_reg & BIT(WAKE_STS_OFF))) {
-					irq = irq_find_mapping(gc->irqdomain,
+					irq = irq_find_mapping(gc->irq.domain,
 								off * 4 + i);
 					generic_handle_irq(irq);
 					writel(pin_reg,
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index 569bc28cb909..03492e3c09fa 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -1603,7 +1603,7 @@ static void gpio_irq_handler(struct irq_desc *desc)
 
 		for_each_set_bit(n, &isr, BITS_PER_LONG) {
 			generic_handle_irq(irq_find_mapping(
-					   gpio_chip->irqdomain, n));
+					   gpio_chip->irq.domain, n));
 		}
 	}
 	chained_irq_exit(chip, desc);
diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c
index 741b39eaeb8b..5b3af065d734 100644
--- a/drivers/pinctrl/pinctrl-coh901.c
+++ b/drivers/pinctrl/pinctrl-coh901.c
@@ -517,7 +517,7 @@ static void u300_gpio_irq_handler(struct irq_desc *desc)
 
 		for_each_set_bit(irqoffset, &val, U300_GPIO_PINS_PER_PORT) {
 			int offset = pinoffset + irqoffset;
-			int pin_irq = irq_find_mapping(chip->irqdomain, offset);
+			int pin_irq = irq_find_mapping(chip->irq.domain, offset);
 
 			dev_dbg(gpio->dev, "GPIO IRQ %d on pin %d\n",
 				pin_irq, offset);
diff --git a/drivers/pinctrl/pinctrl-oxnas.c b/drivers/pinctrl/pinctrl-oxnas.c
index 494ec9a7573a..53ec22a51f5c 100644
--- a/drivers/pinctrl/pinctrl-oxnas.c
+++ b/drivers/pinctrl/pinctrl-oxnas.c
@@ -1064,7 +1064,7 @@ static void oxnas_gpio_irq_handler(struct irq_desc *desc)
 	stat = readl(bank->reg_base + IRQ_PENDING);
 
 	for_each_set_bit(pin, &stat, BITS_PER_LONG)
-		generic_handle_irq(irq_linear_revmap(gc->irqdomain, pin));
+		generic_handle_irq(irq_linear_revmap(gc->irq.domain, pin));
 
 	chained_irq_exit(chip, desc);
 }
diff --git a/drivers/pinctrl/pinctrl-pic32.c b/drivers/pinctrl/pinctrl-pic32.c
index 31ceb958b3fe..96390228d388 100644
--- a/drivers/pinctrl/pinctrl-pic32.c
+++ b/drivers/pinctrl/pinctrl-pic32.c
@@ -2106,7 +2106,7 @@ static void pic32_gpio_irq_handler(struct irq_desc *desc)
 	pending = pic32_gpio_get_pending(gc, stat);
 
 	for_each_set_bit(pin, &pending, BITS_PER_LONG)
-		generic_handle_irq(irq_linear_revmap(gc->irqdomain, pin));
+		generic_handle_irq(irq_linear_revmap(gc->irq.domain, pin));
 
 	chained_irq_exit(chip, desc);
 }
diff --git a/drivers/pinctrl/pinctrl-pistachio.c b/drivers/pinctrl/pinctrl-pistachio.c
index 55375b1b3cc8..302190d1558d 100644
--- a/drivers/pinctrl/pinctrl-pistachio.c
+++ b/drivers/pinctrl/pinctrl-pistachio.c
@@ -1307,7 +1307,7 @@ static void pistachio_gpio_irq_handler(struct irq_desc *desc)
 	pending = gpio_readl(bank, GPIO_INTERRUPT_STATUS) &
 		gpio_readl(bank, GPIO_INTERRUPT_EN);
 	for_each_set_bit(pin, &pending, 16)
-		generic_handle_irq(irq_linear_revmap(gc->irqdomain, pin));
+		generic_handle_irq(irq_linear_revmap(gc->irq.domain, pin));
 	chained_irq_exit(chip, desc);
 }
 
diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c
index 3ae8066bc127..c85449ea1ecb 100644
--- a/drivers/pinctrl/pinctrl-st.c
+++ b/drivers/pinctrl/pinctrl-st.c
@@ -1408,7 +1408,7 @@ static void __gpio_irq_handler(struct st_gpio_bank *bank)
 					continue;
 			}
 
-			generic_handle_irq(irq_find_mapping(bank->gpio_chip.irqdomain, n));
+			generic_handle_irq(irq_find_mapping(bank->gpio_chip.irq.domain, n));
 		}
 	}
 }
diff --git a/drivers/pinctrl/pinctrl-sx150x.c b/drivers/pinctrl/pinctrl-sx150x.c
index 7450f5118445..7db4f6a6eb17 100644
--- a/drivers/pinctrl/pinctrl-sx150x.c
+++ b/drivers/pinctrl/pinctrl-sx150x.c
@@ -561,7 +561,7 @@ static irqreturn_t sx150x_irq_thread_fn(int irq, void *dev_id)
 
 	status = val;
 	for_each_set_bit(n, &status, pctl->data->ngpios)
-		handle_nested_irq(irq_find_mapping(pctl->gpio.irqdomain, n));
+		handle_nested_irq(irq_find_mapping(pctl->gpio.irq.domain, n));
 
 	return IRQ_HANDLED;
 }
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index 273badd92561..eab6936bf0bf 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -782,7 +782,7 @@ static void msm_gpio_irq_handler(struct irq_desc *desc)
 		g = &pctrl->soc->groups[i];
 		val = readl(pctrl->regs + g->intr_status_reg);
 		if (val & BIT(g->intr_status_bit)) {
-			irq_pin = irq_find_mapping(gc->irqdomain, i);
+			irq_pin = irq_find_mapping(gc->irq.domain, i);
 			generic_handle_irq(irq_pin);
 			handled++;
 		}
diff --git a/drivers/pinctrl/sirf/pinctrl-atlas7.c b/drivers/pinctrl/sirf/pinctrl-atlas7.c
index 1efa315a7dbe..36b5c8d5471e 100644
--- a/drivers/pinctrl/sirf/pinctrl-atlas7.c
+++ b/drivers/pinctrl/sirf/pinctrl-atlas7.c
@@ -5820,7 +5820,7 @@ static void atlas7_gpio_handle_irq(struct irq_desc *desc)
 				__func__, gc->label,
 				bank->gpio_offset + pin_in_bank);
 			generic_handle_irq(
-				irq_find_mapping(gc->irqdomain,
+				irq_find_mapping(gc->irq.domain,
 					bank->gpio_offset + pin_in_bank));
 		}
 
diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c
index 0df72be60704..1eca39f2cdac 100644
--- a/drivers/pinctrl/sirf/pinctrl-sirf.c
+++ b/drivers/pinctrl/sirf/pinctrl-sirf.c
@@ -587,7 +587,7 @@ static void sirfsoc_gpio_handle_irq(struct irq_desc *desc)
 		if ((status & 0x1) && (ctrl & SIRFSOC_GPIO_CTL_INTR_EN_MASK)) {
 			pr_debug("%s: gpio id %d idx %d happens\n",
 				__func__, bank->id, idx);
-			generic_handle_irq(irq_find_mapping(gc->irqdomain, idx +
+			generic_handle_irq(irq_find_mapping(gc->irq.domain, idx +
 					bank->id * SIRFSOC_GPIO_BANK_SIZE));
 		}
 
diff --git a/drivers/pinctrl/spear/pinctrl-plgpio.c b/drivers/pinctrl/spear/pinctrl-plgpio.c
index cf6d68c7345b..72ae6bccee55 100644
--- a/drivers/pinctrl/spear/pinctrl-plgpio.c
+++ b/drivers/pinctrl/spear/pinctrl-plgpio.c
@@ -401,7 +401,7 @@ static void plgpio_irq_handler(struct irq_desc *desc)
 			/* get correct irq line number */
 			pin = i * MAX_GPIO_PER_REG + pin;
 			generic_handle_irq(
-				irq_find_mapping(gc->irqdomain, pin));
+				irq_find_mapping(gc->irq.domain, pin));
 		}
 	}
 	chained_irq_exit(irqchip, desc);
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 07d93ffb49af..361b34bd970c 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -25,6 +25,8 @@ struct module;
  * @chip: GPIO IRQ chip implementation, provided by GPIO driver
  * @first: if not dynamically assigned, the base (first) IRQ to allocate GPIO
  *         chip IRQs from
+ * @domain: interrupt translation domain; responsible for mapping
+ *          between GPIO hwirq number and linux irq number
  * @domain_ops: table of interrupt domain operations for this IRQ chip
  * @handler: the interrupt handler for the GPIO chip's parent interrupts
  * @lock_key: per GPIO IRQ chip lockdep class
@@ -41,6 +43,7 @@ struct module;
 struct gpio_irq_chip {
 	struct irq_chip *chip;
 	unsigned int first;
+	struct irq_domain *domain;
 	const struct irq_domain_ops *domain_ops;
 	irq_flow_handler_t handler;
 	struct lock_class_key *lock_key;
@@ -116,8 +119,6 @@ struct gpio_irq_chip {
  * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
  *	direction safely.
  * @irqchip: GPIO IRQ chip impl, provided by GPIO driver
- * @irqdomain: Interrupt translation domain; responsible for mapping
- *	between GPIO hwirq number and linux irq number
  * @irq_base: first linux IRQ number assigned to GPIO IRQ chip (deprecated)
  * @irq_handler: the irq handler to use (often a predefined irq core function)
  *	for GPIO IRQs, provided by GPIO driver
@@ -198,7 +199,6 @@ struct gpio_chip {
 	 * to handle IRQs for most practical cases.
 	 */
 	struct irq_chip		*irqchip;
-	struct irq_domain	*irqdomain;
 	unsigned int		irq_base;
 	irq_flow_handler_t	irq_handler;
 	unsigned int		irq_default_type;
-- 
2.12.0

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 05/12] gpio: Move irqchip into struct gpio_irq_chip
  2017-04-03 16:05 [PATCH 00/12] gpio: Tight IRQ chip integration and Tegra186 support Thierry Reding
  2017-04-03 16:05 ` [PATCH 02/12] gpio: Implement tighter IRQ chip integration Thierry Reding
       [not found] ` <20170403160532.20282-1-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2017-04-03 16:05 ` Thierry Reding
  2017-04-03 16:05 ` [PATCH 06/12] gpio: Move irq_valid_mask " Thierry Reding
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 20+ messages in thread
From: Thierry Reding @ 2017-04-03 16:05 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Alexandre Courbot, linux-gpio, linux-tegra

From: Thierry Reding <treding@nvidia.com>

In order to consolidate the multiple ways to associate an IRQ chip with
a GPIO chip, move more fields into the new struct gpio_irq_chip.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/gpio/gpio-mockup.c  |  4 ++--
 drivers/gpio/gpiolib.c      | 20 +++++++-------------
 include/linux/gpio/driver.h |  2 --
 3 files changed, 9 insertions(+), 17 deletions(-)

diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c
index c6dadac70593..04008fadabef 100644
--- a/drivers/gpio/gpio-mockup.c
+++ b/drivers/gpio/gpio-mockup.c
@@ -174,10 +174,10 @@ static int gpio_mockup_irqchip_setup(struct device *dev,
 		return irq_base;
 
 	gc->irq_base = irq_base;
-	gc->irqchip = &gpio_mockup_irqchip;
+	gc->irq.chip = &gpio_mockup_irqchip;
 
 	for (i = 0; i < gc->ngpio; i++) {
-		irq_set_chip(irq_base + i, gc->irqchip);
+		irq_set_chip(irq_base + i, gc->irq.chip);
 		irq_set_handler(irq_base + i, &handle_simple_irq);
 		irq_modify_status(irq_base + i,
 				  IRQ_NOREQUEST | IRQ_NOAUTOEN, IRQ_NOPROBE);
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 67f8b9c52159..94a428928145 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1611,12 +1611,6 @@ int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
 		     irq_hw_number_t hwirq)
 {
 	struct gpio_chip *chip = d->host_data;
-	struct irq_chip *irqchip;
-
-	if (chip->irq.chip)
-		irqchip = chip->irq.chip;
-	else
-		irqchip = chip->irqchip;
 
 	irq_set_chip_data(irq, chip);
 	/*
@@ -1624,7 +1618,7 @@ int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
 	 * category than their parents, so it won't report false recursion.
 	 */
 	irq_set_lockdep_class(irq, chip->lock_key);
-	irq_set_chip_and_handler(irq, irqchip, chip->irq_handler);
+	irq_set_chip_and_handler(irq, chip->irq.chip, chip->irq_handler);
 	/* Chips that use nested thread handlers have them marked */
 	if (chip->irq.nested)
 		irq_set_nested_thread(irq, 1);
@@ -1850,10 +1844,10 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 		irq_domain_remove(gpiochip->irq.domain);
 	}
 
-	if (gpiochip->irqchip) {
-		gpiochip->irqchip->irq_request_resources = NULL;
-		gpiochip->irqchip->irq_release_resources = NULL;
-		gpiochip->irqchip = NULL;
+	if (gpiochip->irq.chip) {
+		gpiochip->irq.chip->irq_request_resources = NULL;
+		gpiochip->irq.chip->irq_release_resources = NULL;
+		gpiochip->irq.chip = NULL;
 	}
 
 	gpiochip_irqchip_free_valid_mask(gpiochip);
@@ -1931,7 +1925,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 		type = IRQ_TYPE_NONE;
 	}
 
-	gpiochip->irqchip = irqchip;
+	gpiochip->irq.chip = irqchip;
 	gpiochip->irq_handler = handler;
 	gpiochip->irq_default_type = type;
 	gpiochip->to_irq = gpiochip_to_irq;
@@ -1940,7 +1934,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 					gpiochip->ngpio, first_irq,
 					&gpiochip_domain_ops, gpiochip);
 	if (!gpiochip->irq.domain) {
-		gpiochip->irqchip = NULL;
+		gpiochip->irq.chip = NULL;
 		return -EINVAL;
 	}
 
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 361b34bd970c..f69f7dccbcf6 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -118,7 +118,6 @@ struct gpio_irq_chip {
  *	safely.
  * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
  *	direction safely.
- * @irqchip: GPIO IRQ chip impl, provided by GPIO driver
  * @irq_base: first linux IRQ number assigned to GPIO IRQ chip (deprecated)
  * @irq_handler: the irq handler to use (often a predefined irq core function)
  *	for GPIO IRQs, provided by GPIO driver
@@ -198,7 +197,6 @@ struct gpio_chip {
 	 * With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib
 	 * to handle IRQs for most practical cases.
 	 */
-	struct irq_chip		*irqchip;
 	unsigned int		irq_base;
 	irq_flow_handler_t	irq_handler;
 	unsigned int		irq_default_type;
-- 
2.12.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 06/12] gpio: Move irq_valid_mask into struct gpio_irq_chip
  2017-04-03 16:05 [PATCH 00/12] gpio: Tight IRQ chip integration and Tegra186 support Thierry Reding
                   ` (2 preceding siblings ...)
  2017-04-03 16:05 ` [PATCH 05/12] gpio: Move irqchip into struct gpio_irq_chip Thierry Reding
@ 2017-04-03 16:05 ` Thierry Reding
  2017-04-03 16:05 ` [PATCH 10/12] gpio: Move irq_handler to " Thierry Reding
  2017-04-06 22:34 ` [PATCH 00/12] gpio: Tight IRQ chip integration and Tegra186 support Thierry Reding
  5 siblings, 0 replies; 20+ messages in thread
From: Thierry Reding @ 2017-04-03 16:05 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Alexandre Courbot, linux-gpio, linux-tegra

From: Thierry Reding <treding@nvidia.com>

In order to consolidate the multiple ways to associate an IRQ chip with
a GPIO chip, move more fields into the new struct gpio_irq_chip.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 Documentation/gpio/driver.txt              |  4 ++--
 drivers/gpio/gpio-aspeed.c                 |  4 ++--
 drivers/gpio/gpio-stmpe.c                  |  4 ++--
 drivers/gpio/gpiolib.c                     | 16 ++++++++--------
 drivers/pinctrl/intel/pinctrl-baytrail.c   |  4 ++--
 drivers/pinctrl/intel/pinctrl-cherryview.c |  4 ++--
 include/linux/gpio/driver.h                | 12 ++++++------
 7 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/Documentation/gpio/driver.txt b/Documentation/gpio/driver.txt
index dcf6af1d9e56..d8de1c7de85a 100644
--- a/Documentation/gpio/driver.txt
+++ b/Documentation/gpio/driver.txt
@@ -313,8 +313,8 @@ symbol:
   mark all the child IRQs as having the other IRQ as parent.
 
 If there is a need to exclude certain GPIOs from the IRQ domain, you can
-set .irq_need_valid_mask of the gpiochip before gpiochip_add_data() is
-called. This allocates an .irq_valid_mask with as many bits set as there
+set .irq.need_valid_mask of the gpiochip before gpiochip_add_data() is
+called. This allocates an .irq.valid_mask with as many bits set as there
 are GPIOs in the chip. Drivers can exclude GPIOs by clearing bits from this
 mask. The mask must be filled in before gpiochip_irqchip_add() or
 gpiochip_irqchip_add_nested() is called.
diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c
index b1f029154d5e..0c19b89d56cd 100644
--- a/drivers/gpio/gpio-aspeed.c
+++ b/drivers/gpio/gpio-aspeed.c
@@ -460,7 +460,7 @@ static void set_irq_valid_mask(struct aspeed_gpio *gpio)
 			if (i >= gpio->config->nr_gpios)
 				break;
 
-			clear_bit(i, gpio->chip.irq_valid_mask);
+			clear_bit(i, gpio->chip.irq.valid_mask);
 		}
 
 		props++;
@@ -578,7 +578,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
 	gpio->chip.set = aspeed_gpio_set;
 	gpio->chip.label = dev_name(&pdev->dev);
 	gpio->chip.base = -1;
-	gpio->chip.irq_need_valid_mask = true;
+	gpio->chip.irq.need_valid_mask = true;
 
 	rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
 	if (rc < 0)
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index 5aee24fe0254..5b99ff7e75ef 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -451,7 +451,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
 	of_property_read_u32(np, "st,norequest-mask",
 			&stmpe_gpio->norequest_mask);
 	if (stmpe_gpio->norequest_mask)
-		stmpe_gpio->chip.irq_need_valid_mask = true;
+		stmpe_gpio->chip.irq.need_valid_mask = true;
 
 	if (irq < 0)
 		dev_info(&pdev->dev,
@@ -482,7 +482,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
 			/* Forbid unused lines to be mapped as IRQs */
 			for (i = 0; i < sizeof(u32); i++)
 				if (stmpe_gpio->norequest_mask & BIT(i))
-					clear_bit(i, stmpe_gpio->chip.irq_valid_mask);
+					clear_bit(i, stmpe_gpio->chip.irq.valid_mask);
 		}
 		ret =  gpiochip_irqchip_add_nested(&stmpe_gpio->chip,
 						   &stmpe_gpio_irq_chip,
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 94a428928145..318978a79859 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1478,34 +1478,34 @@ static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)
 {
 	int i;
 
-	if (!gpiochip->irq_need_valid_mask)
+	if (!gpiochip->irq.need_valid_mask)
 		return 0;
 
-	gpiochip->irq_valid_mask = kcalloc(BITS_TO_LONGS(gpiochip->ngpio),
+	gpiochip->irq.valid_mask = kcalloc(BITS_TO_LONGS(gpiochip->ngpio),
 					   sizeof(long), GFP_KERNEL);
-	if (!gpiochip->irq_valid_mask)
+	if (!gpiochip->irq.valid_mask)
 		return -ENOMEM;
 
 	/* Assume by default all GPIOs are valid */
 	for (i = 0; i < gpiochip->ngpio; i++)
-		set_bit(i, gpiochip->irq_valid_mask);
+		set_bit(i, gpiochip->irq.valid_mask);
 
 	return 0;
 }
 
 static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip)
 {
-	kfree(gpiochip->irq_valid_mask);
-	gpiochip->irq_valid_mask = NULL;
+	kfree(gpiochip->irq.valid_mask);
+	gpiochip->irq.valid_mask = NULL;
 }
 
 static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
 				       unsigned int offset)
 {
 	/* No mask means all valid */
-	if (likely(!gpiochip->irq_valid_mask))
+	if (likely(!gpiochip->irq.valid_mask))
 		return true;
-	return test_bit(offset, gpiochip->irq_valid_mask);
+	return test_bit(offset, gpiochip->irq.valid_mask);
 }
 
 /**
diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c
index f49cc7ce68fc..04430c66f949 100644
--- a/drivers/pinctrl/intel/pinctrl-baytrail.c
+++ b/drivers/pinctrl/intel/pinctrl-baytrail.c
@@ -1660,7 +1660,7 @@ static void byt_gpio_irq_init_hw(struct byt_gpio *vg)
 
 		value = readl(reg);
 		if (value & BYT_DIRECT_IRQ_EN) {
-			clear_bit(i, gc->irq_valid_mask);
+			clear_bit(i, gc->irq.valid_mask);
 			dev_dbg(dev, "excluding GPIO %d from IRQ domain\n", i);
 		} else if ((value & BYT_PIN_MUX) == byt_get_gpio_mux(vg, i)) {
 			byt_gpio_clear_triggering(vg, i);
@@ -1703,7 +1703,7 @@ static int byt_gpio_probe(struct byt_gpio *vg)
 	gc->can_sleep	= false;
 	gc->parent	= &vg->pdev->dev;
 	gc->ngpio	= vg->soc_data->npins;
-	gc->irq_need_valid_mask	= true;
+	gc->irq.need_valid_mask	= true;
 
 #ifdef CONFIG_PM_SLEEP
 	vg->saved_context = devm_kcalloc(&vg->pdev->dev, gc->ngpio,
diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c
index 13bd1ced5104..8dfb904661fd 100644
--- a/drivers/pinctrl/intel/pinctrl-cherryview.c
+++ b/drivers/pinctrl/intel/pinctrl-cherryview.c
@@ -1541,7 +1541,7 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
 	chip->label = dev_name(pctrl->dev);
 	chip->parent = pctrl->dev;
 	chip->base = -1;
-	chip->irq_need_valid_mask = true;
+	chip->irq.need_valid_mask = true;
 
 	ret = devm_gpiochip_add_data(pctrl->dev, chip, pctrl);
 	if (ret) {
@@ -1573,7 +1573,7 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
 		intsel >>= CHV_PADCTRL0_INTSEL_SHIFT;
 
 		if (intsel >= pctrl->community->nirqs)
-			clear_bit(i, chip->irq_valid_mask);
+			clear_bit(i, chip->irq.valid_mask);
 	}
 
 	/* Clear all interrupts */
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index f69f7dccbcf6..6da14df56047 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -39,6 +39,10 @@ struct module;
  * @parents: a list of interrupt parents of a GPIO chip
  * @map: a list of interrupt parents for each line of a GPIO chip
  * @nested: True if set the interrupt handling is nested.
+ * @need_valid_mask: If set core allocates @valid_mask with all bits set to
+ *                   one
+ * @valid_mask: If not %NULL holds bitmask of GPIOs which are valid to be
+ *              included in IRQ domain of the chip
  */
 struct gpio_irq_chip {
 	struct irq_chip *chip;
@@ -54,6 +58,8 @@ struct gpio_irq_chip {
 	unsigned int *parents;
 	unsigned int *map;
 	bool nested;
+	bool need_valid_mask;
+	unsigned long *valid_mask;
 };
 #endif
 
@@ -126,10 +132,6 @@ struct gpio_irq_chip {
  * @irq_chained_parent: GPIO IRQ chip parent/bank linux irq number,
  *	provided by GPIO driver for chained interrupt (not for nested
  *	interrupts).
- * @irq_need_valid_mask: If set core allocates @irq_valid_mask with all
- *	bits set to one
- * @irq_valid_mask: If not %NULL holds bitmask of GPIOs which are valid to
- *	be included in IRQ domain of the chip
  * @lock_key: per GPIO IRQ chip lockdep class
  *
  * A gpio_chip can help platforms abstract various sources of GPIOs so
@@ -201,8 +203,6 @@ struct gpio_chip {
 	irq_flow_handler_t	irq_handler;
 	unsigned int		irq_default_type;
 	unsigned int		irq_chained_parent;
-	bool			irq_need_valid_mask;
-	unsigned long		*irq_valid_mask;
 	struct lock_class_key	*lock_key;
 
 	struct gpio_irq_chip	irq;
-- 
2.12.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 07/12] gpio: Move lock_key into struct gpio_irq_chip
       [not found] ` <20170403160532.20282-1-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
                     ` (2 preceding siblings ...)
  2017-04-03 16:05   ` [PATCH 04/12] gpio: Move irqdomain " Thierry Reding
@ 2017-04-03 16:05   ` Thierry Reding
  2017-04-03 16:05   ` [PATCH 08/12] gpio: Move irq_chained_parent to " Thierry Reding
                     ` (4 subsequent siblings)
  8 siblings, 0 replies; 20+ messages in thread
From: Thierry Reding @ 2017-04-03 16:05 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Alexandre Courbot, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA

From: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

In order to consolidate the multiple ways to associate an IRQ chip with
a GPIO chip, move more fields into the new struct gpio_irq_chip.

Signed-off-by: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 drivers/gpio/gpiolib.c      | 5 ++---
 include/linux/gpio/driver.h | 2 --
 2 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 318978a79859..f951eeb3c243 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1617,7 +1617,7 @@ int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
 	 * This lock class tells lockdep that GPIO irqs are in a different
 	 * category than their parents, so it won't report false recursion.
 	 */
-	irq_set_lockdep_class(irq, chip->lock_key);
+	irq_set_lockdep_class(irq, chip->irq.lock_key);
 	irq_set_chip_and_handler(irq, chip->irq.chip, chip->irq_handler);
 	/* Chips that use nested thread handlers have them marked */
 	if (chip->irq.nested)
@@ -1733,7 +1733,6 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
 	}
 
 	gpiochip->irq_handler = gpiochip->irq.handler;
-	gpiochip->lock_key = gpiochip->irq.lock_key;
 
 	gpiochip->to_irq = gpiochip_to_irq;
 	gpiochip->irq_default_type = type;
@@ -1929,7 +1928,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 	gpiochip->irq_handler = handler;
 	gpiochip->irq_default_type = type;
 	gpiochip->to_irq = gpiochip_to_irq;
-	gpiochip->lock_key = lock_key;
+	gpiochip->irq.lock_key = lock_key;
 	gpiochip->irq.domain = irq_domain_add_simple(of_node,
 					gpiochip->ngpio, first_irq,
 					&gpiochip_domain_ops, gpiochip);
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 6da14df56047..e0b08e208b23 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -132,7 +132,6 @@ struct gpio_irq_chip {
  * @irq_chained_parent: GPIO IRQ chip parent/bank linux irq number,
  *	provided by GPIO driver for chained interrupt (not for nested
  *	interrupts).
- * @lock_key: per GPIO IRQ chip lockdep class
  *
  * A gpio_chip can help platforms abstract various sources of GPIOs so
  * they can all be accessed through a common programing interface.
@@ -203,7 +202,6 @@ struct gpio_chip {
 	irq_flow_handler_t	irq_handler;
 	unsigned int		irq_default_type;
 	unsigned int		irq_chained_parent;
-	struct lock_class_key	*lock_key;
 
 	struct gpio_irq_chip	irq;
 #endif
-- 
2.12.0

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 08/12] gpio: Move irq_chained_parent to struct gpio_irq_chip
       [not found] ` <20170403160532.20282-1-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
                     ` (3 preceding siblings ...)
  2017-04-03 16:05   ` [PATCH 07/12] gpio: Move lock_key " Thierry Reding
@ 2017-04-03 16:05   ` Thierry Reding
  2017-04-03 16:05   ` [PATCH 09/12] gpio: Move irq_default_type " Thierry Reding
                     ` (3 subsequent siblings)
  8 siblings, 0 replies; 20+ messages in thread
From: Thierry Reding @ 2017-04-03 16:05 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Alexandre Courbot, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA

From: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

In order to consolidate the multiple ways to associate an IRQ chip with
a GPIO chip, move more fields into the new struct gpio_irq_chip.

Signed-off-by: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 drivers/gpio/gpiolib.c      | 8 ++------
 include/linux/gpio/driver.h | 4 ----
 2 files changed, 2 insertions(+), 10 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index f951eeb3c243..ff327512703a 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1545,7 +1545,8 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
 		irq_set_chained_handler_and_data(parent_irq, parent_handler,
 						 gpiochip);
 
-		gpiochip->irq_chained_parent = parent_irq;
+		gpiochip->irq.parents = &parent_irq;
+		gpiochip->irq.num_parents = 1;
 	}
 
 	/* Set the parent IRQ for all affected IRQs */
@@ -1815,11 +1816,6 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 
 	acpi_gpiochip_free_interrupts(gpiochip);
 
-	if (gpiochip->irq_chained_parent) {
-		irq_set_chained_handler(gpiochip->irq_chained_parent, NULL);
-		irq_set_handler_data(gpiochip->irq_chained_parent, NULL);
-	}
-
 	if (gpiochip->irq.chip) {
 		struct gpio_irq_chip *irq = &gpiochip->irq;
 		unsigned int i;
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index e0b08e208b23..631c66d6df58 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -129,9 +129,6 @@ struct gpio_irq_chip {
  *	for GPIO IRQs, provided by GPIO driver
  * @irq_default_type: default IRQ triggering type applied during GPIO driver
  *	initialization, provided by GPIO driver
- * @irq_chained_parent: GPIO IRQ chip parent/bank linux irq number,
- *	provided by GPIO driver for chained interrupt (not for nested
- *	interrupts).
  *
  * A gpio_chip can help platforms abstract various sources of GPIOs so
  * they can all be accessed through a common programing interface.
@@ -201,7 +198,6 @@ struct gpio_chip {
 	unsigned int		irq_base;
 	irq_flow_handler_t	irq_handler;
 	unsigned int		irq_default_type;
-	unsigned int		irq_chained_parent;
 
 	struct gpio_irq_chip	irq;
 #endif
-- 
2.12.0

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 09/12] gpio: Move irq_default_type to struct gpio_irq_chip
       [not found] ` <20170403160532.20282-1-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
                     ` (4 preceding siblings ...)
  2017-04-03 16:05   ` [PATCH 08/12] gpio: Move irq_chained_parent to " Thierry Reding
@ 2017-04-03 16:05   ` Thierry Reding
  2017-04-03 16:05   ` [PATCH 11/12] gpio: Move irq_base " Thierry Reding
                     ` (2 subsequent siblings)
  8 siblings, 0 replies; 20+ messages in thread
From: Thierry Reding @ 2017-04-03 16:05 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Alexandre Courbot, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA

From: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

In order to consolidate the multiple ways to associate an IRQ chip with
a GPIO chip, move more fields into the new struct gpio_irq_chip.

Signed-off-by: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 drivers/gpio/gpiolib.c      | 8 ++++----
 include/linux/gpio/driver.h | 3 ---
 2 files changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index ff327512703a..cb4b35157aca 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1629,8 +1629,8 @@ int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
 	 * No set-up of the hardware will happen if IRQ_TYPE_NONE
 	 * is passed as default type.
 	 */
-	if (chip->irq_default_type != IRQ_TYPE_NONE)
-		irq_set_irq_type(irq, chip->irq_default_type);
+	if (chip->irq.default_type != IRQ_TYPE_NONE)
+		irq_set_irq_type(irq, chip->irq.default_type);
 
 	return 0;
 }
@@ -1736,7 +1736,7 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
 	gpiochip->irq_handler = gpiochip->irq.handler;
 
 	gpiochip->to_irq = gpiochip_to_irq;
-	gpiochip->irq_default_type = type;
+	gpiochip->irq.default_type = type;
 
 	if (gpiochip->irq.domain_ops)
 		ops = gpiochip->irq.domain_ops;
@@ -1922,7 +1922,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 
 	gpiochip->irq.chip = irqchip;
 	gpiochip->irq_handler = handler;
-	gpiochip->irq_default_type = type;
+	gpiochip->irq.default_type = type;
 	gpiochip->to_irq = gpiochip_to_irq;
 	gpiochip->irq.lock_key = lock_key;
 	gpiochip->irq.domain = irq_domain_add_simple(of_node,
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 631c66d6df58..4bc5b4b9cf0b 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -127,8 +127,6 @@ struct gpio_irq_chip {
  * @irq_base: first linux IRQ number assigned to GPIO IRQ chip (deprecated)
  * @irq_handler: the irq handler to use (often a predefined irq core function)
  *	for GPIO IRQs, provided by GPIO driver
- * @irq_default_type: default IRQ triggering type applied during GPIO driver
- *	initialization, provided by GPIO driver
  *
  * A gpio_chip can help platforms abstract various sources of GPIOs so
  * they can all be accessed through a common programing interface.
@@ -197,7 +195,6 @@ struct gpio_chip {
 	 */
 	unsigned int		irq_base;
 	irq_flow_handler_t	irq_handler;
-	unsigned int		irq_default_type;
 
 	struct gpio_irq_chip	irq;
 #endif
-- 
2.12.0

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 10/12] gpio: Move irq_handler to struct gpio_irq_chip
  2017-04-03 16:05 [PATCH 00/12] gpio: Tight IRQ chip integration and Tegra186 support Thierry Reding
                   ` (3 preceding siblings ...)
  2017-04-03 16:05 ` [PATCH 06/12] gpio: Move irq_valid_mask " Thierry Reding
@ 2017-04-03 16:05 ` Thierry Reding
  2017-04-06 22:34 ` [PATCH 00/12] gpio: Tight IRQ chip integration and Tegra186 support Thierry Reding
  5 siblings, 0 replies; 20+ messages in thread
From: Thierry Reding @ 2017-04-03 16:05 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Alexandre Courbot, linux-gpio, linux-tegra

From: Thierry Reding <treding@nvidia.com>

In order to consolidate the multiple ways to associate an IRQ chip with
a GPIO chip, move more fields into the new struct gpio_irq_chip.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/gpio/gpiolib.c      | 6 ++----
 include/linux/gpio/driver.h | 6 ++----
 2 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index cb4b35157aca..3b251d5c0e1a 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1619,7 +1619,7 @@ int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
 	 * category than their parents, so it won't report false recursion.
 	 */
 	irq_set_lockdep_class(irq, chip->irq.lock_key);
-	irq_set_chip_and_handler(irq, chip->irq.chip, chip->irq_handler);
+	irq_set_chip_and_handler(irq, chip->irq.chip, chip->irq.handler);
 	/* Chips that use nested thread handlers have them marked */
 	if (chip->irq.nested)
 		irq_set_nested_thread(irq, 1);
@@ -1733,8 +1733,6 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
 		type = IRQ_TYPE_NONE;
 	}
 
-	gpiochip->irq_handler = gpiochip->irq.handler;
-
 	gpiochip->to_irq = gpiochip_to_irq;
 	gpiochip->irq.default_type = type;
 
@@ -1921,7 +1919,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 	}
 
 	gpiochip->irq.chip = irqchip;
-	gpiochip->irq_handler = handler;
+	gpiochip->irq.handler = handler;
 	gpiochip->irq.default_type = type;
 	gpiochip->to_irq = gpiochip_to_irq;
 	gpiochip->irq.lock_key = lock_key;
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 4bc5b4b9cf0b..91aa808052f1 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -28,7 +28,8 @@ struct module;
  * @domain: interrupt translation domain; responsible for mapping
  *          between GPIO hwirq number and linux irq number
  * @domain_ops: table of interrupt domain operations for this IRQ chip
- * @handler: the interrupt handler for the GPIO chip's parent interrupts
+ * @handler: the IRQ handler to use (often a predefined IRQ core function) for
+ *           GPIO IRQs, provided by GPIO driver
  * @lock_key: per GPIO IRQ chip lockdep class
  * @default_type: default IRQ triggering type applied during GPIO driver
  *                initialization, provided by GPIO driver
@@ -125,8 +126,6 @@ struct gpio_irq_chip {
  * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
  *	direction safely.
  * @irq_base: first linux IRQ number assigned to GPIO IRQ chip (deprecated)
- * @irq_handler: the irq handler to use (often a predefined irq core function)
- *	for GPIO IRQs, provided by GPIO driver
  *
  * A gpio_chip can help platforms abstract various sources of GPIOs so
  * they can all be accessed through a common programing interface.
@@ -194,7 +193,6 @@ struct gpio_chip {
 	 * to handle IRQs for most practical cases.
 	 */
 	unsigned int		irq_base;
-	irq_flow_handler_t	irq_handler;
 
 	struct gpio_irq_chip	irq;
 #endif
-- 
2.12.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 11/12] gpio: Move irq_base to struct gpio_irq_chip
       [not found] ` <20170403160532.20282-1-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
                     ` (5 preceding siblings ...)
  2017-04-03 16:05   ` [PATCH 09/12] gpio: Move irq_default_type " Thierry Reding
@ 2017-04-03 16:05   ` Thierry Reding
  2017-04-03 16:05   ` [PATCH v3 12/12] gpio: Add Tegra186 support Thierry Reding
  2017-04-13 12:22   ` [PATCH 00/12] gpio: Tight IRQ chip integration and " Linus Walleij
  8 siblings, 0 replies; 20+ messages in thread
From: Thierry Reding @ 2017-04-03 16:05 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Alexandre Courbot, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA

From: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

In order to consolidate the multiple ways to associate an IRQ chip with
a GPIO chip, move more fields into the new struct gpio_irq_chip.

Signed-off-by: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 drivers/gpio/gpio-mockup.c  | 6 +++---
 drivers/gpio/gpiolib.c      | 2 +-
 include/linux/gpio/driver.h | 5 +----
 3 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c
index 04008fadabef..f4179f7420a3 100644
--- a/drivers/gpio/gpio-mockup.c
+++ b/drivers/gpio/gpio-mockup.c
@@ -139,7 +139,7 @@ static int gpio_mockup_name_lines(struct device *dev,
 
 static int gpio_mockup_to_irq(struct gpio_chip *chip, unsigned int offset)
 {
-	return chip->irq_base + offset;
+	return chip->irq.first + offset;
 }
 
 /*
@@ -173,7 +173,7 @@ static int gpio_mockup_irqchip_setup(struct device *dev,
 	if (irq_base < 0)
 		return irq_base;
 
-	gc->irq_base = irq_base;
+	gc->irq.first = irq_base;
 	gc->irq.chip = &gpio_mockup_irqchip;
 
 	for (i = 0; i < gc->ngpio; i++) {
@@ -217,7 +217,7 @@ static ssize_t gpio_mockup_event_write(struct file *file,
 		return -EINVAL;
 
 	gpiod_set_value_cansleep(desc, val);
-	priv->chip->irq_ctx.irq = gc->irq_base + priv->offset;
+	priv->chip->irq_ctx.irq = gc->irq.first + priv->offset;
 	irq_work_queue(&priv->chip->irq_ctx.work);
 
 	return size;
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 3b251d5c0e1a..55e59d79bfd3 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1955,7 +1955,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 			 * Store the base into the gpiochip to be used when
 			 * unmapping the irqs.
 			 */
-			gpiochip->irq_base = irq_base;
+			gpiochip->irq.first = irq_base;
 			irq_base_set = true;
 		}
 	}
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 91aa808052f1..96e7aca74ed1 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -24,7 +24,7 @@ struct module;
  * struct gpio_irq_chip - GPIO interrupt controller
  * @chip: GPIO IRQ chip implementation, provided by GPIO driver
  * @first: if not dynamically assigned, the base (first) IRQ to allocate GPIO
- *         chip IRQs from
+ *         chip IRQs from (deprecated)
  * @domain: interrupt translation domain; responsible for mapping
  *          between GPIO hwirq number and linux irq number
  * @domain_ops: table of interrupt domain operations for this IRQ chip
@@ -125,7 +125,6 @@ struct gpio_irq_chip {
  *	safely.
  * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
  *	direction safely.
- * @irq_base: first linux IRQ number assigned to GPIO IRQ chip (deprecated)
  *
  * A gpio_chip can help platforms abstract various sources of GPIOs so
  * they can all be accessed through a common programing interface.
@@ -192,8 +191,6 @@ struct gpio_chip {
 	 * With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib
 	 * to handle IRQs for most practical cases.
 	 */
-	unsigned int		irq_base;
-
 	struct gpio_irq_chip	irq;
 #endif
 
-- 
2.12.0

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v3 12/12] gpio: Add Tegra186 support
       [not found] ` <20170403160532.20282-1-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
                     ` (6 preceding siblings ...)
  2017-04-03 16:05   ` [PATCH 11/12] gpio: Move irq_base " Thierry Reding
@ 2017-04-03 16:05   ` Thierry Reding
       [not found]     ` <20170403160532.20282-13-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  2017-04-13 12:22   ` [PATCH 00/12] gpio: Tight IRQ chip integration and " Linus Walleij
  8 siblings, 1 reply; 20+ messages in thread
From: Thierry Reding @ 2017-04-03 16:05 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Alexandre Courbot, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA

From: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

Tegra186 has two GPIO controllers that are largely register compatible
between one another but are completely different from the controller
found on earlier generations.

Signed-off-by: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
Changes in v3:
- make use of GPIOLIB_IRQCHIP for IRQ chip handling

Changes in v2:
- add pin names to allow easy lookup using the chardev interface
- distinguish AON and main GPIO controllers by label
- use gpiochip_get_data() instead of container_of()
- use C99 initializers

 drivers/gpio/Kconfig         |   9 +
 drivers/gpio/Makefile        |   1 +
 drivers/gpio/gpio-tegra186.c | 625 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 635 insertions(+)
 create mode 100644 drivers/gpio/gpio-tegra186.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 63ceed246b6f..196c0431b54d 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -430,6 +430,15 @@ config GPIO_TEGRA
 	help
 	  Say yes here to support GPIO pins on NVIDIA Tegra SoCs.
 
+config GPIO_TEGRA186
+	tristate "NVIDIA Tegra186 GPIO support"
+	default ARCH_TEGRA_186_SOC
+	depends on ARCH_TEGRA_186_SOC || COMPILE_TEST
+	depends on OF_GPIO
+	select GPIOLIB_IRQCHIP
+	help
+	  Say yes here to support GPIO pins on NVIDIA Tegra186 SoCs.
+
 config GPIO_TS4800
 	tristate "TS-4800 DIO blocks and compatibles"
 	depends on OF_GPIO
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 095598e856ca..c6f53208becd 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -111,6 +111,7 @@ obj-$(CONFIG_GPIO_SYSCON)	+= gpio-syscon.o
 obj-$(CONFIG_GPIO_TB10X)	+= gpio-tb10x.o
 obj-$(CONFIG_GPIO_TC3589X)	+= gpio-tc3589x.o
 obj-$(CONFIG_GPIO_TEGRA)	+= gpio-tegra.o
+obj-$(CONFIG_GPIO_TEGRA186)	+= gpio-tegra186.o
 obj-$(CONFIG_GPIO_TIMBERDALE)	+= gpio-timberdale.o
 obj-$(CONFIG_GPIO_PALMAS)	+= gpio-palmas.o
 obj-$(CONFIG_GPIO_TPIC2810)	+= gpio-tpic2810.o
diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c
new file mode 100644
index 000000000000..e14beca596f6
--- /dev/null
+++ b/drivers/gpio/gpio-tegra186.c
@@ -0,0 +1,625 @@
+/*
+ * Copyright (c) 2016-2017 NVIDIA Corporation
+ *
+ * Author: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+
+#include <dt-bindings/gpio/tegra186-gpio.h>
+
+#define TEGRA186_GPIO_ENABLE_CONFIG 0x00
+#define  TEGRA186_GPIO_ENABLE_CONFIG_ENABLE BIT(0)
+#define  TEGRA186_GPIO_ENABLE_CONFIG_OUT BIT(1)
+#define  TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_NONE (0x0 << 2)
+#define  TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_LEVEL (0x1 << 2)
+#define  TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE (0x2 << 2)
+#define  TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE (0x3 << 2)
+#define  TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_MASK (0x3 << 2)
+#define  TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL BIT(4)
+#define  TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT BIT(6)
+
+#define TEGRA186_GPIO_DEBOUNCE_CONTROL 0x04
+#define  TEGRA186_GPIO_DEBOUNCE_CONTROL_THRESHOLD(x) ((x) & 0xff)
+
+#define TEGRA186_GPIO_INPUT 0x08
+#define  TEGRA186_GPIO_INPUT_HIGH BIT(0)
+
+#define TEGRA186_GPIO_OUTPUT_CONTROL 0x0c
+#define  TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED BIT(0)
+
+#define TEGRA186_GPIO_OUTPUT_VALUE 0x10
+#define  TEGRA186_GPIO_OUTPUT_VALUE_HIGH BIT(0)
+
+#define TEGRA186_GPIO_INTERRUPT_CLEAR 0x14
+
+#define TEGRA186_GPIO_INTERRUPT_STATUS(x) (0x100 + (x) * 4)
+
+struct tegra_gpio_port {
+	const char *name;
+	unsigned int offset;
+	unsigned int pins;
+	unsigned int irq;
+};
+
+struct tegra_gpio_soc {
+	const struct tegra_gpio_port *ports;
+	unsigned int num_ports;
+	const char *name;
+};
+
+struct tegra_gpio {
+	struct gpio_chip gpio;
+	struct irq_chip intc;
+	unsigned int num_irq;
+	unsigned int *irq;
+
+	const struct tegra_gpio_soc *soc;
+
+	void __iomem *base;
+};
+
+static const struct tegra_gpio_port *
+tegra186_gpio_get_port(struct tegra_gpio *gpio, unsigned int *pin)
+{
+	unsigned int start = 0, i;
+
+	for (i = 0; i < gpio->soc->num_ports; i++) {
+		const struct tegra_gpio_port *port = &gpio->soc->ports[i];
+
+		if (*pin >= start && *pin < start + port->pins) {
+			*pin -= start;
+			return port;
+		}
+
+		start += port->pins;
+	}
+
+	return NULL;
+}
+
+static void __iomem *tegra186_gpio_get_base(struct tegra_gpio *gpio,
+					    unsigned int pin)
+{
+	const struct tegra_gpio_port *port;
+
+	port = tegra186_gpio_get_port(gpio, &pin);
+	if (!port)
+		return NULL;
+
+	return gpio->base + port->offset + pin * 0x20;
+}
+
+static int tegra186_gpio_get_direction(struct gpio_chip *chip,
+				       unsigned int offset)
+{
+	struct tegra_gpio *gpio = gpiochip_get_data(chip);
+	void __iomem *base;
+	u32 value;
+
+	base = tegra186_gpio_get_base(gpio, offset);
+	if (WARN_ON(base == NULL))
+		return -ENODEV;
+
+	value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
+	if (value & TEGRA186_GPIO_ENABLE_CONFIG_OUT)
+		return 0;
+
+	return 1;
+}
+
+static int tegra186_gpio_direction_input(struct gpio_chip *chip,
+					 unsigned int offset)
+{
+	struct tegra_gpio *gpio = gpiochip_get_data(chip);
+	void __iomem *base;
+	u32 value;
+
+	base = tegra186_gpio_get_base(gpio, offset);
+	if (WARN_ON(base == NULL))
+		return -ENODEV;
+
+	value = readl(base + TEGRA186_GPIO_OUTPUT_CONTROL);
+	value |= TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED;
+	writel(value, base + TEGRA186_GPIO_OUTPUT_CONTROL);
+
+	value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
+	value |= TEGRA186_GPIO_ENABLE_CONFIG_ENABLE;
+	value &= ~TEGRA186_GPIO_ENABLE_CONFIG_OUT;
+	writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
+
+	return 0;
+}
+
+static int tegra186_gpio_direction_output(struct gpio_chip *chip,
+					  unsigned int offset, int level)
+{
+	struct tegra_gpio *gpio = gpiochip_get_data(chip);
+	void __iomem *base;
+	u32 value;
+
+	/* configure output level first */
+	chip->set(chip, offset, level);
+
+	base = tegra186_gpio_get_base(gpio, offset);
+	if (WARN_ON(base == NULL))
+		return -EINVAL;
+
+	/* set the direction */
+	value = readl(base + TEGRA186_GPIO_OUTPUT_CONTROL);
+	value &= ~TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED;
+	writel(value, base + TEGRA186_GPIO_OUTPUT_CONTROL);
+
+	value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
+	value |= TEGRA186_GPIO_ENABLE_CONFIG_ENABLE;
+	value |= TEGRA186_GPIO_ENABLE_CONFIG_OUT;
+	writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
+
+	return 0;
+}
+
+static int tegra186_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+	struct tegra_gpio *gpio = gpiochip_get_data(chip);
+	void __iomem *base;
+	u32 value;
+
+	base = tegra186_gpio_get_base(gpio, offset);
+	if (WARN_ON(base == NULL))
+		return -ENODEV;
+
+	value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
+	if (value & TEGRA186_GPIO_ENABLE_CONFIG_OUT)
+		value = readl(base + TEGRA186_GPIO_OUTPUT_VALUE);
+	else
+		value = readl(base + TEGRA186_GPIO_INPUT);
+
+	return value & BIT(0);
+}
+
+static void tegra186_gpio_set(struct gpio_chip *chip, unsigned int offset,
+			      int level)
+{
+	struct tegra_gpio *gpio = gpiochip_get_data(chip);
+	void __iomem *base;
+	u32 value;
+
+	base = tegra186_gpio_get_base(gpio, offset);
+	if (WARN_ON(base == NULL))
+		return;
+
+	value = readl(base + TEGRA186_GPIO_OUTPUT_VALUE);
+	if (level == 0)
+		value &= ~TEGRA186_GPIO_OUTPUT_VALUE_HIGH;
+	else
+		value |= TEGRA186_GPIO_OUTPUT_VALUE_HIGH;
+
+	writel(value, base + TEGRA186_GPIO_OUTPUT_VALUE);
+}
+
+static int tegra186_gpio_of_xlate(struct gpio_chip *chip,
+				  const struct of_phandle_args *spec,
+				  u32 *flags)
+{
+	struct tegra_gpio *gpio = gpiochip_get_data(chip);
+	unsigned int port, pin, i, offset = 0;
+
+	if (WARN_ON(chip->of_gpio_n_cells < 2))
+		return -EINVAL;
+
+	if (WARN_ON(spec->args_count < chip->of_gpio_n_cells))
+		return -EINVAL;
+
+	port = spec->args[0] / 8;
+	pin = spec->args[0] % 8;
+
+	if (port >= gpio->soc->num_ports) {
+		dev_err(chip->parent, "invalid port number: %u\n", port);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < port; i++)
+		offset += gpio->soc->ports[i].pins;
+
+	if (flags)
+		*flags = spec->args[1];
+
+	return offset + pin;
+}
+
+static void tegra186_irq_ack(struct irq_data *data)
+{
+	struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
+	void __iomem *base;
+
+	base = tegra186_gpio_get_base(gpio, data->hwirq);
+	if (WARN_ON(base == NULL))
+		return;
+
+	writel(1, base + TEGRA186_GPIO_INTERRUPT_CLEAR);
+}
+
+static void tegra186_irq_mask(struct irq_data *data)
+{
+	struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
+	void __iomem *base;
+	u32 value;
+
+	base = tegra186_gpio_get_base(gpio, data->hwirq);
+	if (WARN_ON(base == NULL))
+		return;
+
+	value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
+	value &= ~TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT;
+	writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
+}
+
+static void tegra186_irq_unmask(struct irq_data *data)
+{
+	struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
+	void __iomem *base;
+	u32 value;
+
+	base = tegra186_gpio_get_base(gpio, data->hwirq);
+	if (WARN_ON(base == NULL))
+		return;
+
+	value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
+	value |= TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT;
+	writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
+}
+
+static int tegra186_irq_set_type(struct irq_data *data, unsigned int flow)
+{
+	struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
+	void __iomem *base;
+	u32 value;
+
+	base = tegra186_gpio_get_base(gpio, data->hwirq);
+	if (WARN_ON(base == NULL))
+		return -ENODEV;
+
+	value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
+	value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_MASK;
+	value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL;
+
+	switch (flow & IRQ_TYPE_SENSE_MASK) {
+	case IRQ_TYPE_NONE:
+		break;
+
+	case IRQ_TYPE_EDGE_RISING:
+		value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE;
+		value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL;
+		break;
+
+	case IRQ_TYPE_EDGE_FALLING:
+		value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE;
+		break;
+
+	case IRQ_TYPE_EDGE_BOTH:
+		value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE;
+		break;
+
+	case IRQ_TYPE_LEVEL_HIGH:
+		value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_LEVEL;
+		value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL;
+		break;
+
+	case IRQ_TYPE_LEVEL_LOW:
+		value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_LEVEL;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
+
+	if ((flow & IRQ_TYPE_EDGE_BOTH) == 0)
+		irq_set_handler_locked(data, handle_level_irq);
+	else
+		irq_set_handler_locked(data, handle_edge_irq);
+
+	return 0;
+}
+
+static void tegra186_gpio_irq(struct irq_desc *desc)
+{
+	struct tegra_gpio *gpio = irq_desc_get_handler_data(desc);
+	struct irq_domain *domain = gpio->gpio.irq.domain;
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	unsigned int parent = irq_desc_get_irq(desc);
+	unsigned int i, offset = 0;
+
+	chained_irq_enter(chip, desc);
+
+	for (i = 0; i < gpio->soc->num_ports; i++) {
+		const struct tegra_gpio_port *port = &gpio->soc->ports[i];
+		void __iomem *base = gpio->base + port->offset;
+		unsigned int pin, irq;
+		unsigned long value;
+
+		/* skip ports that are not associated with this controller */
+		if (parent != gpio->irq[port->irq])
+			goto skip;
+
+		value = readl(base + TEGRA186_GPIO_INTERRUPT_STATUS(1));
+
+		for_each_set_bit(pin, &value, port->pins) {
+			irq = irq_find_mapping(domain, offset + pin);
+			if (WARN_ON(irq == 0))
+				continue;
+
+			generic_handle_irq(irq);
+		}
+
+skip:
+		offset += port->pins;
+	}
+
+	chained_irq_exit(chip, desc);
+}
+
+static int tegra186_gpio_irq_domain_xlate(struct irq_domain *domain,
+					  struct device_node *np,
+					  const u32 *spec, unsigned int size,
+					  unsigned long *hwirq,
+					  unsigned int *type)
+{
+	struct tegra_gpio *gpio = gpiochip_get_data(domain->host_data);
+	unsigned int port, pin, i, offset = 0;
+
+	if (size < 2)
+		return -EINVAL;
+
+	port = spec[0] / 8;
+	pin = spec[0] % 8;
+
+	if (port >= gpio->soc->num_ports) {
+		dev_err(gpio->gpio.parent, "invalid port number: %u\n", port);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < port; i++)
+		offset += gpio->soc->ports[i].pins;
+
+	*type = spec[1] & IRQ_TYPE_SENSE_MASK;
+	*hwirq = offset + pin;
+
+	return 0;
+}
+
+static const struct irq_domain_ops tegra186_gpio_irq_domain_ops = {
+	.map = gpiochip_irq_map,
+	.unmap = gpiochip_irq_unmap,
+	.xlate = tegra186_gpio_irq_domain_xlate,
+};
+
+static struct lock_class_key tegra186_gpio_lock_class;
+
+static int tegra186_gpio_probe(struct platform_device *pdev)
+{
+	unsigned int i, j, offset;
+	struct gpio_irq_chip *irq;
+	struct tegra_gpio *gpio;
+	struct resource *res;
+	char **names;
+	int err;
+
+	gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
+	if (!gpio)
+		return -ENOMEM;
+
+	gpio->soc = of_device_get_match_data(&pdev->dev);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpio");
+	gpio->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(gpio->base))
+		return PTR_ERR(gpio->base);
+
+	err = of_irq_count(pdev->dev.of_node);
+	if (err < 0)
+		return err;
+
+	gpio->num_irq = err;
+
+	gpio->irq = devm_kcalloc(&pdev->dev, gpio->num_irq, sizeof(*gpio->irq),
+				 GFP_KERNEL);
+	if (!gpio->irq)
+		return -ENOMEM;
+
+	for (i = 0; i < gpio->num_irq; i++) {
+		err = platform_get_irq(pdev, i);
+		if (err < 0)
+			return err;
+
+		gpio->irq[i] = err;
+	}
+
+	gpio->gpio.label = gpio->soc->name;
+	gpio->gpio.parent = &pdev->dev;
+
+	gpio->gpio.get_direction = tegra186_gpio_get_direction;
+	gpio->gpio.direction_input = tegra186_gpio_direction_input;
+	gpio->gpio.direction_output = tegra186_gpio_direction_output;
+	gpio->gpio.get = tegra186_gpio_get,
+	gpio->gpio.set = tegra186_gpio_set;
+
+	gpio->gpio.base = -1;
+
+	for (i = 0; i < gpio->soc->num_ports; i++)
+		gpio->gpio.ngpio += gpio->soc->ports[i].pins;
+
+	names = devm_kcalloc(gpio->gpio.parent, gpio->gpio.ngpio,
+			     sizeof(*names), GFP_KERNEL);
+	if (!names)
+		return -ENOMEM;
+
+	for (i = 0, offset = 0; i < gpio->soc->num_ports; i++) {
+		const struct tegra_gpio_port *port = &gpio->soc->ports[i];
+		char *name;
+
+		for (j = 0; j < port->pins; j++) {
+			name = devm_kasprintf(gpio->gpio.parent, GFP_KERNEL,
+					      "P%s.%02x", port->name, j);
+			if (!name)
+				return -ENOMEM;
+
+			names[offset + j] = name;
+		}
+
+		offset += port->pins;
+	}
+
+	gpio->gpio.names = (const char * const *)names;
+
+	gpio->gpio.of_node = pdev->dev.of_node;
+	gpio->gpio.of_gpio_n_cells = 2;
+	gpio->gpio.of_xlate = tegra186_gpio_of_xlate;
+
+	gpio->intc.name = pdev->dev.of_node->name;
+	gpio->intc.irq_ack = tegra186_irq_ack;
+	gpio->intc.irq_mask = tegra186_irq_mask;
+	gpio->intc.irq_unmask = tegra186_irq_unmask;
+	gpio->intc.irq_set_type = tegra186_irq_set_type;
+
+	irq = &gpio->gpio.irq;
+	irq->chip = &gpio->intc;
+	irq->first = 0;
+	irq->domain_ops = &tegra186_gpio_irq_domain_ops;
+	irq->handler = handle_simple_irq;
+	irq->lock_key = &tegra186_gpio_lock_class;
+	irq->default_type = IRQ_TYPE_NONE;
+	irq->parent_handler = tegra186_gpio_irq;
+	irq->parent_handler_data = gpio;
+	irq->num_parents = gpio->num_irq;
+	irq->parents = gpio->irq;
+
+	irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio,
+				sizeof(*irq->map), GFP_KERNEL);
+	if (!irq->map)
+		return -ENOMEM;
+
+	for (i = 0, offset = 0; i < gpio->soc->num_ports; i++) {
+		const struct tegra_gpio_port *port = &gpio->soc->ports[i];
+
+		for (j = 0; j < port->pins; j++)
+			irq->map[offset + j] = irq->parents[port->irq];
+
+		offset += port->pins;
+	}
+
+	platform_set_drvdata(pdev, gpio);
+
+	err = devm_gpiochip_add_data(&pdev->dev, &gpio->gpio, gpio);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int tegra186_gpio_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+#define TEGRA_MAIN_GPIO_PORT(port, base, count, controller)	\
+	[TEGRA_MAIN_GPIO_PORT_##port] = {			\
+		.name = #port,					\
+		.offset = base,					\
+		.pins = count,					\
+		.irq = controller,				\
+	}
+
+static const struct tegra_gpio_port tegra186_main_ports[] = {
+	TEGRA_MAIN_GPIO_PORT( A, 0x2000, 7, 2),
+	TEGRA_MAIN_GPIO_PORT( B, 0x3000, 7, 3),
+	TEGRA_MAIN_GPIO_PORT( C, 0x3200, 7, 3),
+	TEGRA_MAIN_GPIO_PORT( D, 0x3400, 6, 3),
+	TEGRA_MAIN_GPIO_PORT( E, 0x2200, 8, 2),
+	TEGRA_MAIN_GPIO_PORT( F, 0x2400, 6, 2),
+	TEGRA_MAIN_GPIO_PORT( G, 0x4200, 6, 4),
+	TEGRA_MAIN_GPIO_PORT( H, 0x1000, 7, 1),
+	TEGRA_MAIN_GPIO_PORT( I, 0x0800, 8, 0),
+	TEGRA_MAIN_GPIO_PORT( J, 0x5000, 8, 5),
+	TEGRA_MAIN_GPIO_PORT( K, 0x5200, 1, 5),
+	TEGRA_MAIN_GPIO_PORT( L, 0x1200, 8, 1),
+	TEGRA_MAIN_GPIO_PORT( M, 0x5600, 6, 5),
+	TEGRA_MAIN_GPIO_PORT( N, 0x0000, 7, 0),
+	TEGRA_MAIN_GPIO_PORT( O, 0x0200, 4, 0),
+	TEGRA_MAIN_GPIO_PORT( P, 0x4000, 7, 4),
+	TEGRA_MAIN_GPIO_PORT( Q, 0x0400, 6, 0),
+	TEGRA_MAIN_GPIO_PORT( R, 0x0a00, 6, 0),
+	TEGRA_MAIN_GPIO_PORT( T, 0x0600, 4, 0),
+	TEGRA_MAIN_GPIO_PORT( X, 0x1400, 8, 1),
+	TEGRA_MAIN_GPIO_PORT( Y, 0x1600, 7, 1),
+	TEGRA_MAIN_GPIO_PORT(BB, 0x2600, 2, 2),
+	TEGRA_MAIN_GPIO_PORT(CC, 0x5400, 4, 5),
+};
+
+static const struct tegra_gpio_soc tegra186_main_soc = {
+	.num_ports = ARRAY_SIZE(tegra186_main_ports),
+	.ports = tegra186_main_ports,
+	.name = "tegra186-gpio",
+};
+
+#define TEGRA_AON_GPIO_PORT(port, base, count, controller)	\
+	[TEGRA_AON_GPIO_PORT_##port] = {			\
+		.name = #port,					\
+		.offset = base,					\
+		.pins = count,					\
+		.irq = controller,				\
+	}
+
+static const struct tegra_gpio_port tegra186_aon_ports[] = {
+	TEGRA_AON_GPIO_PORT( S, 0x0200, 5, 0),
+	TEGRA_AON_GPIO_PORT( U, 0x0400, 6, 0),
+	TEGRA_AON_GPIO_PORT( V, 0x0800, 8, 0),
+	TEGRA_AON_GPIO_PORT( W, 0x0a00, 8, 0),
+	TEGRA_AON_GPIO_PORT( Z, 0x0e00, 4, 0),
+	TEGRA_AON_GPIO_PORT(AA, 0x0c00, 8, 0),
+	TEGRA_AON_GPIO_PORT(EE, 0x0600, 3, 0),
+	TEGRA_AON_GPIO_PORT(FF, 0x0000, 5, 0),
+};
+
+static const struct tegra_gpio_soc tegra186_aon_soc = {
+	.num_ports = ARRAY_SIZE(tegra186_aon_ports),
+	.ports = tegra186_aon_ports,
+	.name = "tegra186-gpio-aon",
+};
+
+static const struct of_device_id tegra186_gpio_of_match[] = {
+	{
+		.compatible = "nvidia,tegra186-gpio",
+		.data = &tegra186_main_soc
+	}, {
+		.compatible = "nvidia,tegra186-gpio-aon",
+		.data = &tegra186_aon_soc
+	}, {
+		/* sentinel */
+	}
+};
+
+static struct platform_driver tegra186_gpio_driver = {
+	.driver = {
+		.name = "tegra186-gpio",
+		.of_match_table = tegra186_gpio_of_match,
+	},
+	.probe = tegra186_gpio_probe,
+	.remove = tegra186_gpio_remove,
+};
+module_platform_driver(tegra186_gpio_driver);
+
+MODULE_DESCRIPTION("NVIDIA Tegra186 GPIO controller driver");
+MODULE_AUTHOR("Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>");
+MODULE_LICENSE("GPL v2");
-- 
2.12.0

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH 00/12] gpio: Tight IRQ chip integration and Tegra186 support
  2017-04-03 16:05 [PATCH 00/12] gpio: Tight IRQ chip integration and Tegra186 support Thierry Reding
                   ` (4 preceding siblings ...)
  2017-04-03 16:05 ` [PATCH 10/12] gpio: Move irq_handler to " Thierry Reding
@ 2017-04-06 22:34 ` Thierry Reding
       [not found]   ` <20170406223449.GH27728-EkSeR96xj6Pcmrwk2tT4+A@public.gmane.org>
  5 siblings, 1 reply; 20+ messages in thread
From: Thierry Reding @ 2017-04-06 22:34 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Alexandre Courbot, linux-gpio, linux-tegra

[-- Attachment #1: Type: text/plain, Size: 4962 bytes --]

On Mon, Apr 03, 2017 at 06:05:20PM +0200, Thierry Reding wrote:
> From: Thierry Reding <treding@nvidia.com>
> 
> Hi Linus,
> 
> here's a first draft of patches to make GPIOLIB_IRQCHIP flexible enough
> to support the Tegra186 use-case. Instead of just fixing the bugs that I
> had pointed out earlier, this goes one step further and completely
> integrates IRQ chip registration into GPIO chip registration. The idea
> is that drivers will initialize a set of fields (collected in a new
> struct gpio_irq_chip) before calling gpiochip_add() (or derivatives) and
> gpiolib will internally set up an IRQ domain and register the IRQ chip.
> 
> Currently this makes use of the new infrastructure only in the Tegra186
> driver, but I plan to convert a couple of others once we can agree that
> this is a direction that you're comfortable with.

Linus,

any comments on this?

Thierry

> Thierry Reding (12):
>   gpio: Use unsigned int for interrupt numbers
>   gpio: Implement tighter IRQ chip integration
>   gpio: Move irq_nested into struct gpio_irq_chip
>   gpio: Move irqdomain into struct gpio_irq_chip
>   gpio: Move irqchip into struct gpio_irq_chip
>   gpio: Move irq_valid_mask into struct gpio_irq_chip
>   gpio: Move lock_key into struct gpio_irq_chip
>   gpio: Move irq_chained_parent to struct gpio_irq_chip
>   gpio: Move irq_default_type to struct gpio_irq_chip
>   gpio: Move irq_handler to struct gpio_irq_chip
>   gpio: Move irq_base to struct gpio_irq_chip
>   gpio: Add Tegra186 support
> 
>  Documentation/gpio/driver.txt              |   6 +-
>  drivers/bcma/driver_gpio.c                 |   2 +-
>  drivers/gpio/Kconfig                       |   9 +
>  drivers/gpio/Makefile                      |   1 +
>  drivers/gpio/gpio-104-dio-48e.c            |   2 +-
>  drivers/gpio/gpio-104-idi-48.c             |   2 +-
>  drivers/gpio/gpio-104-idio-16.c            |   2 +-
>  drivers/gpio/gpio-adnp.c                   |   2 +-
>  drivers/gpio/gpio-altera.c                 |   4 +-
>  drivers/gpio/gpio-aspeed.c                 |   6 +-
>  drivers/gpio/gpio-ath79.c                  |   2 +-
>  drivers/gpio/gpio-brcmstb.c                |   2 +-
>  drivers/gpio/gpio-crystalcove.c            |   2 +-
>  drivers/gpio/gpio-dln2.c                   |   2 +-
>  drivers/gpio/gpio-ftgpio010.c              |   2 +-
>  drivers/gpio/gpio-intel-mid.c              |   2 +-
>  drivers/gpio/gpio-lynxpoint.c              |   2 +-
>  drivers/gpio/gpio-max732x.c                |   2 +-
>  drivers/gpio/gpio-mcp23s08.c               |   2 +-
>  drivers/gpio/gpio-merrifield.c             |   2 +-
>  drivers/gpio/gpio-mockup.c                 |  10 +-
>  drivers/gpio/gpio-omap.c                   |   2 +-
>  drivers/gpio/gpio-pca953x.c                |   2 +-
>  drivers/gpio/gpio-pcf857x.c                |   2 +-
>  drivers/gpio/gpio-pci-idio-16.c            |   2 +-
>  drivers/gpio/gpio-pl061.c                  |   2 +-
>  drivers/gpio/gpio-rcar.c                   |   2 +-
>  drivers/gpio/gpio-reg.c                    |   4 +-
>  drivers/gpio/gpio-stmpe.c                  |   6 +-
>  drivers/gpio/gpio-tc3589x.c                |   2 +-
>  drivers/gpio/gpio-tegra186.c               | 625 +++++++++++++++++++++++++++++
>  drivers/gpio/gpio-vf610.c                  |   2 +-
>  drivers/gpio/gpio-wcove.c                  |   2 +-
>  drivers/gpio/gpio-ws16c48.c                |   2 +-
>  drivers/gpio/gpio-xgene-sb.c               |   2 +-
>  drivers/gpio/gpio-xlp.c                    |   2 +-
>  drivers/gpio/gpio-zx.c                     |   2 +-
>  drivers/gpio/gpio-zynq.c                   |   2 +-
>  drivers/gpio/gpiolib.c                     | 232 ++++++++---
>  drivers/pinctrl/bcm/pinctrl-bcm2835.c      |   4 +-
>  drivers/pinctrl/bcm/pinctrl-iproc-gpio.c   |   2 +-
>  drivers/pinctrl/intel/pinctrl-baytrail.c   |   6 +-
>  drivers/pinctrl/intel/pinctrl-cherryview.c |   6 +-
>  drivers/pinctrl/intel/pinctrl-intel.c      |   2 +-
>  drivers/pinctrl/nomadik/pinctrl-nomadik.c  |   4 +-
>  drivers/pinctrl/pinctrl-amd.c              |   2 +-
>  drivers/pinctrl/pinctrl-at91.c             |   2 +-
>  drivers/pinctrl/pinctrl-coh901.c           |   2 +-
>  drivers/pinctrl/pinctrl-oxnas.c            |   2 +-
>  drivers/pinctrl/pinctrl-pic32.c            |   2 +-
>  drivers/pinctrl/pinctrl-pistachio.c        |   2 +-
>  drivers/pinctrl/pinctrl-st.c               |   2 +-
>  drivers/pinctrl/pinctrl-sx150x.c           |   2 +-
>  drivers/pinctrl/qcom/pinctrl-msm.c         |   2 +-
>  drivers/pinctrl/sirf/pinctrl-atlas7.c      |   2 +-
>  drivers/pinctrl/sirf/pinctrl-sirf.c        |   2 +-
>  drivers/pinctrl/spear/pinctrl-plgpio.c     |   2 +-
>  include/linux/gpio/driver.h                |  81 ++--
>  58 files changed, 943 insertions(+), 147 deletions(-)
>  create mode 100644 drivers/gpio/gpio-tegra186.c
> 
> -- 
> 2.12.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 01/12] gpio: Use unsigned int for interrupt numbers
       [not found]     ` <20170403160532.20282-2-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2017-04-13 12:17       ` Linus Walleij
  0 siblings, 0 replies; 20+ messages in thread
From: Linus Walleij @ 2017-04-13 12:17 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Alexandre Courbot, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA

On Mon, Apr 3, 2017 at 6:05 PM, Thierry Reding <thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:

> From: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
>
> Interrupt numbers are never negative, zero serves as the special invalid
> value.
>
> Signed-off-by: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

Patch applied for devel (v4.12).

The rest we need to discuss.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 00/12] gpio: Tight IRQ chip integration and Tegra186 support
       [not found] ` <20170403160532.20282-1-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
                     ` (7 preceding siblings ...)
  2017-04-03 16:05   ` [PATCH v3 12/12] gpio: Add Tegra186 support Thierry Reding
@ 2017-04-13 12:22   ` Linus Walleij
  8 siblings, 0 replies; 20+ messages in thread
From: Linus Walleij @ 2017-04-13 12:22 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Alexandre Courbot, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA

On Mon, Apr 3, 2017 at 6:05 PM, Thierry Reding <thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:

> here's a first draft of patches to make GPIOLIB_IRQCHIP flexible enough
> to support the Tegra186 use-case. Instead of just fixing the bugs that I
> had pointed out earlier, this goes one step further and completely
> integrates IRQ chip registration into GPIO chip registration. The idea
> is that drivers will initialize a set of fields (collected in a new
> struct gpio_irq_chip) before calling gpiochip_add() (or derivatives) and
> gpiolib will internally set up an IRQ domain and register the IRQ chip.
>
> Currently this makes use of the new infrastructure only in the Tegra186
> driver, but I plan to convert a couple of others once we can agree that
> this is a direction that you're comfortable with.

So I like what you are doing here, I applied patch 1 which is an obvious
fix.

Patches 2-11 need to be applied early after v4.12-rc1 (after rebasing)
and pulled into both the GPIO and pin control trees so we do not
get development glitches. It gives a more elegant structure to things.

I will look into patch 12 especially to see how you use the infrastructure.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 00/12] gpio: Tight IRQ chip integration and Tegra186 support
       [not found]   ` <20170406223449.GH27728-EkSeR96xj6Pcmrwk2tT4+A@public.gmane.org>
@ 2017-04-13 12:23     ` Linus Walleij
  0 siblings, 0 replies; 20+ messages in thread
From: Linus Walleij @ 2017-04-13 12:23 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Alexandre Courbot, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA

On Fri, Apr 7, 2017 at 12:34 AM, Thierry Reding
<thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On Mon, Apr 03, 2017 at 06:05:20PM +0200, Thierry Reding wrote:
>> From: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
>>
>> Hi Linus,
>>
>> here's a first draft of patches to make GPIOLIB_IRQCHIP flexible enough
>> to support the Tegra186 use-case. Instead of just fixing the bugs that I
>> had pointed out earlier, this goes one step further and completely
>> integrates IRQ chip registration into GPIO chip registration. The idea
>> is that drivers will initialize a set of fields (collected in a new
>> struct gpio_irq_chip) before calling gpiochip_add() (or derivatives) and
>> gpiolib will internally set up an IRQ domain and register the IRQ chip.
>>
>> Currently this makes use of the new infrastructure only in the Tegra186
>> driver, but I plan to convert a couple of others once we can agree that
>> this is a direction that you're comfortable with.
>
> Linus,
>
> any comments on this?

Just overworked and snowed under as usual, sorry for that.

The patches as such cannot be merged at this point in the development
cycle but becomes material for the next kernel cycle due to changing
API in all the drivers using the infrastructure.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v3 12/12] gpio: Add Tegra186 support
       [not found]     ` <20170403160532.20282-13-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2017-04-13 12:38       ` Linus Walleij
       [not found]         ` <CACRpkdaQacEqqW9Vdn7mtnZMH_VvL1B-35VFV=PcORwgtLz2eg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 20+ messages in thread
From: Linus Walleij @ 2017-04-13 12:38 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Alexandre Courbot, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA

On Mon, Apr 3, 2017 at 6:05 PM, Thierry Reding <thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:

> From: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
>
> Tegra186 has two GPIO controllers that are largely register compatible
> between one another but are completely different from the controller
> found on earlier generations.
>
> Signed-off-by: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> ---
> Changes in v3:
> - make use of GPIOLIB_IRQCHIP for IRQ chip handling

So this is the interesting patch where you make use of the new
tightly integrated IRQchip.

> +struct tegra_gpio {
> +       struct gpio_chip gpio;
> +       struct irq_chip intc;
> +       unsigned int num_irq;
> +       unsigned int *irq;

So I find it a bit strange that the array of irq parents is still kept around
when you add so much infrastructure. Could this not just go into the core
so that is natively able to handle multiple parents cleanly?

> +static int tegra186_gpio_of_xlate(struct gpio_chip *chip,
> +                                 const struct of_phandle_args *spec,
> +                                 u32 *flags)
> +{
> +       struct tegra_gpio *gpio = gpiochip_get_data(chip);
> +       unsigned int port, pin, i, offset = 0;
> +
> +       if (WARN_ON(chip->of_gpio_n_cells < 2))
> +               return -EINVAL;
> +
> +       if (WARN_ON(spec->args_count < chip->of_gpio_n_cells))
> +               return -EINVAL;
> +
> +       port = spec->args[0] / 8;
> +       pin = spec->args[0] % 8;

Actually modular ports/banks is something we will also see again and
have seen before. Maybe this should be a new core xlate function
just taking some MOD argument.

> +static void tegra186_gpio_irq(struct irq_desc *desc)
> +{
> +       struct tegra_gpio *gpio = irq_desc_get_handler_data(desc);
> +       struct irq_domain *domain = gpio->gpio.irq.domain;
> +       struct irq_chip *chip = irq_desc_get_chip(desc);
> +       unsigned int parent = irq_desc_get_irq(desc);
> +       unsigned int i, offset = 0;
> +
> +       chained_irq_enter(chip, desc);
> +
> +       for (i = 0; i < gpio->soc->num_ports; i++) {
> +               const struct tegra_gpio_port *port = &gpio->soc->ports[i];
> +               void __iomem *base = gpio->base + port->offset;
> +               unsigned int pin, irq;
> +               unsigned long value;
> +
> +               /* skip ports that are not associated with this controller */
> +               if (parent != gpio->irq[port->irq])
> +                       goto skip;

This parent-to-irq lookup I think the core should handle.

> +static int tegra186_gpio_irq_domain_xlate(struct irq_domain *domain,
> +                                         struct device_node *np,
> +                                         const u32 *spec, unsigned int size,
> +                                         unsigned long *hwirq,
> +                                         unsigned int *type)
> +{
> +       struct tegra_gpio *gpio = gpiochip_get_data(domain->host_data);
> +       unsigned int port, pin, i, offset = 0;
> +
> +       if (size < 2)
> +               return -EINVAL;
> +
> +       port = spec[0] / 8;
> +       pin = spec[0] % 8;

Here is this MOD business again. This is clearly a pattern.

> +       err = of_irq_count(pdev->dev.of_node);
> +       if (err < 0)
> +               return err;
> +
> +       gpio->num_irq = err;

This variable (err) has a confusing name. This is clearly not an error
at this point. Can you rename it to "ret" or something?

> +       gpio->irq = devm_kcalloc(&pdev->dev, gpio->num_irq, sizeof(*gpio->irq),
> +                                GFP_KERNEL);
> +       if (!gpio->irq)
> +               return -ENOMEM;
> +
> +       for (i = 0; i < gpio->num_irq; i++) {
> +               err = platform_get_irq(pdev, i);
> +               if (err < 0)
> +                       return err;
> +
> +               gpio->irq[i] = err;
> +       }

So this array of parent IRQs I think should be stored in the core
gpio irqchip, not here locally in the driver.

> +       for (i = 0, offset = 0; i < gpio->soc->num_ports; i++) {
> +               const struct tegra_gpio_port *port = &gpio->soc->ports[i];
> +               char *name;
> +
> +               for (j = 0; j < port->pins; j++) {
> +                       name = devm_kasprintf(gpio->gpio.parent, GFP_KERNEL,
> +                                             "P%s.%02x", port->name, j);
> +                       if (!name)
> +                               return -ENOMEM;
> +
> +                       names[offset + j] = name;
> +               }
> +
> +               offset += port->pins;
> +       }

Interesting way of using the names array. This will override any names
from the device tree I think, don't you want to use gpio-line-names = ""..
in the device tree instead?

> +       irq = &gpio->gpio.irq;
> +       irq->chip = &gpio->intc;
> +       irq->first = 0;
> +       irq->domain_ops = &tegra186_gpio_irq_domain_ops;
> +       irq->handler = handle_simple_irq;
> +       irq->lock_key = &tegra186_gpio_lock_class;
> +       irq->default_type = IRQ_TYPE_NONE;
> +       irq->parent_handler = tegra186_gpio_irq;
> +       irq->parent_handler_data = gpio;
> +       irq->num_parents = gpio->num_irq;
> +       irq->parents = gpio->irq;
> +
> +       irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio,
> +                               sizeof(*irq->map), GFP_KERNEL);
> +       if (!irq->map)
> +               return -ENOMEM;
> +
> +       for (i = 0, offset = 0; i < gpio->soc->num_ports; i++) {
> +               const struct tegra_gpio_port *port = &gpio->soc->ports[i];
> +
> +               for (j = 0; j < port->pins; j++)
> +                       irq->map[offset + j] = irq->parents[port->irq];
> +
> +               offset += port->pins;
> +       }

So this is the core API use. But setting up the map in the driver, that
seems too much to implement over and over again for all drivers
don't you think? Also to have local irqdomain operations. All that
should be in the core and be reusable IMO.

I would imagine that the core keeps track of the parent IRQs and
will make sure to free up all maps of all IRQs when the GPIOchip
is removed.

Maybe I'm missing something about this, I was simply expecting
a full multi-parent handling and tracking in the core, moving the
drivers that now loose track of their parents over to that as well.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v3 12/12] gpio: Add Tegra186 support
       [not found]         ` <CACRpkdaQacEqqW9Vdn7mtnZMH_VvL1B-35VFV=PcORwgtLz2eg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2017-04-13 15:19           ` Thierry Reding
  2017-05-11  8:30             ` Linus Walleij
  0 siblings, 1 reply; 20+ messages in thread
From: Thierry Reding @ 2017-04-13 15:19 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Alexandre Courbot, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 10738 bytes --]

On Thu, Apr 13, 2017 at 02:38:44PM +0200, Linus Walleij wrote:
> On Mon, Apr 3, 2017 at 6:05 PM, Thierry Reding <thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> 
> > From: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> >
> > Tegra186 has two GPIO controllers that are largely register compatible
> > between one another but are completely different from the controller
> > found on earlier generations.
> >
> > Signed-off-by: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> > ---
> > Changes in v3:
> > - make use of GPIOLIB_IRQCHIP for IRQ chip handling
> 
> So this is the interesting patch where you make use of the new
> tightly integrated IRQchip.
> 
> > +struct tegra_gpio {
> > +       struct gpio_chip gpio;
> > +       struct irq_chip intc;
> > +       unsigned int num_irq;
> > +       unsigned int *irq;
> 
> So I find it a bit strange that the array of irq parents is still kept around
> when you add so much infrastructure. Could this not just go into the core
> so that is natively able to handle multiple parents cleanly?

I did this on purpose because I'd like to avoid making this new
infrastructure into too much of a midlayer. The mechanism to parse
interrupts may depend on the driver. Perhaps a good middle ground
would be to provide generic helpers that will parse this, while
keeping the possibility to let the driver specify the list?

> > +static int tegra186_gpio_of_xlate(struct gpio_chip *chip,
> > +                                 const struct of_phandle_args *spec,
> > +                                 u32 *flags)
> > +{
> > +       struct tegra_gpio *gpio = gpiochip_get_data(chip);
> > +       unsigned int port, pin, i, offset = 0;
> > +
> > +       if (WARN_ON(chip->of_gpio_n_cells < 2))
> > +               return -EINVAL;
> > +
> > +       if (WARN_ON(spec->args_count < chip->of_gpio_n_cells))
> > +               return -EINVAL;
> > +
> > +       port = spec->args[0] / 8;
> > +       pin = spec->args[0] % 8;
> 
> Actually modular ports/banks is something we will also see again and
> have seen before. Maybe this should be a new core xlate function
> just taking some MOD argument.

This xlate function uses driver-specific data to compute the hwirq
number of the specified GPIO. That's not something I think we can easily
turn into a generic helper, not without adding a lot more infrastructure
than we already have. One of the problems that I see with adding too
much infrastructure is that the core will become completely unwieldy
because it has to take care of too many special cases.

> > +static void tegra186_gpio_irq(struct irq_desc *desc)
> > +{
> > +       struct tegra_gpio *gpio = irq_desc_get_handler_data(desc);
> > +       struct irq_domain *domain = gpio->gpio.irq.domain;
> > +       struct irq_chip *chip = irq_desc_get_chip(desc);
> > +       unsigned int parent = irq_desc_get_irq(desc);
> > +       unsigned int i, offset = 0;
> > +
> > +       chained_irq_enter(chip, desc);
> > +
> > +       for (i = 0; i < gpio->soc->num_ports; i++) {
> > +               const struct tegra_gpio_port *port = &gpio->soc->ports[i];
> > +               void __iomem *base = gpio->base + port->offset;
> > +               unsigned int pin, irq;
> > +               unsigned long value;
> > +
> > +               /* skip ports that are not associated with this controller */
> > +               if (parent != gpio->irq[port->irq])
> > +                       goto skip;
> 
> This parent-to-irq lookup I think the core should handle.

Again, this is based heavily on data that is highly Tegra-specific. If
we wanted to support something like this in the core, we'd have to add
some generic version of struct tegra_gpio_port, which has the
disadvantage of making it more difficult to support for drivers that
have only a single parent interrupt.

> > +static int tegra186_gpio_irq_domain_xlate(struct irq_domain *domain,
> > +                                         struct device_node *np,
> > +                                         const u32 *spec, unsigned int size,
> > +                                         unsigned long *hwirq,
> > +                                         unsigned int *type)
> > +{
> > +       struct tegra_gpio *gpio = gpiochip_get_data(domain->host_data);
> > +       unsigned int port, pin, i, offset = 0;
> > +
> > +       if (size < 2)
> > +               return -EINVAL;
> > +
> > +       port = spec[0] / 8;
> > +       pin = spec[0] % 8;
> 
> Here is this MOD business again. This is clearly a pattern.

The same as above applies. Yes, we could support this in the core but at
the expense of making it difficult to write simple drivers.

> > +       err = of_irq_count(pdev->dev.of_node);
> > +       if (err < 0)
> > +               return err;
> > +
> > +       gpio->num_irq = err;
> 
> This variable (err) has a confusing name. This is clearly not an error
> at this point. Can you rename it to "ret" or something?

Yeah, why not.

> > +       gpio->irq = devm_kcalloc(&pdev->dev, gpio->num_irq, sizeof(*gpio->irq),
> > +                                GFP_KERNEL);
> > +       if (!gpio->irq)
> > +               return -ENOMEM;
> > +
> > +       for (i = 0; i < gpio->num_irq; i++) {
> > +               err = platform_get_irq(pdev, i);
> > +               if (err < 0)
> > +                       return err;
> > +
> > +               gpio->irq[i] = err;
> > +       }
> 
> So this array of parent IRQs I think should be stored in the core
> gpio irqchip, not here locally in the driver.

Well, it's already stored in the struct gpio_irq_chip, but it is the
driver that allocates it, because the mechanism to construct it is
driver-specific, hence I prefer it to be in the driver to make it
explicit that it is the driver that owns it. That way the array of
interrupts stored in struct gpio_irq_chip can be defined as merely a
reference, so it is very clear that the core shouldn't touch it. In
fact I had thought about making it even more explicit by making the
struct gpio_irq_chip carry a const unsigned int * for these.

If we only store it in the core, it becomes ambiguous who owns it.
Should the core be responsible for freeing it? How does the core decide
that it is responsible for managing it?

> > +       for (i = 0, offset = 0; i < gpio->soc->num_ports; i++) {
> > +               const struct tegra_gpio_port *port = &gpio->soc->ports[i];
> > +               char *name;
> > +
> > +               for (j = 0; j < port->pins; j++) {
> > +                       name = devm_kasprintf(gpio->gpio.parent, GFP_KERNEL,
> > +                                             "P%s.%02x", port->name, j);
> > +                       if (!name)
> > +                               return -ENOMEM;
> > +
> > +                       names[offset + j] = name;
> > +               }
> > +
> > +               offset += port->pins;
> > +       }
> 
> Interesting way of using the names array. This will override any names
> from the device tree I think, don't you want to use gpio-line-names = ""..
> in the device tree instead?

I don't think this overrides any names provided in DT. The names are
picked up from this arry in gpiochip_set_desc_names(), which is called
before of_gpiochip_add() where the names are read from DT. So this will
effectively make the driver set default names for the pins, but allow
these names to be overridden by DT.

Putting these names into DT feels wrong because they can easily be
generated from the port and pin numbers.

> > +       irq = &gpio->gpio.irq;
> > +       irq->chip = &gpio->intc;
> > +       irq->first = 0;
> > +       irq->domain_ops = &tegra186_gpio_irq_domain_ops;
> > +       irq->handler = handle_simple_irq;
> > +       irq->lock_key = &tegra186_gpio_lock_class;
> > +       irq->default_type = IRQ_TYPE_NONE;
> > +       irq->parent_handler = tegra186_gpio_irq;
> > +       irq->parent_handler_data = gpio;
> > +       irq->num_parents = gpio->num_irq;
> > +       irq->parents = gpio->irq;
> > +
> > +       irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio,
> > +                               sizeof(*irq->map), GFP_KERNEL);
> > +       if (!irq->map)
> > +               return -ENOMEM;
> > +
> > +       for (i = 0, offset = 0; i < gpio->soc->num_ports; i++) {
> > +               const struct tegra_gpio_port *port = &gpio->soc->ports[i];
> > +
> > +               for (j = 0; j < port->pins; j++)
> > +                       irq->map[offset + j] = irq->parents[port->irq];
> > +
> > +               offset += port->pins;
> > +       }
> 
> So this is the core API use. But setting up the map in the driver, that
> seems too much to implement over and over again for all drivers
> don't you think? Also to have local irqdomain operations. All that
> should be in the core and be reusable IMO.

Like I said above, the mapping is highly specific to Tegra. The only way
to move this into the core is to provide even more infrastructure. I'm
not sure that would be wise at this point. Maybe that can be added at a
later point when we have more samples.

Similarly I think having the driver specify IRQ domain operations is
useful because it increases the flexibility to do what drivers need,
rather than restricting the drivers to what the midlayer defines. If we
wrap all of this into the core, we're likely going to face situations
where we either have to rework or add quirks to the core because some
drivers need some extra flexibility.

The above tries to implement the infrastructure as a library of helpers
which has the advantage that for the common cases the core can provide
helpers, but drivers can also substitute their own if they need to.

> I would imagine that the core keeps track of the parent IRQs and
> will make sure to free up all maps of all IRQs when the GPIOchip
> is removed.
> 
> Maybe I'm missing something about this, I was simply expecting
> a full multi-parent handling and tracking in the core, moving the
> drivers that now loose track of their parents over to that as well.

There are two pieces to this: this series prepares the infrastructure to
deal with multiple parent interrupts better and uses that infrastructure
in the new Tegra driver. But it also keeps the driver-specific bits in
the driver. Certainly there's a possibility to refactor some of that
later on, but I think it's premature to do that right away. We'd need to
convert a slew of other drivers first to see if the same pattern appears
or if these are chip-specific after all.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v3 12/12] gpio: Add Tegra186 support
  2017-04-13 15:19           ` Thierry Reding
@ 2017-05-11  8:30             ` Linus Walleij
  0 siblings, 0 replies; 20+ messages in thread
From: Linus Walleij @ 2017-05-11  8:30 UTC (permalink / raw)
  To: Thierry Reding; +Cc: Alexandre Courbot, linux-gpio, linux-tegra

Sorry for taking so long before I get back to answering these important
architecture questions. I am just overburdened by work in the merge
window time frames. :(

On Thu, Apr 13, 2017 at 5:19 PM, Thierry Reding
<thierry.reding@gmail.com> wrote:
> On Thu, Apr 13, 2017 at 02:38:44PM +0200, Linus Walleij wrote:

>> > +struct tegra_gpio {
>> > +       struct gpio_chip gpio;
>> > +       struct irq_chip intc;
>> > +       unsigned int num_irq;
>> > +       unsigned int *irq;
>>
>> So I find it a bit strange that the array of irq parents is still kept around
>> when you add so much infrastructure. Could this not just go into the core
>> so that is natively able to handle multiple parents cleanly?
>
> I did this on purpose because I'd like to avoid making this new
> infrastructure into too much of a midlayer. The mechanism to parse
> interrupts may depend on the driver. Perhaps a good middle ground
> would be to provide generic helpers that will parse this, while
> keeping the possibility to let the driver specify the list?

I don't know honestly, the way I code is usually the most elegant
solution pops out by itself when I work on the code. We have a bit
of stuff in the gpiolib (I guess that is what you mean by the midlayer)
for example the ability to mask off individual IRQ lines as
non-requestable.

I do not see a problem for gpiolib to keep a list of parents which may
contain only one item, and special functions like
gpiochip_set_chained_irqchip_multiparent() and
gpiochip_set_nested_irqchip_multiparent() with
gpiochip_set_chained_irqchip() just calling the former with
a static inline passing a list of just one parent.

And thus we would keep track of all parents inside of gpiolib.

>> > +static int tegra186_gpio_of_xlate(struct gpio_chip *chip,
>> > +                                 const struct of_phandle_args *spec,
>> > +                                 u32 *flags)
>> > +{
>> > +       struct tegra_gpio *gpio = gpiochip_get_data(chip);
>> > +       unsigned int port, pin, i, offset = 0;
>> > +
>> > +       if (WARN_ON(chip->of_gpio_n_cells < 2))
>> > +               return -EINVAL;
>> > +
>> > +       if (WARN_ON(spec->args_count < chip->of_gpio_n_cells))
>> > +               return -EINVAL;
>> > +
>> > +       port = spec->args[0] / 8;
>> > +       pin = spec->args[0] % 8;
>>
>> Actually modular ports/banks is something we will also see again and
>> have seen before. Maybe this should be a new core xlate function
>> just taking some MOD argument.
>
> This xlate function uses driver-specific data to compute the hwirq
> number of the specified GPIO. That's not something I think we can easily
> turn into a generic helper, not without adding a lot more infrastructure
> than we already have. One of the problems that I see with adding too
> much infrastructure is that the core will become completely unwieldy
> because it has to take care of too many special cases.

I understand that concern.

But the problem I have as a maintainer, and I speak from experience
doing the job, is that maintaining the core is causing very little
problems because it solves problems for a lot of drivers in one single
spot.

What is causing me problems is a lot of duplicated or "almost-the-same"
code in a lot of drivers, making similar bugs pop out and clog my
inbox with similar semantic (and valid) patches generated by cocinelle
because now the bugs are all over the place instead of confined to
the gpiolib core.

I do not think parametrized xlate functions for 8, 16 and 32 bits of
MOD on the arg, so that interrupt parent A, B, C is assigned
depending on whether arg MOD [8, 16, 32] is 0, 1, 2 is very
extraordinary. It more seems to be what can be expected from
every chained driver with multiple IRQ parents, and thus
reusable.

As soon as it is used by more than one driver, it is a win for
me.

The compiler will not include it in the final zImage if there
are no users, so it is not a footprint issue.

>> > +static void tegra186_gpio_irq(struct irq_desc *desc)
>> > +{
>> > +       struct tegra_gpio *gpio = irq_desc_get_handler_data(desc);
>> > +       struct irq_domain *domain = gpio->gpio.irq.domain;
>> > +       struct irq_chip *chip = irq_desc_get_chip(desc);
>> > +       unsigned int parent = irq_desc_get_irq(desc);
>> > +       unsigned int i, offset = 0;
>> > +
>> > +       chained_irq_enter(chip, desc);
>> > +
>> > +       for (i = 0; i < gpio->soc->num_ports; i++) {
>> > +               const struct tegra_gpio_port *port = &gpio->soc->ports[i];
>> > +               void __iomem *base = gpio->base + port->offset;
>> > +               unsigned int pin, irq;
>> > +               unsigned long value;
>> > +
>> > +               /* skip ports that are not associated with this controller */
>> > +               if (parent != gpio->irq[port->irq])
>> > +                       goto skip;
>>
>> This parent-to-irq lookup I think the core should handle.
>
> Again, this is based heavily on data that is highly Tegra-specific. If
> we wanted to support something like this in the core, we'd have to add
> some generic version of struct tegra_gpio_port, which has the
> disadvantage of making it more difficult to support for drivers that
> have only a single parent interrupt.

This concept:

- The chip has multiple parents

- The multiple parents correspond to multiple "ports" or actually registers,
  that are n bits wide, and map 1:1 between a parent and a "port".

Is nothing unique at all. I have seen it dozens of times and I see an
increasing influx of driver doing exactly this.

Normally my gut reaction is to have one driver instance per "port" so that
each port is its own device, but several times driver writers convinced me
that they need to have it inside a parent device (like a pin controller
or so), and that instead complicates these functions.

But I think they are pretty much all the same and something can be
done to abstract this. I am thinking something like bitmaps that
map an GPIO interrupt line back to its parent IRQ.

We need to think it through and look at some examples.

For example:
bcm2835_gpio_irq_handler in bcm/pinctrl-bcm2835.c
iproc_gpio_irq_handler in bcm/pinctrl-iproc-gpio.c
adi_gpio_handle_pint_irq in pinctrl-adi2.c
atlas7_gpio_handle_irq in sirf/pinctrl-atlas7.c
bcm_kona_gpio_irq_handler in gpio-bcm-kona.c
mx2_gpio_irq_handler in gpio-mxc.c
tegra_gpio_irq_handler in gpio-tegra.c
xlp_gpio_generic_handler in gpio-xlp.c
zynq_gpio_irqhandler in gpio-zynq.c

They all do some bank-to-parent "magic" in their interrupt handlers.
I'm suspecting that even pcs_irq_handle() in
pinctrl-single.c does something similar.

I strongly suspect they could all use some simple bitmap,
hashmap or similar to associate banks to parent IRQs.

It's not like I'm asking you to upfront clean up this mess
(because it is a mess) but if you invented something that generalized
this for just say tegra186 and gpio-tegra that you work on,
I'd be a happy cow. (And you get to decide what everyone
else has to do to map children to parents... yeah I can attack
patch those drivers after that.)

>> > +       gpio->irq = devm_kcalloc(&pdev->dev, gpio->num_irq, sizeof(*gpio->irq),
>> > +                                GFP_KERNEL);
>> > +       if (!gpio->irq)
>> > +               return -ENOMEM;
>> > +
>> > +       for (i = 0; i < gpio->num_irq; i++) {
>> > +               err = platform_get_irq(pdev, i);
>> > +               if (err < 0)
>> > +                       return err;
>> > +
>> > +               gpio->irq[i] = err;
>> > +       }
>>
>> So this array of parent IRQs I think should be stored in the core
>> gpio irqchip, not here locally in the driver.
>
> Well, it's already stored in the struct gpio_irq_chip, but it is the
> driver that allocates it, because the mechanism to construct it is
> driver-specific, hence I prefer it to be in the driver to make it
> explicit that it is the driver that owns it. That way the array of
> interrupts stored in struct gpio_irq_chip can be defined as merely a
> reference, so it is very clear that the core shouldn't touch it.

It's fine if it is only a reference to an interrupt obtained with e.g.
platform_get_irq() no problem with that. I am not expecting the core
to *parse* IRQs, just keep track of them, and how they map to
"banks".

> In
> fact I had thought about making it even more explicit by making the
> struct gpio_irq_chip carry a const unsigned int * for these.

That is a good idea.

> If we only store it in the core, it becomes ambiguous who owns it.
> Should the core be responsible for freeing it? How does the core decide
> that it is responsible for managing it?

I don't understand what you mean by "freeing it"?

As those are mostly chained handler the drivers never e.g.
request the IRQs in the first place, that is done by the consumers
that just let the handler ripple down the chain.

>> > +       for (i = 0, offset = 0; i < gpio->soc->num_ports; i++) {
>> > +               const struct tegra_gpio_port *port = &gpio->soc->ports[i];
>> > +               char *name;
>> > +
>> > +               for (j = 0; j < port->pins; j++) {
>> > +                       name = devm_kasprintf(gpio->gpio.parent, GFP_KERNEL,
>> > +                                             "P%s.%02x", port->name, j);
>> > +                       if (!name)
>> > +                               return -ENOMEM;
>> > +
>> > +                       names[offset + j] = name;
>> > +               }
>> > +
>> > +               offset += port->pins;
>> > +       }
>>
>> Interesting way of using the names array. This will override any names
>> from the device tree I think, don't you want to use gpio-line-names = ""..
>> in the device tree instead?
>
> I don't think this overrides any names provided in DT. The names are
> picked up from this arry in gpiochip_set_desc_names(), which is called
> before of_gpiochip_add() where the names are read from DT. So this will
> effectively make the driver set default names for the pins, but allow
> these names to be overridden by DT.

Ah yeah I see. I coded that actually :D

OK fine then, that is actually a design pattern we should encourage,
it's very helpful to have default names and let the device tree override
them if it can be more specific.

> Putting these names into DT feels wrong because they can easily be
> generated from the port and pin numbers.

It's fine, keep it.

> Like I said above, the mapping is highly specific to Tegra. The only way
> to move this into the core is to provide even more infrastructure. I'm
> not sure that would be wise at this point. Maybe that can be added at a
> later point when we have more samples.

We have those samples. Outlined above. gpio-tegra is one of them.

> Similarly I think having the driver specify IRQ domain operations is
> useful because it increases the flexibility to do what drivers need,
> rather than restricting the drivers to what the midlayer defines. If we
> wrap all of this into the core, we're likely going to face situations
> where we either have to rework or add quirks to the core because some
> drivers need some extra flexibility.

We already have out-of-core handling with e.g. hierarchical irq domains.

That is fine.

But I feel that this driver is looking familiar to things I've seen before,
and my grep operation above seems to confirm this.

It is mapping IRQ sources in "banks" to parent IRQs, and
that is being done all over the place, so we should generalize
it.

> There are two pieces to this: this series prepares the infrastructure to
> deal with multiple parent interrupts better and uses that infrastructure
> in the new Tegra driver. But it also keeps the driver-specific bits in
> the driver. Certainly there's a possibility to refactor some of that
> later on, but I think it's premature to do that right away. We'd need to
> convert a slew of other drivers first to see if the same pattern appears
> or if these are chip-specific after all.

I kind of like the new struct and all. I just feel it doesn't add enough
value unless we also deal with this bank-irq-to-parent mapping inside
the core as well as part of this.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2017-05-11  8:30 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-04-03 16:05 [PATCH 00/12] gpio: Tight IRQ chip integration and Tegra186 support Thierry Reding
2017-04-03 16:05 ` [PATCH 02/12] gpio: Implement tighter IRQ chip integration Thierry Reding
     [not found] ` <20170403160532.20282-1-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2017-04-03 16:05   ` [PATCH 01/12] gpio: Use unsigned int for interrupt numbers Thierry Reding
     [not found]     ` <20170403160532.20282-2-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2017-04-13 12:17       ` Linus Walleij
2017-04-03 16:05   ` [PATCH 03/12] gpio: Move irq_nested into struct gpio_irq_chip Thierry Reding
2017-04-03 16:05   ` [PATCH 04/12] gpio: Move irqdomain " Thierry Reding
2017-04-03 16:05   ` [PATCH 07/12] gpio: Move lock_key " Thierry Reding
2017-04-03 16:05   ` [PATCH 08/12] gpio: Move irq_chained_parent to " Thierry Reding
2017-04-03 16:05   ` [PATCH 09/12] gpio: Move irq_default_type " Thierry Reding
2017-04-03 16:05   ` [PATCH 11/12] gpio: Move irq_base " Thierry Reding
2017-04-03 16:05   ` [PATCH v3 12/12] gpio: Add Tegra186 support Thierry Reding
     [not found]     ` <20170403160532.20282-13-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2017-04-13 12:38       ` Linus Walleij
     [not found]         ` <CACRpkdaQacEqqW9Vdn7mtnZMH_VvL1B-35VFV=PcORwgtLz2eg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2017-04-13 15:19           ` Thierry Reding
2017-05-11  8:30             ` Linus Walleij
2017-04-13 12:22   ` [PATCH 00/12] gpio: Tight IRQ chip integration and " Linus Walleij
2017-04-03 16:05 ` [PATCH 05/12] gpio: Move irqchip into struct gpio_irq_chip Thierry Reding
2017-04-03 16:05 ` [PATCH 06/12] gpio: Move irq_valid_mask " Thierry Reding
2017-04-03 16:05 ` [PATCH 10/12] gpio: Move irq_handler to " Thierry Reding
2017-04-06 22:34 ` [PATCH 00/12] gpio: Tight IRQ chip integration and Tegra186 support Thierry Reding
     [not found]   ` <20170406223449.GH27728-EkSeR96xj6Pcmrwk2tT4+A@public.gmane.org>
2017-04-13 12:23     ` Linus Walleij

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.