All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/16] gpio: Tight IRQ chip integration and banked infrastructure
@ 2017-09-28  9:56 ` Thierry Reding
  0 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-09-28  9:56 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Jonathan Hunter, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

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

Hi Linus,

here's the latest series of patches that implement the tighter IRQ chip
integration as well as the banked GPIO infrastructure that we had
discussed a couple of weeks/months back.

The first couple of patches are mostly preparatory work in order to
consolidate all IRQ chip related fields in a new structure and create
the base functionality for adding IRQ chips.

After that, I've added the Tegra186 GPIO support patch that makes use of
the new tight integration.

To round things off the new banked GPIO infrastructure is added (along
with some more preparatory work), followed by the conversion of the two
Tegra GPIO drivers to the new infrastructure.

Changes in v2:
- rename pins to lines for consistent terminology
- rename gpio_irq_chip_banked_handler() to
  gpio_irq_chip_banked_chained_handler()

Thierry

Thierry Reding (16):
  gpio: Implement tighter IRQ chip integration
  gpio: Move irqchip into struct gpio_irq_chip
  gpio: Move irqdomain into struct gpio_irq_chip
  gpio: Move irq_base to struct gpio_irq_chip
  gpio: Move irq_handler to struct gpio_irq_chip
  gpio: Move irq_default_type to struct gpio_irq_chip
  gpio: Move irq_chained_parent to struct gpio_irq_chip
  gpio: Move irq_nested 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: Add Tegra186 support
  gpio: omap: Fix checkpatch warnings
  gpio: omap: Rename struct gpio_bank to struct omap_gpio_bank
  gpio: Add support for banked GPIO controllers
  gpio: tegra: Use banked GPIO infrastructure
  gpio: tegra186: Use banked GPIO infrastructure

 Documentation/gpio/driver.txt               |   6 +-
 drivers/bcma/driver_gpio.c                  |   2 +-
 drivers/gpio/Kconfig                        |  10 +
 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-ingenic.c                 |   2 +-
 drivers/gpio/gpio-intel-mid.c               |   2 +-
 drivers/gpio/gpio-lynxpoint.c               |   2 +-
 drivers/gpio/gpio-max732x.c                 |   2 +-
 drivers/gpio/gpio-merrifield.c              |   2 +-
 drivers/gpio/gpio-omap.c                    | 222 ++++++-----
 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-tegra.c                   | 203 +++++-----
 drivers/gpio/gpio-tegra186.c                | 571 ++++++++++++++++++++++++++++
 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-of.c                   | 101 +++++
 drivers/gpio/gpiolib.c                      | 320 ++++++++++++++--
 drivers/pinctrl/bcm/pinctrl-bcm2835.c       |   5 +-
 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/mvebu/pinctrl-armada-37xx.c |   4 +-
 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-mcp23s08.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 +-
 drivers/platform/x86/intel_int0002_vgpio.c  |   6 +-
 include/linux/gpio/driver.h                 | 272 +++++++++++--
 include/linux/of_gpio.h                     |  10 +
 63 files changed, 1505 insertions(+), 348 deletions(-)
 create mode 100644 drivers/gpio/gpio-tegra186.c

-- 
2.14.1

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

* [PATCH v2 00/16] gpio: Tight IRQ chip integration and banked infrastructure
@ 2017-09-28  9:56 ` Thierry Reding
  0 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-09-28  9:56 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

From: Thierry Reding <treding@nvidia.com>

Hi Linus,

here's the latest series of patches that implement the tighter IRQ chip
integration as well as the banked GPIO infrastructure that we had
discussed a couple of weeks/months back.

The first couple of patches are mostly preparatory work in order to
consolidate all IRQ chip related fields in a new structure and create
the base functionality for adding IRQ chips.

After that, I've added the Tegra186 GPIO support patch that makes use of
the new tight integration.

To round things off the new banked GPIO infrastructure is added (along
with some more preparatory work), followed by the conversion of the two
Tegra GPIO drivers to the new infrastructure.

Changes in v2:
- rename pins to lines for consistent terminology
- rename gpio_irq_chip_banked_handler() to
  gpio_irq_chip_banked_chained_handler()

Thierry

Thierry Reding (16):
  gpio: Implement tighter IRQ chip integration
  gpio: Move irqchip into struct gpio_irq_chip
  gpio: Move irqdomain into struct gpio_irq_chip
  gpio: Move irq_base to struct gpio_irq_chip
  gpio: Move irq_handler to struct gpio_irq_chip
  gpio: Move irq_default_type to struct gpio_irq_chip
  gpio: Move irq_chained_parent to struct gpio_irq_chip
  gpio: Move irq_nested 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: Add Tegra186 support
  gpio: omap: Fix checkpatch warnings
  gpio: omap: Rename struct gpio_bank to struct omap_gpio_bank
  gpio: Add support for banked GPIO controllers
  gpio: tegra: Use banked GPIO infrastructure
  gpio: tegra186: Use banked GPIO infrastructure

 Documentation/gpio/driver.txt               |   6 +-
 drivers/bcma/driver_gpio.c                  |   2 +-
 drivers/gpio/Kconfig                        |  10 +
 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-ingenic.c                 |   2 +-
 drivers/gpio/gpio-intel-mid.c               |   2 +-
 drivers/gpio/gpio-lynxpoint.c               |   2 +-
 drivers/gpio/gpio-max732x.c                 |   2 +-
 drivers/gpio/gpio-merrifield.c              |   2 +-
 drivers/gpio/gpio-omap.c                    | 222 ++++++-----
 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-tegra.c                   | 203 +++++-----
 drivers/gpio/gpio-tegra186.c                | 571 ++++++++++++++++++++++++++++
 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-of.c                   | 101 +++++
 drivers/gpio/gpiolib.c                      | 320 ++++++++++++++--
 drivers/pinctrl/bcm/pinctrl-bcm2835.c       |   5 +-
 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/mvebu/pinctrl-armada-37xx.c |   4 +-
 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-mcp23s08.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 +-
 drivers/platform/x86/intel_int0002_vgpio.c  |   6 +-
 include/linux/gpio/driver.h                 | 272 +++++++++++--
 include/linux/of_gpio.h                     |  10 +
 63 files changed, 1505 insertions(+), 348 deletions(-)
 create mode 100644 drivers/gpio/gpio-tegra186.c

-- 
2.14.1

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

* [PATCH v2 01/16] gpio: Implement tighter IRQ chip integration
  2017-09-28  9:56 ` Thierry Reding
  (?)
@ 2017-09-28  9:56 ` Thierry Reding
       [not found]   ` <20170928095628.21966-2-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  -1 siblings, 1 reply; 56+ messages in thread
From: Thierry Reding @ 2017-09-28  9:56 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

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      | 146 +++++++++++++++++++++++++++++++++++++++++++-
 include/linux/gpio/driver.h |  64 +++++++++++++++++++
 2 files changed, 207 insertions(+), 3 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index eb80dac4e26a..b34d9cbd5809 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);
@@ -1260,6 +1261,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;
@@ -1626,8 +1631,8 @@ 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;
 
@@ -1655,8 +1660,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;
 
@@ -1665,6 +1671,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,
@@ -1705,6 +1712,124 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
 	return irq_create_mapping(chip->irqdomain, 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->irqchip;
+	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->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_base,
+						    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
@@ -1722,6 +1847,16 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 		irq_set_handler_data(gpiochip->irq_chained_parent, NULL);
 	}
 
+	if (gpiochip->irqchip) {
+		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++) {
@@ -1842,6 +1977,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 c97f8325e8bf..6100b171817e 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -19,6 +19,58 @@ struct module;
 
 #ifdef CONFIG_GPIOLIB
 
+#ifdef CONFIG_GPIOLIB_IRQCHIP
+/**
+ * struct gpio_irq_chip - GPIO interrupt controller
+ */
+struct gpio_irq_chip {
+	/**
+	 * @domain_ops:
+	 *
+	 * Table of interrupt domain operations for this IRQ chip.
+	 */
+	const struct irq_domain_ops *domain_ops;
+
+	/**
+	 * @parent_handler:
+	 *
+	 * The interrupt handler for the GPIO chip's parent interrupts, may be
+	 * NULL if the parent interrupts are nested rather than cascaded.
+	 */
+	irq_flow_handler_t parent_handler;
+
+	/**
+	 * @parent_handler_data:
+	 *
+	 * Data associated, and passed to, the handler for the parent
+	 * interrupt.
+	 */
+	void *parent_handler_data;
+
+	/**
+	 * @num_parents:
+	 *
+	 * The number of interrupt parents of a GPIO chip.
+	 */
+	unsigned int num_parents;
+
+	/**
+	 * @parents:
+	 *
+	 * A list of interrupt parents of a GPIO chip. This is owned by the
+	 * driver, so the core will only reference this list, not modify it.
+	 */
+	unsigned int *parents;
+
+	/**
+	 * @map:
+	 *
+	 * A list of interrupt parents for each line of a GPIO chip.
+	 */
+	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 +225,14 @@ struct gpio_chip {
 	bool			irq_need_valid_mask;
 	unsigned long		*irq_valid_mask;
 	struct lock_class_key	*lock_key;
+
+	/**
+	 * @irq:
+	 *
+	 * Integrates interrupt chip functionality with the GPIO chip. Can be
+	 * used to handle IRQs for most practical cases.
+	 */
+	struct gpio_irq_chip irq;
 #endif
 
 #if defined(CONFIG_OF_GPIO)
@@ -264,6 +324,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.14.1

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

* [PATCH v2 02/16] gpio: Move irqchip into struct gpio_irq_chip
  2017-09-28  9:56 ` Thierry Reding
@ 2017-09-28  9:56     ` Thierry Reding
  -1 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-09-28  9:56 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Jonathan Hunter, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-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      | 18 +++++++++---------
 include/linux/gpio/driver.h | 14 ++++++++++++--
 2 files changed, 21 insertions(+), 11 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index b34d9cbd5809..450007ac1fc0 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1645,7 +1645,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, chip->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);
@@ -1718,7 +1718,7 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
  */
 static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
 {
-	struct irq_chip *irqchip = gpiochip->irqchip;
+	struct irq_chip *irqchip = gpiochip->irq.chip;
 	const struct irq_domain_ops *ops;
 	struct device_node *np;
 	unsigned int type;
@@ -1847,7 +1847,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 		irq_set_handler_data(gpiochip->irq_chained_parent, NULL);
 	}
 
-	if (gpiochip->irqchip) {
+	if (gpiochip->irq.chip) {
 		struct gpio_irq_chip *irq = &gpiochip->irq;
 		unsigned int i;
 
@@ -1868,10 +1868,10 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 		irq_domain_remove(gpiochip->irqdomain);
 	}
 
-	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);
@@ -1946,7 +1946,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;
@@ -1955,7 +1955,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 					gpiochip->ngpio, first_irq,
 					&gpiochip_domain_ops, gpiochip);
 	if (!gpiochip->irqdomain) {
-		gpiochip->irqchip = NULL;
+		gpiochip->irq.chip = NULL;
 		return -EINVAL;
 	}
 
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 6100b171817e..974247646886 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -24,6 +24,13 @@ struct module;
  * struct gpio_irq_chip - GPIO interrupt controller
  */
 struct gpio_irq_chip {
+	/**
+	 * @chip:
+	 *
+	 * GPIO IRQ chip implementation, provided by GPIO driver.
+	 */
+	struct irq_chip *chip;
+
 	/**
 	 * @domain_ops:
 	 *
@@ -69,6 +76,11 @@ struct gpio_irq_chip {
 	 */
 	unsigned int *map;
 };
+
+static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
+{
+	return container_of(chip, struct gpio_irq_chip, chip);
+}
 #endif
 
 /**
@@ -132,7 +144,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
  * @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)
@@ -215,7 +226,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;
 	struct irq_domain	*irqdomain;
 	unsigned int		irq_base;
 	irq_flow_handler_t	irq_handler;
-- 
2.14.1

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

* [PATCH v2 02/16] gpio: Move irqchip into struct gpio_irq_chip
@ 2017-09-28  9:56     ` Thierry Reding
  0 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-09-28  9:56 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

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      | 18 +++++++++---------
 include/linux/gpio/driver.h | 14 ++++++++++++--
 2 files changed, 21 insertions(+), 11 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index b34d9cbd5809..450007ac1fc0 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1645,7 +1645,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, chip->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);
@@ -1718,7 +1718,7 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
  */
 static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
 {
-	struct irq_chip *irqchip = gpiochip->irqchip;
+	struct irq_chip *irqchip = gpiochip->irq.chip;
 	const struct irq_domain_ops *ops;
 	struct device_node *np;
 	unsigned int type;
@@ -1847,7 +1847,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 		irq_set_handler_data(gpiochip->irq_chained_parent, NULL);
 	}
 
-	if (gpiochip->irqchip) {
+	if (gpiochip->irq.chip) {
 		struct gpio_irq_chip *irq = &gpiochip->irq;
 		unsigned int i;
 
@@ -1868,10 +1868,10 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 		irq_domain_remove(gpiochip->irqdomain);
 	}
 
-	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);
@@ -1946,7 +1946,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;
@@ -1955,7 +1955,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 					gpiochip->ngpio, first_irq,
 					&gpiochip_domain_ops, gpiochip);
 	if (!gpiochip->irqdomain) {
-		gpiochip->irqchip = NULL;
+		gpiochip->irq.chip = NULL;
 		return -EINVAL;
 	}
 
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 6100b171817e..974247646886 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -24,6 +24,13 @@ struct module;
  * struct gpio_irq_chip - GPIO interrupt controller
  */
 struct gpio_irq_chip {
+	/**
+	 * @chip:
+	 *
+	 * GPIO IRQ chip implementation, provided by GPIO driver.
+	 */
+	struct irq_chip *chip;
+
 	/**
 	 * @domain_ops:
 	 *
@@ -69,6 +76,11 @@ struct gpio_irq_chip {
 	 */
 	unsigned int *map;
 };
+
+static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
+{
+	return container_of(chip, struct gpio_irq_chip, chip);
+}
 #endif
 
 /**
@@ -132,7 +144,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
  * @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)
@@ -215,7 +226,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;
 	struct irq_domain	*irqdomain;
 	unsigned int		irq_base;
 	irq_flow_handler_t	irq_handler;
-- 
2.14.1

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

* [PATCH v2 03/16] gpio: Move irqdomain into struct gpio_irq_chip
  2017-09-28  9:56 ` Thierry Reding
  (?)
  (?)
@ 2017-09-28  9:56 ` Thierry Reding
  -1 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-09-28  9:56 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

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               |  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-ingenic.c                 |  2 +-
 drivers/gpio/gpio-intel-mid.c               |  2 +-
 drivers/gpio/gpio-lynxpoint.c               |  2 +-
 drivers/gpio/gpio-max732x.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                      | 32 +++++++++++++++--------------
 drivers/pinctrl/bcm/pinctrl-bcm2835.c       |  5 +++--
 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/mvebu/pinctrl-armada-37xx.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-mcp23s08.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 +-
 drivers/platform/x86/intel_int0002_vgpio.c  |  2 +-
 include/linux/gpio/driver.h                 | 11 +++++++---
 57 files changed, 85 insertions(+), 77 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 982d5781d3ce..2c0ffb77d738 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 598e209efa2d..bab3b94c5cbc 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 51f046e29ff7..add859d59766 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 ec2ce34ff473..2f16638a0589 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 ccc02ed65b3c..8e76d390e653 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 bfc53995064a..a9342b471359 100644
--- a/drivers/gpio/gpio-aspeed.c
+++ b/drivers/gpio/gpio-aspeed.c
@@ -466,7 +466,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 27e92e57adae..db5c37a628f7 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 e60156ec0c18..b6f0f729656c 100644
--- a/drivers/gpio/gpio-crystalcove.c
+++ b/drivers/gpio/gpio-crystalcove.c
@@ -295,7 +295,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-ingenic.c b/drivers/gpio/gpio-ingenic.c
index 254780730b95..15fb2bc796a8 100644
--- a/drivers/gpio/gpio-ingenic.c
+++ b/drivers/gpio/gpio-ingenic.c
@@ -242,7 +242,7 @@ static void ingenic_gpio_irq_handler(struct irq_desc *desc)
 		flag = gpio_ingenic_read_reg(jzgc, JZ4740_GPIO_FLAG);
 
 	for_each_set_bit(i, &flag, 32)
-		generic_handle_irq(irq_linear_revmap(gc->irqdomain, i));
+		generic_handle_irq(irq_linear_revmap(gc->irq.domain, i));
 	chained_irq_exit(irq_chip, 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 7f4d26ce5f23..c04fae1ba32a 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-merrifield.c b/drivers/gpio/gpio-merrifield.c
index ec8560298805..dd67a31ac337 100644
--- a/drivers/gpio/gpio-merrifield.c
+++ b/drivers/gpio/gpio-merrifield.c
@@ -357,7 +357,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 22d7d4838265..9779eaf35504 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -733,7 +733,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 1b9dbf691ae7..babb7bd2ba59 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -608,7 +608,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 a4fd78b9c0e4..38fbb420c6cd 100644
--- a/drivers/gpio/gpio-pcf857x.c
+++ b/drivers/gpio/gpio-pcf857x.c
@@ -196,7 +196,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 6aaaab79c205..b70974cb9ef1 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 1f0871553fd2..5bd1339d5a48 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 cbe9e06861de..4610cc2938ad 100644
--- a/drivers/gpio/gpio-vf610.c
+++ b/drivers/gpio/gpio-vf610.c
@@ -160,7 +160,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 85341eab795d..dde7c6aecbb5 100644
--- a/drivers/gpio/gpio-wcove.c
+++ b/drivers/gpio/gpio-wcove.c
@@ -350,7 +350,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 5037974ac063..746648244bf3 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 ad8cb9c27eee..2313af82fad3 100644
--- a/drivers/gpio/gpio-xgene-sb.c
+++ b/drivers/gpio/gpio-xgene-sb.c
@@ -289,7 +289,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 b3cc948a2d8b..75ee877e5cd5 100644
--- a/drivers/gpio/gpio-zynq.c
+++ b/drivers/gpio/gpio-zynq.c
@@ -562,7 +562,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 450007ac1fc0..f4e18e0ffb56 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1549,7 +1549,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;
@@ -1576,7 +1576,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);
 	}
 }
@@ -1709,7 +1709,7 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
 {
 	if (!gpiochip_irqchip_irq_valid(chip, offset))
 		return -ENXIO;
-	return irq_create_mapping(chip->irqdomain, offset);
+	return irq_create_mapping(chip->irq.domain, offset);
 }
 
 /**
@@ -1769,10 +1769,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_base,
-						    ops, gpiochip);
-	if (!gpiochip->irqdomain)
+	gpiochip->irq.domain = irq_domain_add_simple(np, gpiochip->ngpio,
+						     gpiochip->irq_base,
+						     ops, gpiochip);
+	if (!gpiochip->irq.domain)
 		return -EINVAL;
 
 	/*
@@ -1814,7 +1814,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",
@@ -1838,7 +1838,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);
 
@@ -1858,14 +1858,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->irq.chip) {
@@ -1951,10 +1953,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->irq.chip = NULL;
 		return -EINVAL;
 	}
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
index ff782445dfb7..aec71d1a7478 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
@@ -379,7 +379,8 @@ static void bcm2835_gpio_irq_handle_bank(struct bcm2835_pinctrl *pc,
 	events &= pc->enabled_irq_map[bank];
 	for_each_set_bit(offset, &events, 32) {
 		gpio = (32 * bank) + offset;
-		generic_handle_irq(irq_linear_revmap(pc->gpio_chip.irqdomain,
+
+		generic_handle_irq(irq_linear_revmap(pc->gpio_chip.irq.domain,
 						     gpio));
 	}
 }
@@ -661,7 +662,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 85a8c97d9dfe..b93f62dc8733 100644
--- a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
+++ b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
@@ -172,7 +172,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 0f3a02495aeb..5897981e5ed3 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 8d50eaec9577..15166799528f 100644
--- a/drivers/pinctrl/intel/pinctrl-cherryview.c
+++ b/drivers/pinctrl/intel/pinctrl-cherryview.c
@@ -1523,7 +1523,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 71df0f70b61f..ffda27bfd133 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.c
+++ b/drivers/pinctrl/intel/pinctrl-intel.c
@@ -1005,7 +1005,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/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
index 71b944748304..c9851bd120b4 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
@@ -592,7 +592,7 @@ static void armada_37xx_irq_handler(struct irq_desc *desc)
 	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
 	struct irq_chip *chip = irq_desc_get_chip(desc);
 	struct armada_37xx_pinctrl *info = gpiochip_get_data(gc);
-	struct irq_domain *d = gc->irqdomain;
+	struct irq_domain *d = gc->irq.domain;
 	int i;
 
 	chained_irq_enter(chip, desc);
diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c
index a53f1a9b1ed2..f0e7a8c114b2 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 d10d280ab1c9..b9c0dd75319e 100644
--- a/drivers/pinctrl/pinctrl-amd.c
+++ b/drivers/pinctrl/pinctrl-amd.c
@@ -532,7 +532,7 @@ static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id)
 			regval = readl(regs + i);
 			if (!(regval & PIN_IRQ_PENDING))
 				continue;
-			irq = irq_find_mapping(gc->irqdomain, irqnr + i);
+			irq = irq_find_mapping(gc->irq.domain, irqnr + i);
 			generic_handle_irq(irq);
 			/* Clear interrupt */
 			writel(regval, regs + i);
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 ac155e7d3412..7939b178c6ae 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-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c
index 3e40d4245512..db19a2f2f575 100644
--- a/drivers/pinctrl/pinctrl-mcp23s08.c
+++ b/drivers/pinctrl/pinctrl-mcp23s08.c
@@ -537,7 +537,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/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 a5205b94b2e6..2081c67667a8 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 ff491da64dab..7a960590ecaa 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -795,7 +795,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 4db9323251e3..f5cef6e5fa3e 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 d3ef05973901..8b14a1f1e671 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/drivers/platform/x86/intel_int0002_vgpio.c b/drivers/platform/x86/intel_int0002_vgpio.c
index 92dc230ef5b2..f6b3af73dea5 100644
--- a/drivers/platform/x86/intel_int0002_vgpio.c
+++ b/drivers/platform/x86/intel_int0002_vgpio.c
@@ -119,7 +119,7 @@ static irqreturn_t int0002_irq(int irq, void *data)
 	if (!(gpe_sts_reg & GPE0A_PME_B0_STS_BIT))
 		return IRQ_NONE;
 
-	generic_handle_irq(irq_find_mapping(chip->irqdomain,
+	generic_handle_irq(irq_find_mapping(chip->irq.domain,
 					    GPE0A_PME_B0_VIRT_GPIO_PIN));
 
 	pm_system_wakeup();
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 974247646886..031037bb8670 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -31,6 +31,14 @@ struct gpio_irq_chip {
 	 */
 	struct irq_chip *chip;
 
+	/**
+	 * @domain:
+	 *
+	 * Interrupt translation domain; responsible for mapping between GPIO
+	 * hwirq number and Linux IRQ number.
+	 */
+	struct irq_domain *domain;
+
 	/**
 	 * @domain_ops:
 	 *
@@ -144,8 +152,6 @@ static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
  *	safely.
  * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
  *	direction safely.
- * @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
@@ -226,7 +232,6 @@ struct gpio_chip {
 	 * With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib
 	 * to handle IRQs for most practical cases.
 	 */
-	struct irq_domain	*irqdomain;
 	unsigned int		irq_base;
 	irq_flow_handler_t	irq_handler;
 	unsigned int		irq_default_type;
-- 
2.14.1

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

* [PATCH v2 04/16] gpio: Move irq_base to struct gpio_irq_chip
  2017-09-28  9:56 ` Thierry Reding
                   ` (2 preceding siblings ...)
  (?)
@ 2017-09-28  9:56 ` Thierry Reding
  -1 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-09-28  9:56 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

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                      |  2 +-
 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c |  2 +-
 include/linux/gpio/driver.h                 | 10 ++++++++--
 3 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index f4e18e0ffb56..2f0fa3d646d2 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1770,7 +1770,7 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
 		ops = &gpiochip_domain_ops;
 
 	gpiochip->irq.domain = irq_domain_add_simple(np, gpiochip->ngpio,
-						     gpiochip->irq_base,
+						     gpiochip->irq.first,
 						     ops, gpiochip);
 	if (!gpiochip->irq.domain)
 		return -EINVAL;
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
index c9851bd120b4..500238d898ea 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
@@ -627,7 +627,7 @@ static void armada_37xx_irq_handler(struct irq_desc *desc)
 static unsigned int armada_37xx_irq_startup(struct irq_data *d)
 {
 	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
-	int irq = d->hwirq - chip->irq_base;
+	int irq = d->hwirq - chip->irq.first;
 	/*
 	 * The mask field is a "precomputed bitmask for accessing the
 	 * chip registers" which was introduced for the generic
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 031037bb8670..9389406df0b1 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -46,6 +46,14 @@ struct gpio_irq_chip {
 	 */
 	const struct irq_domain_ops *domain_ops;
 
+	/**
+	 * @first:
+	 *
+	 * If not dynamically assigned, the base (first) IRQ to allocate GPIO
+	 * chip IRQs from (deprecated).
+	 */
+	unsigned int first;
+
 	/**
 	 * @parent_handler:
 	 *
@@ -152,7 +160,6 @@ static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *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)
  * @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
@@ -232,7 +239,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;
 	irq_flow_handler_t	irq_handler;
 	unsigned int		irq_default_type;
 	unsigned int		irq_chained_parent;
-- 
2.14.1

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

* [PATCH v2 05/16] gpio: Move irq_handler to struct gpio_irq_chip
  2017-09-28  9:56 ` Thierry Reding
                   ` (3 preceding siblings ...)
  (?)
@ 2017-09-28  9:56 ` Thierry Reding
  -1 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-09-28  9:56 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

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      |  4 ++--
 include/linux/gpio/driver.h | 11 ++++++++---
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 2f0fa3d646d2..dc44f2c97498 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1645,7 +1645,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, 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);
@@ -1949,7 +1949,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->lock_key = lock_key;
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 9389406df0b1..b1398ea0c32a 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -54,6 +54,14 @@ struct gpio_irq_chip {
 	 */
 	unsigned int first;
 
+	/**
+	 * @handler:
+	 *
+	 * The IRQ handler to use (often a predefined IRQ core function) for
+	 * GPIO IRQs, provided by GPIO driver.
+	 */
+	irq_flow_handler_t handler;
+
 	/**
 	 * @parent_handler:
 	 *
@@ -160,8 +168,6 @@ static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
  *	safely.
  * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
  *	direction safely.
- * @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
  * @irq_chained_parent: GPIO IRQ chip parent/bank linux irq number,
@@ -239,7 +245,6 @@ struct gpio_chip {
 	 * With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib
 	 * to handle IRQs for most practical cases.
 	 */
-	irq_flow_handler_t	irq_handler;
 	unsigned int		irq_default_type;
 	unsigned int		irq_chained_parent;
 	bool			irq_nested;
-- 
2.14.1


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

* [PATCH v2 06/16] gpio: Move irq_default_type to struct gpio_irq_chip
  2017-09-28  9:56 ` Thierry Reding
                   ` (4 preceding siblings ...)
  (?)
@ 2017-09-28  9:56 ` Thierry Reding
  -1 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-09-28  9:56 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

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      | 10 +++++-----
 include/linux/gpio/driver.h | 11 ++++++++---
 2 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index dc44f2c97498..bbad2eae30e2 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1655,8 +1655,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;
 }
@@ -1733,7 +1733,7 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
 		return -EINVAL;
 	}
 
-	type = gpiochip->irq_default_type;
+	type = gpiochip->irq.default_type;
 	np = gpiochip->parent->of_node;
 
 #ifdef CONFIG_OF_GPIO
@@ -1762,7 +1762,7 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
 	}
 
 	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;
@@ -1950,7 +1950,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->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 b1398ea0c32a..bcf93afddfa6 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -62,6 +62,14 @@ struct gpio_irq_chip {
 	 */
 	irq_flow_handler_t handler;
 
+	/**
+	 * @default_type:
+	 *
+	 * Default IRQ triggering type applied during GPIO driver
+	 * initialization, provided by GPIO driver.
+	 */
+	unsigned int default_type;
+
 	/**
 	 * @parent_handler:
 	 *
@@ -168,8 +176,6 @@ static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
  *	safely.
  * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
  *	direction safely.
- * @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).
@@ -245,7 +251,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_default_type;
 	unsigned int		irq_chained_parent;
 	bool			irq_nested;
 	bool			irq_need_valid_mask;
-- 
2.14.1

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

* [PATCH v2 07/16] gpio: Move irq_chained_parent to struct gpio_irq_chip
  2017-09-28  9:56 ` Thierry Reding
@ 2017-09-28  9:56     ` Thierry Reding
  -1 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-09-28  9:56 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Jonathan Hunter, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-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 bbad2eae30e2..7a62f4a63635 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1569,7 +1569,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 */
@@ -1842,11 +1843,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 bcf93afddfa6..c3eafd874884 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -176,9 +176,6 @@ static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
  *	safely.
  * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
  *	direction safely.
- * @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
@@ -251,7 +248,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_chained_parent;
 	bool			irq_nested;
 	bool			irq_need_valid_mask;
 	unsigned long		*irq_valid_mask;
-- 
2.14.1

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

* [PATCH v2 07/16] gpio: Move irq_chained_parent to struct gpio_irq_chip
@ 2017-09-28  9:56     ` Thierry Reding
  0 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-09-28  9:56 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

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      | 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 bbad2eae30e2..7a62f4a63635 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1569,7 +1569,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 */
@@ -1842,11 +1843,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 bcf93afddfa6..c3eafd874884 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -176,9 +176,6 @@ static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
  *	safely.
  * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
  *	direction safely.
- * @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
@@ -251,7 +248,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_chained_parent;
 	bool			irq_nested;
 	bool			irq_need_valid_mask;
 	unsigned long		*irq_valid_mask;
-- 
2.14.1

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

* [PATCH v2 08/16] gpio: Move irq_nested into struct gpio_irq_chip
  2017-09-28  9:56 ` Thierry Reding
                   ` (5 preceding siblings ...)
  (?)
@ 2017-09-28  9:56 ` Thierry Reding
  -1 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-09-28  9:56 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

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      | 12 ++++++------
 include/linux/gpio/driver.h |  9 +++++++--
 2 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 7a62f4a63635..eaca1ccd2431 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1613,7 +1613,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;
 	}
@@ -1648,7 +1648,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, chip->irq.chip, 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);
 
@@ -1667,7 +1667,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);
@@ -1800,9 +1800,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;
 	}
 
 	/*
@@ -1919,7 +1919,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 c3eafd874884..7d632a8932be 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -107,6 +107,13 @@ struct gpio_irq_chip {
 	 * A list of interrupt parents for each line of a GPIO chip.
 	 */
 	unsigned int *map;
+
+	/**
+	 * @nested:
+	 *
+	 * True if set the interrupt handling is nested.
+	 */
+	bool nested;
 };
 
 static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
@@ -176,7 +183,6 @@ static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
  *	safely.
  * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
  *	direction safely.
- * @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
@@ -248,7 +254,6 @@ struct gpio_chip {
 	 * With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib
 	 * to handle IRQs for most practical cases.
 	 */
-	bool			irq_nested;
 	bool			irq_need_valid_mask;
 	unsigned long		*irq_valid_mask;
 	struct lock_class_key	*lock_key;
-- 
2.14.1

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

* [PATCH v2 09/16] gpio: Move irq_valid_mask into struct gpio_irq_chip
  2017-09-28  9:56 ` Thierry Reding
@ 2017-09-28  9:56     ` Thierry Reding
  -1 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-09-28  9:56 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Jonathan Hunter, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-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              |  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 ++--
 drivers/platform/x86/intel_int0002_vgpio.c |  4 ++--
 include/linux/gpio/driver.h                | 21 +++++++++++++++------
 8 files changed, 35 insertions(+), 26 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 a9342b471359..fbd551a0c634 100644
--- a/drivers/gpio/gpio-aspeed.c
+++ b/drivers/gpio/gpio-aspeed.c
@@ -498,7 +498,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++;
@@ -853,7 +853,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
 	gpio->chip.set_config = aspeed_gpio_set_config;
 	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 eaca1ccd2431..4d140eb27d5b 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1503,33 +1503,33 @@ static struct gpio_chip *find_chip_by_name(const char *name)
 
 static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)
 {
-	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 */
-	bitmap_fill(gpiochip->irq_valid_mask, gpiochip->ngpio);
+	bitmap_fill(gpiochip->irq.valid_mask, gpiochip->ngpio);
 
 	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 5897981e5ed3..9c1ca29c60b7 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 15166799528f..d6bdf61eeed8 100644
--- a/drivers/pinctrl/intel/pinctrl-cherryview.c
+++ b/drivers/pinctrl/intel/pinctrl-cherryview.c
@@ -1584,7 +1584,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 = need_valid_mask;
+	chip->irq.need_valid_mask = need_valid_mask;
 
 	ret = devm_gpiochip_add_data(pctrl->dev, chip, pctrl);
 	if (ret) {
@@ -1616,7 +1616,7 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
 		intsel >>= CHV_PADCTRL0_INTSEL_SHIFT;
 
 		if (need_valid_mask && intsel >= pctrl->community->nirqs)
-			clear_bit(i, chip->irq_valid_mask);
+			clear_bit(i, chip->irq.valid_mask);
 	}
 
 	/* Clear all interrupts */
diff --git a/drivers/platform/x86/intel_int0002_vgpio.c b/drivers/platform/x86/intel_int0002_vgpio.c
index f6b3af73dea5..f7b67e898abc 100644
--- a/drivers/platform/x86/intel_int0002_vgpio.c
+++ b/drivers/platform/x86/intel_int0002_vgpio.c
@@ -165,7 +165,7 @@ static int int0002_probe(struct platform_device *pdev)
 	chip->direction_output = int0002_gpio_direction_output;
 	chip->base = -1;
 	chip->ngpio = GPE0A_PME_B0_VIRT_GPIO_PIN + 1;
-	chip->irq_need_valid_mask = true;
+	chip->irq.need_valid_mask = true;
 
 	ret = devm_gpiochip_add_data(&pdev->dev, chip, NULL);
 	if (ret) {
@@ -173,7 +173,7 @@ static int int0002_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	bitmap_clear(chip->irq_valid_mask, 0, GPE0A_PME_B0_VIRT_GPIO_PIN);
+	bitmap_clear(chip->irq.valid_mask, 0, GPE0A_PME_B0_VIRT_GPIO_PIN);
 
 	/*
 	 * We manually request the irq here instead of passing a flow-handler
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 7d632a8932be..f8d31e7da9cc 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -114,6 +114,21 @@ struct gpio_irq_chip {
 	 * True if set the interrupt handling is nested.
 	 */
 	bool nested;
+
+	/**
+	 * @need_valid_mask:
+	 *
+	 * If set core allocates @valid_mask with all bits set to one.
+	 */
+	bool need_valid_mask;
+
+	/**
+	 * @valid_mask:
+	 *
+	 * If not %NULL holds bitmask of GPIOs which are valid to be included
+	 * in IRQ domain of the chip.
+	 */
+	unsigned long *valid_mask;
 };
 
 static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
@@ -183,10 +198,6 @@ static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
  *	safely.
  * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
  *	direction safely.
- * @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
@@ -254,8 +265,6 @@ struct gpio_chip {
 	 * With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib
 	 * to handle IRQs for most practical cases.
 	 */
-	bool			irq_need_valid_mask;
-	unsigned long		*irq_valid_mask;
 	struct lock_class_key	*lock_key;
 
 	/**
-- 
2.14.1

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

* [PATCH v2 09/16] gpio: Move irq_valid_mask into struct gpio_irq_chip
@ 2017-09-28  9:56     ` Thierry Reding
  0 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-09-28  9:56 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

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 ++--
 drivers/platform/x86/intel_int0002_vgpio.c |  4 ++--
 include/linux/gpio/driver.h                | 21 +++++++++++++++------
 8 files changed, 35 insertions(+), 26 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 a9342b471359..fbd551a0c634 100644
--- a/drivers/gpio/gpio-aspeed.c
+++ b/drivers/gpio/gpio-aspeed.c
@@ -498,7 +498,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++;
@@ -853,7 +853,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
 	gpio->chip.set_config = aspeed_gpio_set_config;
 	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 eaca1ccd2431..4d140eb27d5b 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1503,33 +1503,33 @@ static struct gpio_chip *find_chip_by_name(const char *name)
 
 static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)
 {
-	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 */
-	bitmap_fill(gpiochip->irq_valid_mask, gpiochip->ngpio);
+	bitmap_fill(gpiochip->irq.valid_mask, gpiochip->ngpio);
 
 	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 5897981e5ed3..9c1ca29c60b7 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 15166799528f..d6bdf61eeed8 100644
--- a/drivers/pinctrl/intel/pinctrl-cherryview.c
+++ b/drivers/pinctrl/intel/pinctrl-cherryview.c
@@ -1584,7 +1584,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 = need_valid_mask;
+	chip->irq.need_valid_mask = need_valid_mask;
 
 	ret = devm_gpiochip_add_data(pctrl->dev, chip, pctrl);
 	if (ret) {
@@ -1616,7 +1616,7 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
 		intsel >>= CHV_PADCTRL0_INTSEL_SHIFT;
 
 		if (need_valid_mask && intsel >= pctrl->community->nirqs)
-			clear_bit(i, chip->irq_valid_mask);
+			clear_bit(i, chip->irq.valid_mask);
 	}
 
 	/* Clear all interrupts */
diff --git a/drivers/platform/x86/intel_int0002_vgpio.c b/drivers/platform/x86/intel_int0002_vgpio.c
index f6b3af73dea5..f7b67e898abc 100644
--- a/drivers/platform/x86/intel_int0002_vgpio.c
+++ b/drivers/platform/x86/intel_int0002_vgpio.c
@@ -165,7 +165,7 @@ static int int0002_probe(struct platform_device *pdev)
 	chip->direction_output = int0002_gpio_direction_output;
 	chip->base = -1;
 	chip->ngpio = GPE0A_PME_B0_VIRT_GPIO_PIN + 1;
-	chip->irq_need_valid_mask = true;
+	chip->irq.need_valid_mask = true;
 
 	ret = devm_gpiochip_add_data(&pdev->dev, chip, NULL);
 	if (ret) {
@@ -173,7 +173,7 @@ static int int0002_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	bitmap_clear(chip->irq_valid_mask, 0, GPE0A_PME_B0_VIRT_GPIO_PIN);
+	bitmap_clear(chip->irq.valid_mask, 0, GPE0A_PME_B0_VIRT_GPIO_PIN);
 
 	/*
 	 * We manually request the irq here instead of passing a flow-handler
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 7d632a8932be..f8d31e7da9cc 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -114,6 +114,21 @@ struct gpio_irq_chip {
 	 * True if set the interrupt handling is nested.
 	 */
 	bool nested;
+
+	/**
+	 * @need_valid_mask:
+	 *
+	 * If set core allocates @valid_mask with all bits set to one.
+	 */
+	bool need_valid_mask;
+
+	/**
+	 * @valid_mask:
+	 *
+	 * If not %NULL holds bitmask of GPIOs which are valid to be included
+	 * in IRQ domain of the chip.
+	 */
+	unsigned long *valid_mask;
 };
 
 static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
@@ -183,10 +198,6 @@ static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
  *	safely.
  * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
  *	direction safely.
- * @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
@@ -254,8 +265,6 @@ struct gpio_chip {
 	 * With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib
 	 * to handle IRQs for most practical cases.
 	 */
-	bool			irq_need_valid_mask;
-	unsigned long		*irq_valid_mask;
 	struct lock_class_key	*lock_key;
 
 	/**
-- 
2.14.1

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

* [PATCH v2 10/16] gpio: Move lock_key into struct gpio_irq_chip
  2017-09-28  9:56 ` Thierry Reding
                   ` (6 preceding siblings ...)
  (?)
@ 2017-09-28  9:56 ` Thierry Reding
  -1 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-09-28  9:56 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

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      | 4 ++--
 include/linux/gpio/driver.h | 9 +++++++--
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 4d140eb27d5b..c15fb858848a 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1645,7 +1645,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)
@@ -1948,7 +1948,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 f8d31e7da9cc..c453e0716228 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -70,6 +70,13 @@ struct gpio_irq_chip {
 	 */
 	unsigned int default_type;
 
+	/**
+	 * @lock_key:
+	 *
+	 * Per GPIO IRQ chip lockdep class.
+	 */
+	struct lock_class_key *lock_key;
+
 	/**
 	 * @parent_handler:
 	 *
@@ -198,7 +205,6 @@ static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
  *	safely.
  * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
  *	direction safely.
- * @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.
@@ -265,7 +271,6 @@ struct gpio_chip {
 	 * With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib
 	 * to handle IRQs for most practical cases.
 	 */
-	struct lock_class_key	*lock_key;
 
 	/**
 	 * @irq:
-- 
2.14.1

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

* [PATCH v2 11/16] gpio: Add Tegra186 support
  2017-09-28  9:56 ` Thierry Reding
                   ` (7 preceding siblings ...)
  (?)
@ 2017-09-28  9:56 ` Thierry Reding
  -1 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-09-28  9:56 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

From: Thierry Reding <treding@nvidia.com>

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@nvidia.com>
---
Changes in v4:
- use platform_irq_count() instead of of_irq_count()

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 | 624 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 634 insertions(+)
 create mode 100644 drivers/gpio/gpio-tegra186.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 796b11c489ae..db3e446ad9b3 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -442,6 +442,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 aeb70e9de6f2..4cb7c9b93215 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -113,6 +113,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_THUNDERX)	+= gpio-thunderx.o
 obj-$(CONFIG_GPIO_TIMBERDALE)	+= gpio-timberdale.o
 obj-$(CONFIG_GPIO_PALMAS)	+= gpio-palmas.o
diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c
new file mode 100644
index 000000000000..162dc6b41ae8
--- /dev/null
+++ b/drivers/gpio/gpio-tegra186.c
@@ -0,0 +1,624 @@
+/*
+ * Copyright (c) 2016-2017 NVIDIA Corporation
+ *
+ * Author: Thierry Reding <treding@nvidia.com>
+ *
+ * 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/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 = platform_irq_count(pdev);
+	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@nvidia.com>");
+MODULE_LICENSE("GPL v2");
-- 
2.14.1

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

* [PATCH v2 12/16] gpio: omap: Fix checkpatch warnings
  2017-09-28  9:56 ` Thierry Reding
                   ` (8 preceding siblings ...)
  (?)
@ 2017-09-28  9:56 ` Thierry Reding
  -1 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-09-28  9:56 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

From: Thierry Reding <treding@nvidia.com>

Use unsigned int rather than unsigned, wrap lines longer than 80
characters and other minor coding style cleanups.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/gpio/gpio-omap.c | 113 ++++++++++++++++++++++++++---------------------
 1 file changed, 63 insertions(+), 50 deletions(-)

diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 9779eaf35504..81a70a1edaf5 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -76,7 +76,8 @@ struct gpio_bank {
 	int power_mode;
 	bool workaround_enabled;
 
-	void (*set_dataout)(struct gpio_bank *bank, unsigned gpio, int enable);
+	void (*set_dataout)(struct gpio_bank *bank, unsigned int gpio,
+			    int enable);
 	int (*get_context_loss_count)(struct device *dev);
 
 	struct omap_gpio_reg_offs *regs;
@@ -92,6 +93,7 @@ static void omap_gpio_unmask_irq(struct irq_data *d);
 static inline struct gpio_bank *omap_irq_data_get_bank(struct irq_data *d)
 {
 	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+
 	return gpiochip_get_data(chip);
 }
 
@@ -113,8 +115,8 @@ static void omap_set_gpio_direction(struct gpio_bank *bank, int gpio,
 
 
 /* set data out value using dedicate set/clear register */
-static void omap_set_gpio_dataout_reg(struct gpio_bank *bank, unsigned offset,
-				      int enable)
+static void omap_set_gpio_dataout_reg(struct gpio_bank *bank,
+				      unsigned int offset, int enable)
 {
 	void __iomem *reg = bank->base;
 	u32 l = BIT(offset);
@@ -131,8 +133,8 @@ static void omap_set_gpio_dataout_reg(struct gpio_bank *bank, unsigned offset,
 }
 
 /* set data out value using mask register */
-static void omap_set_gpio_dataout_mask(struct gpio_bank *bank, unsigned offset,
-				       int enable)
+static void omap_set_gpio_dataout_mask(struct gpio_bank *bank,
+				       unsigned int offset, int enable)
 {
 	void __iomem *reg = bank->base + bank->regs->dataout;
 	u32 gpio_bit = BIT(offset);
@@ -161,7 +163,8 @@ static int omap_get_gpio_dataout(struct gpio_bank *bank, int offset)
 	return (readl_relaxed(reg) & (BIT(offset))) != 0;
 }
 
-static inline void omap_gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set)
+static inline void omap_gpio_rmw(void __iomem *base, u32 reg, u32 mask,
+				 bool set)
 {
 	int l = readl_relaxed(base + reg);
 
@@ -211,8 +214,8 @@ static inline void omap_gpio_dbck_disable(struct gpio_bank *bank)
  *
  * Return: 0 on success, negative error otherwise.
  */
-static int omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset,
-				   unsigned debounce)
+static int omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned int offset,
+				   unsigned int debounce)
 {
 	void __iomem		*reg;
 	u32			val;
@@ -272,7 +275,8 @@ static int omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset,
  * time too. The debounce clock will also be disabled when calling this function
  * if this is the only gpio in the bank using debounce.
  */
-static void omap_clear_gpio_debounce(struct gpio_bank *bank, unsigned offset)
+static void omap_clear_gpio_debounce(struct gpio_bank *bank,
+				     unsigned int offset)
 {
 	u32 gpio_bit = BIT(offset);
 
@@ -284,8 +288,8 @@ static void omap_clear_gpio_debounce(struct gpio_bank *bank, unsigned offset)
 
 	bank->dbck_enable_mask &= ~gpio_bit;
 	bank->context.debounce_en &= ~gpio_bit;
-        writel_relaxed(bank->context.debounce_en,
-		     bank->base + bank->regs->debounce_en);
+	writel_relaxed(bank->context.debounce_en,
+		       bank->base + bank->regs->debounce_en);
 
 	if (!bank->dbck_enable_mask) {
 		bank->context.debounce = 0;
@@ -297,7 +301,7 @@ static void omap_clear_gpio_debounce(struct gpio_bank *bank, unsigned offset)
 }
 
 static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
-						unsigned trigger)
+					 unsigned int trigger)
 {
 	void __iomem *base = bank->base;
 	u32 gpio_bit = BIT(gpio);
@@ -321,7 +325,8 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
 			readl_relaxed(bank->base + bank->regs->fallingdetect);
 
 	if (likely(!(bank->non_wakeup_gpios & gpio_bit))) {
-		omap_gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0);
+		omap_gpio_rmw(base, bank->regs->wkup_en, gpio_bit,
+			      trigger != 0);
 		bank->context.wake_en =
 			readl_relaxed(bank->base + bank->regs->wkup_en);
 	}
@@ -376,11 +381,13 @@ static void omap_toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)
 	writel_relaxed(l, reg);
 }
 #else
-static void omap_toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) {}
+static void omap_toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)
+{
+}
 #endif
 
 static int omap_set_gpio_triggering(struct gpio_bank *bank, int gpio,
-				    unsigned trigger)
+				    unsigned int trigger)
 {
 	void __iomem *reg = bank->base;
 	void __iomem *base = bank->base;
@@ -425,7 +432,7 @@ static int omap_set_gpio_triggering(struct gpio_bank *bank, int gpio,
 	return 0;
 }
 
-static void omap_enable_gpio_module(struct gpio_bank *bank, unsigned offset)
+static void omap_enable_gpio_module(struct gpio_bank *bank, unsigned int offset)
 {
 	if (bank->regs->pinctrl) {
 		void __iomem *reg = bank->base + bank->regs->pinctrl;
@@ -446,7 +453,8 @@ static void omap_enable_gpio_module(struct gpio_bank *bank, unsigned offset)
 	}
 }
 
-static void omap_disable_gpio_module(struct gpio_bank *bank, unsigned offset)
+static void omap_disable_gpio_module(struct gpio_bank *bank,
+				     unsigned int offset)
 {
 	void __iomem *base = bank->base;
 
@@ -471,14 +479,14 @@ static void omap_disable_gpio_module(struct gpio_bank *bank, unsigned offset)
 	}
 }
 
-static int omap_gpio_is_input(struct gpio_bank *bank, unsigned offset)
+static int omap_gpio_is_input(struct gpio_bank *bank, unsigned int offset)
 {
 	void __iomem *reg = bank->base + bank->regs->direction;
 
 	return readl_relaxed(reg) & BIT(offset);
 }
 
-static void omap_gpio_init_irq(struct gpio_bank *bank, unsigned offset)
+static void omap_gpio_init_irq(struct gpio_bank *bank, unsigned int offset)
 {
 	if (!LINE_USED(bank->mod_usage, offset)) {
 		omap_enable_gpio_module(bank, offset);
@@ -487,12 +495,12 @@ static void omap_gpio_init_irq(struct gpio_bank *bank, unsigned offset)
 	bank->irq_usage |= BIT(offset);
 }
 
-static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
+static int omap_gpio_irq_type(struct irq_data *d, unsigned int type)
 {
 	struct gpio_bank *bank = omap_irq_data_get_bank(d);
 	int retval;
 	unsigned long flags;
-	unsigned offset = d->hwirq;
+	unsigned int offset = d->hwirq;
 
 	if (type & ~IRQ_TYPE_SENSE_MASK)
 		return -EINVAL;
@@ -544,7 +552,7 @@ static void omap_clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
 }
 
 static inline void omap_clear_gpio_irqstatus(struct gpio_bank *bank,
-					     unsigned offset)
+					     unsigned int offset)
 {
 	omap_clear_gpio_irqbank(bank, BIT(offset));
 }
@@ -608,7 +616,7 @@ static void omap_disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
 }
 
 static inline void omap_set_gpio_irqenable(struct gpio_bank *bank,
-					   unsigned offset, int enable)
+					   unsigned int offset, int enable)
 {
 	if (enable)
 		omap_enable_gpio_irqbank(bank, BIT(offset));
@@ -624,7 +632,7 @@ static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable)
 	return irq_set_irq_wake(bank->irq, enable);
 }
 
-static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
+static int omap_gpio_request(struct gpio_chip *chip, unsigned int offset)
 {
 	struct gpio_bank *bank = gpiochip_get_data(chip);
 	unsigned long flags;
@@ -644,7 +652,7 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
 	return 0;
 }
 
-static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
+static void omap_gpio_free(struct gpio_chip *chip, unsigned int offset)
 {
 	struct gpio_bank *bank = gpiochip_get_data(chip);
 	unsigned long flags;
@@ -702,9 +710,11 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
 		if (bank->level_mask)
 			level_mask = bank->level_mask & enabled;
 
-		/* clear edge sensitive interrupts before handler(s) are
-		called so that we don't miss any interrupt occurred while
-		executing them */
+		/*
+		 * clear edge sensitive interrupts before handler(s) are
+		 * called so that we don't miss any interrupt occurred while
+		 * executing them
+		 */
 		omap_disable_gpio_irqbank(bank, isr_saved & ~level_mask);
 		omap_clear_gpio_irqbank(bank, isr_saved & ~level_mask);
 		omap_enable_gpio_irqbank(bank, isr_saved & ~level_mask);
@@ -715,6 +725,8 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
 			break;
 
 		while (isr) {
+			unsigned int irq;
+
 			bit = __ffs(isr);
 			isr &= ~(BIT(bit));
 
@@ -733,8 +745,8 @@ 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.irq.domain,
-							    bit));
+			irq = irq_find_mapping(bank->chip.irq.domain, bit);
+			generic_handle_irq(irq);
 
 			raw_spin_unlock_irqrestore(&bank->wa_lock,
 						   wa_lock_flags);
@@ -749,7 +761,7 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d)
 {
 	struct gpio_bank *bank = omap_irq_data_get_bank(d);
 	unsigned long flags;
-	unsigned offset = d->hwirq;
+	unsigned int offset = d->hwirq;
 
 	raw_spin_lock_irqsave(&bank->lock, flags);
 
@@ -773,7 +785,7 @@ static void omap_gpio_irq_shutdown(struct irq_data *d)
 {
 	struct gpio_bank *bank = omap_irq_data_get_bank(d);
 	unsigned long flags;
-	unsigned offset = d->hwirq;
+	unsigned int offset = d->hwirq;
 
 	raw_spin_lock_irqsave(&bank->lock, flags);
 	bank->irq_usage &= ~(BIT(offset));
@@ -809,7 +821,7 @@ static void gpio_irq_bus_sync_unlock(struct irq_data *data)
 static void omap_gpio_ack_irq(struct irq_data *d)
 {
 	struct gpio_bank *bank = omap_irq_data_get_bank(d);
-	unsigned offset = d->hwirq;
+	unsigned int offset = d->hwirq;
 
 	omap_clear_gpio_irqstatus(bank, offset);
 }
@@ -817,7 +829,7 @@ static void omap_gpio_ack_irq(struct irq_data *d)
 static void omap_gpio_mask_irq(struct irq_data *d)
 {
 	struct gpio_bank *bank = omap_irq_data_get_bank(d);
-	unsigned offset = d->hwirq;
+	unsigned int offset = d->hwirq;
 	unsigned long flags;
 
 	raw_spin_lock_irqsave(&bank->lock, flags);
@@ -829,7 +841,7 @@ static void omap_gpio_mask_irq(struct irq_data *d)
 static void omap_gpio_unmask_irq(struct irq_data *d)
 {
 	struct gpio_bank *bank = omap_irq_data_get_bank(d);
-	unsigned offset = d->hwirq;
+	unsigned int offset = d->hwirq;
 	u32 trigger = irqd_get_trigger_type(d);
 	unsigned long flags;
 
@@ -837,8 +849,10 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
 	if (trigger)
 		omap_set_gpio_triggering(bank, offset, trigger);
 
-	/* For level-triggered GPIOs, the clearing must be done after
-	 * the HW source is cleared, thus after the handler has run */
+	/*
+	 * For level-triggered GPIOs, the clearing must be done after
+	 * the HW source is cleared, thus after the handler has run
+	 */
 	if (bank->level_mask & BIT(offset)) {
 		omap_set_gpio_irqenable(bank, offset, 0);
 		omap_clear_gpio_irqstatus(bank, offset);
@@ -912,7 +926,7 @@ static inline void omap_mpuio_init(struct gpio_bank *bank)
 
 /*---------------------------------------------------------------------*/
 
-static int omap_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+static int omap_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
 {
 	struct gpio_bank *bank;
 	unsigned long flags;
@@ -927,7 +941,7 @@ static int omap_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
 	return dir;
 }
 
-static int omap_gpio_input(struct gpio_chip *chip, unsigned offset)
+static int omap_gpio_input(struct gpio_chip *chip, unsigned int offset)
 {
 	struct gpio_bank *bank;
 	unsigned long flags;
@@ -939,7 +953,7 @@ static int omap_gpio_input(struct gpio_chip *chip, unsigned offset)
 	return 0;
 }
 
-static int omap_gpio_get(struct gpio_chip *chip, unsigned offset)
+static int omap_gpio_get(struct gpio_chip *chip, unsigned int offset)
 {
 	struct gpio_bank *bank;
 
@@ -951,7 +965,8 @@ static int omap_gpio_get(struct gpio_chip *chip, unsigned offset)
 		return omap_get_gpio_dataout(bank, offset);
 }
 
-static int omap_gpio_output(struct gpio_chip *chip, unsigned offset, int value)
+static int omap_gpio_output(struct gpio_chip *chip, unsigned int offset,
+			    int value)
 {
 	struct gpio_bank *bank;
 	unsigned long flags;
@@ -964,8 +979,8 @@ static int omap_gpio_output(struct gpio_chip *chip, unsigned offset, int value)
 	return 0;
 }
 
-static int omap_gpio_debounce(struct gpio_chip *chip, unsigned offset,
-			      unsigned debounce)
+static int omap_gpio_debounce(struct gpio_chip *chip, unsigned int offset,
+			      unsigned int debounce)
 {
 	struct gpio_bank *bank;
 	unsigned long flags;
@@ -985,7 +1000,7 @@ static int omap_gpio_debounce(struct gpio_chip *chip, unsigned offset,
 	return ret;
 }
 
-static int omap_gpio_set_config(struct gpio_chip *chip, unsigned offset,
+static int omap_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
 				unsigned long config)
 {
 	u32 debounce;
@@ -997,7 +1012,8 @@ static int omap_gpio_set_config(struct gpio_chip *chip, unsigned offset,
 	return omap_gpio_debounce(chip, offset, debounce);
 }
 
-static void omap_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+static void omap_gpio_set(struct gpio_chip *chip, unsigned int offset,
+			  int value)
 {
 	struct gpio_bank *bank;
 	unsigned long flags;
@@ -1153,10 +1169,8 @@ static int omap_gpio_probe(struct platform_device *pdev)
 		return -EINVAL;
 
 	bank = devm_kzalloc(dev, sizeof(struct gpio_bank), GFP_KERNEL);
-	if (!bank) {
-		dev_err(dev, "Memory alloc failed\n");
+	if (!bank)
 		return -ENOMEM;
-	}
 
 	irqc = devm_kzalloc(dev, sizeof(*irqc), GFP_KERNEL);
 	if (!irqc)
@@ -1217,9 +1231,8 @@ static int omap_gpio_probe(struct platform_device *pdev)
 	/* Static mapping, never released */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	bank->base = devm_ioremap_resource(dev, res);
-	if (IS_ERR(bank->base)) {
+	if (IS_ERR(bank->base))
 		return PTR_ERR(bank->base);
-	}
 
 	if (bank->dbck_flag) {
 		bank->dbck = devm_clk_get(dev, "dbclk");
-- 
2.14.1

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

* [PATCH v2 13/16] gpio: omap: Rename struct gpio_bank to struct omap_gpio_bank
  2017-09-28  9:56 ` Thierry Reding
                   ` (9 preceding siblings ...)
  (?)
@ 2017-09-28  9:56 ` Thierry Reding
  -1 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-09-28  9:56 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

From: Thierry Reding <treding@nvidia.com>

Subsequent patches will want to introduce a struct gpio_bank in core
code, so rename this to something driver-specific in order to avoid the
names from clashing.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/gpio/gpio-omap.c | 131 ++++++++++++++++++++++++-----------------------
 1 file changed, 68 insertions(+), 63 deletions(-)

diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 81a70a1edaf5..feccfbf5866b 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -48,7 +48,7 @@ struct gpio_regs {
 	u32 debounce_en;
 };
 
-struct gpio_bank {
+struct omap_gpio_bank {
 	struct list_head node;
 	void __iomem *base;
 	int irq;
@@ -76,7 +76,7 @@ struct gpio_bank {
 	int power_mode;
 	bool workaround_enabled;
 
-	void (*set_dataout)(struct gpio_bank *bank, unsigned int gpio,
+	void (*set_dataout)(struct omap_gpio_bank *bank, unsigned int gpio,
 			    int enable);
 	int (*get_context_loss_count)(struct device *dev);
 
@@ -90,14 +90,14 @@ struct gpio_bank {
 
 static void omap_gpio_unmask_irq(struct irq_data *d);
 
-static inline struct gpio_bank *omap_irq_data_get_bank(struct irq_data *d)
+static inline struct omap_gpio_bank *omap_irq_data_get_bank(struct irq_data *d)
 {
 	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
 
 	return gpiochip_get_data(chip);
 }
 
-static void omap_set_gpio_direction(struct gpio_bank *bank, int gpio,
+static void omap_set_gpio_direction(struct omap_gpio_bank *bank, int gpio,
 				    int is_input)
 {
 	void __iomem *reg = bank->base;
@@ -115,7 +115,7 @@ static void omap_set_gpio_direction(struct gpio_bank *bank, int gpio,
 
 
 /* set data out value using dedicate set/clear register */
-static void omap_set_gpio_dataout_reg(struct gpio_bank *bank,
+static void omap_set_gpio_dataout_reg(struct omap_gpio_bank *bank,
 				      unsigned int offset, int enable)
 {
 	void __iomem *reg = bank->base;
@@ -133,7 +133,7 @@ static void omap_set_gpio_dataout_reg(struct gpio_bank *bank,
 }
 
 /* set data out value using mask register */
-static void omap_set_gpio_dataout_mask(struct gpio_bank *bank,
+static void omap_set_gpio_dataout_mask(struct omap_gpio_bank *bank,
 				       unsigned int offset, int enable)
 {
 	void __iomem *reg = bank->base + bank->regs->dataout;
@@ -149,14 +149,14 @@ static void omap_set_gpio_dataout_mask(struct gpio_bank *bank,
 	bank->context.dataout = l;
 }
 
-static int omap_get_gpio_datain(struct gpio_bank *bank, int offset)
+static int omap_get_gpio_datain(struct omap_gpio_bank *bank, int offset)
 {
 	void __iomem *reg = bank->base + bank->regs->datain;
 
 	return (readl_relaxed(reg) & (BIT(offset))) != 0;
 }
 
-static int omap_get_gpio_dataout(struct gpio_bank *bank, int offset)
+static int omap_get_gpio_dataout(struct omap_gpio_bank *bank, int offset)
 {
 	void __iomem *reg = bank->base + bank->regs->dataout;
 
@@ -176,7 +176,7 @@ static inline void omap_gpio_rmw(void __iomem *base, u32 reg, u32 mask,
 	writel_relaxed(l, base + reg);
 }
 
-static inline void omap_gpio_dbck_enable(struct gpio_bank *bank)
+static inline void omap_gpio_dbck_enable(struct omap_gpio_bank *bank)
 {
 	if (bank->dbck_enable_mask && !bank->dbck_enabled) {
 		clk_enable(bank->dbck);
@@ -187,7 +187,7 @@ static inline void omap_gpio_dbck_enable(struct gpio_bank *bank)
 	}
 }
 
-static inline void omap_gpio_dbck_disable(struct gpio_bank *bank)
+static inline void omap_gpio_dbck_disable(struct omap_gpio_bank *bank)
 {
 	if (bank->dbck_enable_mask && bank->dbck_enabled) {
 		/*
@@ -214,8 +214,8 @@ static inline void omap_gpio_dbck_disable(struct gpio_bank *bank)
  *
  * Return: 0 on success, negative error otherwise.
  */
-static int omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned int offset,
-				   unsigned int debounce)
+static int omap2_set_gpio_debounce(struct omap_gpio_bank *bank,
+				   unsigned int offset, unsigned int debounce)
 {
 	void __iomem		*reg;
 	u32			val;
@@ -275,7 +275,7 @@ static int omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned int offset,
  * time too. The debounce clock will also be disabled when calling this function
  * if this is the only gpio in the bank using debounce.
  */
-static void omap_clear_gpio_debounce(struct gpio_bank *bank,
+static void omap_clear_gpio_debounce(struct omap_gpio_bank *bank,
 				     unsigned int offset)
 {
 	u32 gpio_bit = BIT(offset);
@@ -300,7 +300,7 @@ static void omap_clear_gpio_debounce(struct gpio_bank *bank,
 	}
 }
 
-static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
+static inline void omap_set_gpio_trigger(struct omap_gpio_bank *bank, int gpio,
 					 unsigned int trigger)
 {
 	void __iomem *base = bank->base;
@@ -362,7 +362,8 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
  * This only applies to chips that can't do both rising and falling edge
  * detection at once.  For all other chips, this function is a noop.
  */
-static void omap_toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)
+static void omap_toggle_gpio_edge_triggering(struct omap_gpio_bank *bank,
+					     int gpio)
 {
 	void __iomem *reg = bank->base;
 	u32 l = 0;
@@ -381,12 +382,13 @@ static void omap_toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)
 	writel_relaxed(l, reg);
 }
 #else
-static void omap_toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)
+static void omap_toggle_gpio_edge_triggering(struct omap_gpio_bank *bank,
+					     int gpio)
 {
 }
 #endif
 
-static int omap_set_gpio_triggering(struct gpio_bank *bank, int gpio,
+static int omap_set_gpio_triggering(struct omap_gpio_bank *bank, int gpio,
 				    unsigned int trigger)
 {
 	void __iomem *reg = bank->base;
@@ -432,7 +434,8 @@ static int omap_set_gpio_triggering(struct gpio_bank *bank, int gpio,
 	return 0;
 }
 
-static void omap_enable_gpio_module(struct gpio_bank *bank, unsigned int offset)
+static void omap_enable_gpio_module(struct omap_gpio_bank *bank,
+				    unsigned int offset)
 {
 	if (bank->regs->pinctrl) {
 		void __iomem *reg = bank->base + bank->regs->pinctrl;
@@ -453,7 +456,7 @@ static void omap_enable_gpio_module(struct gpio_bank *bank, unsigned int offset)
 	}
 }
 
-static void omap_disable_gpio_module(struct gpio_bank *bank,
+static void omap_disable_gpio_module(struct omap_gpio_bank *bank,
 				     unsigned int offset)
 {
 	void __iomem *base = bank->base;
@@ -479,14 +482,14 @@ static void omap_disable_gpio_module(struct gpio_bank *bank,
 	}
 }
 
-static int omap_gpio_is_input(struct gpio_bank *bank, unsigned int offset)
+static int omap_gpio_is_input(struct omap_gpio_bank *bank, unsigned int offset)
 {
 	void __iomem *reg = bank->base + bank->regs->direction;
 
 	return readl_relaxed(reg) & BIT(offset);
 }
 
-static void omap_gpio_init_irq(struct gpio_bank *bank, unsigned int offset)
+static void omap_gpio_init_irq(struct omap_gpio_bank *bank, unsigned int offset)
 {
 	if (!LINE_USED(bank->mod_usage, offset)) {
 		omap_enable_gpio_module(bank, offset);
@@ -497,7 +500,7 @@ static void omap_gpio_init_irq(struct gpio_bank *bank, unsigned int offset)
 
 static int omap_gpio_irq_type(struct irq_data *d, unsigned int type)
 {
-	struct gpio_bank *bank = omap_irq_data_get_bank(d);
+	struct omap_gpio_bank *bank = omap_irq_data_get_bank(d);
 	int retval;
 	unsigned long flags;
 	unsigned int offset = d->hwirq;
@@ -534,7 +537,7 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned int type)
 	return retval;
 }
 
-static void omap_clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
+static void omap_clear_gpio_irqbank(struct omap_gpio_bank *bank, int gpio_mask)
 {
 	void __iomem *reg = bank->base;
 
@@ -551,13 +554,13 @@ static void omap_clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
 	readl_relaxed(reg);
 }
 
-static inline void omap_clear_gpio_irqstatus(struct gpio_bank *bank,
+static inline void omap_clear_gpio_irqstatus(struct omap_gpio_bank *bank,
 					     unsigned int offset)
 {
 	omap_clear_gpio_irqbank(bank, BIT(offset));
 }
 
-static u32 omap_get_gpio_irqbank_mask(struct gpio_bank *bank)
+static u32 omap_get_gpio_irqbank_mask(struct omap_gpio_bank *bank)
 {
 	void __iomem *reg = bank->base;
 	u32 l;
@@ -571,7 +574,7 @@ static u32 omap_get_gpio_irqbank_mask(struct gpio_bank *bank)
 	return l;
 }
 
-static void omap_enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
+static void omap_enable_gpio_irqbank(struct omap_gpio_bank *bank, int gpio_mask)
 {
 	void __iomem *reg = bank->base;
 	u32 l;
@@ -593,7 +596,8 @@ static void omap_enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
 	writel_relaxed(l, reg);
 }
 
-static void omap_disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
+static void omap_disable_gpio_irqbank(struct omap_gpio_bank *bank,
+				      int gpio_mask)
 {
 	void __iomem *reg = bank->base;
 	u32 l;
@@ -615,7 +619,7 @@ static void omap_disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
 	writel_relaxed(l, reg);
 }
 
-static inline void omap_set_gpio_irqenable(struct gpio_bank *bank,
+static inline void omap_set_gpio_irqenable(struct omap_gpio_bank *bank,
 					   unsigned int offset, int enable)
 {
 	if (enable)
@@ -627,14 +631,14 @@ static inline void omap_set_gpio_irqenable(struct gpio_bank *bank,
 /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
 static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable)
 {
-	struct gpio_bank *bank = omap_irq_data_get_bank(d);
+	struct omap_gpio_bank *bank = omap_irq_data_get_bank(d);
 
 	return irq_set_irq_wake(bank->irq, enable);
 }
 
 static int omap_gpio_request(struct gpio_chip *chip, unsigned int offset)
 {
-	struct gpio_bank *bank = gpiochip_get_data(chip);
+	struct omap_gpio_bank *bank = gpiochip_get_data(chip);
 	unsigned long flags;
 
 	/*
@@ -654,7 +658,7 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned int offset)
 
 static void omap_gpio_free(struct gpio_chip *chip, unsigned int offset)
 {
-	struct gpio_bank *bank = gpiochip_get_data(chip);
+	struct omap_gpio_bank *bank = gpiochip_get_data(chip);
 	unsigned long flags;
 
 	raw_spin_lock_irqsave(&bank->lock, flags);
@@ -688,7 +692,7 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
 	void __iomem *isr_reg = NULL;
 	u32 isr;
 	unsigned int bit;
-	struct gpio_bank *bank = gpiobank;
+	struct omap_gpio_bank *bank = gpiobank;
 	unsigned long wa_lock_flags;
 	unsigned long lock_flags;
 
@@ -759,7 +763,7 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
 
 static unsigned int omap_gpio_irq_startup(struct irq_data *d)
 {
-	struct gpio_bank *bank = omap_irq_data_get_bank(d);
+	struct omap_gpio_bank *bank = omap_irq_data_get_bank(d);
 	unsigned long flags;
 	unsigned int offset = d->hwirq;
 
@@ -783,7 +787,7 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d)
 
 static void omap_gpio_irq_shutdown(struct irq_data *d)
 {
-	struct gpio_bank *bank = omap_irq_data_get_bank(d);
+	struct omap_gpio_bank *bank = omap_irq_data_get_bank(d);
 	unsigned long flags;
 	unsigned int offset = d->hwirq;
 
@@ -800,7 +804,7 @@ static void omap_gpio_irq_shutdown(struct irq_data *d)
 
 static void omap_gpio_irq_bus_lock(struct irq_data *data)
 {
-	struct gpio_bank *bank = omap_irq_data_get_bank(data);
+	struct omap_gpio_bank *bank = omap_irq_data_get_bank(data);
 
 	if (!BANK_USED(bank))
 		pm_runtime_get_sync(bank->chip.parent);
@@ -808,7 +812,7 @@ static void omap_gpio_irq_bus_lock(struct irq_data *data)
 
 static void gpio_irq_bus_sync_unlock(struct irq_data *data)
 {
-	struct gpio_bank *bank = omap_irq_data_get_bank(data);
+	struct omap_gpio_bank *bank = omap_irq_data_get_bank(data);
 
 	/*
 	 * If this is the last IRQ to be freed in the bank,
@@ -820,7 +824,7 @@ static void gpio_irq_bus_sync_unlock(struct irq_data *data)
 
 static void omap_gpio_ack_irq(struct irq_data *d)
 {
-	struct gpio_bank *bank = omap_irq_data_get_bank(d);
+	struct omap_gpio_bank *bank = omap_irq_data_get_bank(d);
 	unsigned int offset = d->hwirq;
 
 	omap_clear_gpio_irqstatus(bank, offset);
@@ -828,7 +832,7 @@ static void omap_gpio_ack_irq(struct irq_data *d)
 
 static void omap_gpio_mask_irq(struct irq_data *d)
 {
-	struct gpio_bank *bank = omap_irq_data_get_bank(d);
+	struct omap_gpio_bank *bank = omap_irq_data_get_bank(d);
 	unsigned int offset = d->hwirq;
 	unsigned long flags;
 
@@ -840,7 +844,7 @@ static void omap_gpio_mask_irq(struct irq_data *d)
 
 static void omap_gpio_unmask_irq(struct irq_data *d)
 {
-	struct gpio_bank *bank = omap_irq_data_get_bank(d);
+	struct omap_gpio_bank *bank = omap_irq_data_get_bank(d);
 	unsigned int offset = d->hwirq;
 	u32 trigger = irqd_get_trigger_type(d);
 	unsigned long flags;
@@ -867,7 +871,7 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
 static int omap_mpuio_suspend_noirq(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
-	struct gpio_bank	*bank = platform_get_drvdata(pdev);
+	struct omap_gpio_bank	*bank = platform_get_drvdata(pdev);
 	void __iomem		*mask_reg = bank->base +
 					OMAP_MPUIO_GPIO_MASKIT / bank->stride;
 	unsigned long		flags;
@@ -882,7 +886,7 @@ static int omap_mpuio_suspend_noirq(struct device *dev)
 static int omap_mpuio_resume_noirq(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
-	struct gpio_bank	*bank = platform_get_drvdata(pdev);
+	struct omap_gpio_bank	*bank = platform_get_drvdata(pdev);
 	void __iomem		*mask_reg = bank->base +
 					OMAP_MPUIO_GPIO_MASKIT / bank->stride;
 	unsigned long		flags;
@@ -916,7 +920,7 @@ static struct platform_device omap_mpuio_device = {
 	/* could list the /proc/iomem resources */
 };
 
-static inline void omap_mpuio_init(struct gpio_bank *bank)
+static inline void omap_mpuio_init(struct omap_gpio_bank *bank)
 {
 	platform_set_drvdata(&omap_mpuio_device, bank);
 
@@ -928,7 +932,7 @@ static inline void omap_mpuio_init(struct gpio_bank *bank)
 
 static int omap_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
 {
-	struct gpio_bank *bank;
+	struct omap_gpio_bank *bank;
 	unsigned long flags;
 	void __iomem *reg;
 	int dir;
@@ -943,7 +947,7 @@ static int omap_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
 
 static int omap_gpio_input(struct gpio_chip *chip, unsigned int offset)
 {
-	struct gpio_bank *bank;
+	struct omap_gpio_bank *bank;
 	unsigned long flags;
 
 	bank = gpiochip_get_data(chip);
@@ -955,7 +959,7 @@ static int omap_gpio_input(struct gpio_chip *chip, unsigned int offset)
 
 static int omap_gpio_get(struct gpio_chip *chip, unsigned int offset)
 {
-	struct gpio_bank *bank;
+	struct omap_gpio_bank *bank;
 
 	bank = gpiochip_get_data(chip);
 
@@ -968,7 +972,7 @@ static int omap_gpio_get(struct gpio_chip *chip, unsigned int offset)
 static int omap_gpio_output(struct gpio_chip *chip, unsigned int offset,
 			    int value)
 {
-	struct gpio_bank *bank;
+	struct omap_gpio_bank *bank;
 	unsigned long flags;
 
 	bank = gpiochip_get_data(chip);
@@ -982,7 +986,7 @@ static int omap_gpio_output(struct gpio_chip *chip, unsigned int offset,
 static int omap_gpio_debounce(struct gpio_chip *chip, unsigned int offset,
 			      unsigned int debounce)
 {
-	struct gpio_bank *bank;
+	struct omap_gpio_bank *bank;
 	unsigned long flags;
 	int ret;
 
@@ -1015,7 +1019,7 @@ static int omap_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
 static void omap_gpio_set(struct gpio_chip *chip, unsigned int offset,
 			  int value)
 {
-	struct gpio_bank *bank;
+	struct omap_gpio_bank *bank;
 	unsigned long flags;
 
 	bank = gpiochip_get_data(chip);
@@ -1026,7 +1030,7 @@ static void omap_gpio_set(struct gpio_chip *chip, unsigned int offset,
 
 /*---------------------------------------------------------------------*/
 
-static void omap_gpio_show_rev(struct gpio_bank *bank)
+static void omap_gpio_show_rev(struct omap_gpio_bank *bank)
 {
 	static bool called;
 	u32 rev;
@@ -1041,7 +1045,7 @@ static void omap_gpio_show_rev(struct gpio_bank *bank)
 	called = true;
 }
 
-static void omap_gpio_mod_init(struct gpio_bank *bank)
+static void omap_gpio_mod_init(struct omap_gpio_bank *bank)
 {
 	void __iomem *base = bank->base;
 	u32 l = 0xffffffff;
@@ -1068,7 +1072,8 @@ static void omap_gpio_mod_init(struct gpio_bank *bank)
 		writel_relaxed(0, base + bank->regs->ctrl);
 }
 
-static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
+static int omap_gpio_chip_init(struct omap_gpio_bank *bank,
+			       struct irq_chip *irqc)
 {
 	static int gpio;
 	int irq_base = 0;
@@ -1158,7 +1163,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
 	const struct of_device_id *match;
 	const struct omap_gpio_platform_data *pdata;
 	struct resource *res;
-	struct gpio_bank *bank;
+	struct omap_gpio_bank *bank;
 	struct irq_chip *irqc;
 	int ret;
 
@@ -1168,7 +1173,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
 	if (!pdata)
 		return -EINVAL;
 
-	bank = devm_kzalloc(dev, sizeof(struct gpio_bank), GFP_KERNEL);
+	bank = devm_kzalloc(dev, sizeof(struct omap_gpio_bank), GFP_KERNEL);
 	if (!bank)
 		return -ENOMEM;
 
@@ -1276,7 +1281,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
 
 static int omap_gpio_remove(struct platform_device *pdev)
 {
-	struct gpio_bank *bank = platform_get_drvdata(pdev);
+	struct omap_gpio_bank *bank = platform_get_drvdata(pdev);
 
 	list_del(&bank->node);
 	gpiochip_remove(&bank->chip);
@@ -1290,12 +1295,12 @@ static int omap_gpio_remove(struct platform_device *pdev)
 #ifdef CONFIG_ARCH_OMAP2PLUS
 
 #if defined(CONFIG_PM)
-static void omap_gpio_restore_context(struct gpio_bank *bank);
+static void omap_gpio_restore_context(struct omap_gpio_bank *bank);
 
 static int omap_gpio_runtime_suspend(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
-	struct gpio_bank *bank = platform_get_drvdata(pdev);
+	struct omap_gpio_bank *bank = platform_get_drvdata(pdev);
 	u32 l1 = 0, l2 = 0;
 	unsigned long flags;
 	u32 wake_low, wake_hi;
@@ -1358,12 +1363,12 @@ static int omap_gpio_runtime_suspend(struct device *dev)
 	return 0;
 }
 
-static void omap_gpio_init_context(struct gpio_bank *p);
+static void omap_gpio_init_context(struct omap_gpio_bank *p);
 
 static int omap_gpio_runtime_resume(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
-	struct gpio_bank *bank = platform_get_drvdata(pdev);
+	struct omap_gpio_bank *bank = platform_get_drvdata(pdev);
 	u32 l = 0, gen, gen0, gen1;
 	unsigned long flags;
 	int c;
@@ -1475,7 +1480,7 @@ static int omap_gpio_runtime_resume(struct device *dev)
 #if IS_BUILTIN(CONFIG_GPIO_OMAP)
 void omap2_gpio_prepare_for_idle(int pwr_mode)
 {
-	struct gpio_bank *bank;
+	struct omap_gpio_bank *bank;
 
 	list_for_each_entry(bank, &omap_gpio_list, node) {
 		if (!BANK_USED(bank) || !bank->loses_context)
@@ -1489,7 +1494,7 @@ void omap2_gpio_prepare_for_idle(int pwr_mode)
 
 void omap2_gpio_resume_after_idle(void)
 {
-	struct gpio_bank *bank;
+	struct omap_gpio_bank *bank;
 
 	list_for_each_entry(bank, &omap_gpio_list, node) {
 		if (!BANK_USED(bank) || !bank->loses_context)
@@ -1501,7 +1506,7 @@ void omap2_gpio_resume_after_idle(void)
 #endif
 
 #if defined(CONFIG_PM)
-static void omap_gpio_init_context(struct gpio_bank *p)
+static void omap_gpio_init_context(struct omap_gpio_bank *p)
 {
 	struct omap_gpio_reg_offs *regs = p->regs;
 	void __iomem *base = p->base;
@@ -1524,7 +1529,7 @@ static void omap_gpio_init_context(struct gpio_bank *p)
 	p->context_valid = true;
 }
 
-static void omap_gpio_restore_context(struct gpio_bank *bank)
+static void omap_gpio_restore_context(struct omap_gpio_bank *bank)
 {
 	writel_relaxed(bank->context.wake_en,
 				bank->base + bank->regs->wkup_en);
@@ -1561,7 +1566,7 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
 #else
 #define omap_gpio_runtime_suspend NULL
 #define omap_gpio_runtime_resume NULL
-static inline void omap_gpio_init_context(struct gpio_bank *p) {}
+static inline void omap_gpio_init_context(struct omap_gpio_bank *p) {}
 #endif
 
 static const struct dev_pm_ops gpio_pm_ops = {
-- 
2.14.1

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

* [PATCH v2 14/16] gpio: Add support for banked GPIO controllers
  2017-09-28  9:56 ` Thierry Reding
@ 2017-09-28  9:56     ` Thierry Reding
  -1 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-09-28  9:56 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Jonathan Hunter, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

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

Some GPIO controllers are subdivided into multiple logical blocks called
banks (or ports). This is often caused by the design assigning separate
resources, such as register regions or interrupts, to each bank, or some
set of banks.

This commit adds support for describing controllers that have such a
banked design and provides common code for dealing with them.

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

diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index bfcd20699ec8..9baabe00966d 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -309,6 +309,107 @@ int of_gpio_simple_xlate(struct gpio_chip *gc,
 }
 EXPORT_SYMBOL(of_gpio_simple_xlate);
 
+/**
+ * gpio_banked_irq_domain_xlate - decode an IRQ specifier for banked chips
+ * @domain: IRQ domain
+ * @np: device tree node
+ * @spec: IRQ specifier
+ * @size: number of cells in IRQ specifier
+ * @hwirq: return location for the hardware IRQ number
+ * @type: return location for the IRQ type
+ *
+ * Translates the IRQ specifier found in device tree into a hardware IRQ
+ * number and an interrupt type.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ */
+int gpio_banked_irq_domain_xlate(struct irq_domain *domain,
+				 struct device_node *np,
+				 const u32 *spec, unsigned int size,
+				 unsigned long *hwirq,
+				 unsigned int *type)
+{
+	struct gpio_chip *gc = domain->host_data;
+	unsigned int bank, line, i, offset = 0;
+
+	if (size < 2)
+		return -EINVAL;
+
+	bank = (spec[0] >> gc->of_gpio_bank_mask) & gc->of_gpio_bank_shift;
+	line = (spec[0] >> gc->of_gpio_line_mask) & gc->of_gpio_line_shift;
+
+	if (bank >= gc->num_banks) {
+		dev_err(gc->parent, "invalid bank number: %u\n", bank);
+		return -EINVAL;
+	}
+
+	if (line >= gc->banks[bank]->num_lines) {
+		dev_err(gc->parent, "invalid line number: %u\n", line);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < bank; i++)
+		offset += gc->banks[i]->num_lines;
+
+	*type = spec[1] & IRQ_TYPE_SENSE_MASK;
+	*hwirq = offset + line;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(gpio_banked_irq_domain_xlate);
+
+/**
+ * of_gpio_banked_xlate - translate GPIO specifier to a GPIO number and flags
+ * @gc: GPIO chip
+ * @gpiospec: GPIO specifier
+ * @flags: return location for flags parsed from the GPIO specifier
+ *
+ * This translation function takes into account multiple banks that can make
+ * up a single controller. Each bank can contain one or more pins. A single
+ * cell in the specifier is used to represent a (bank, pin) pair, with each
+ * encoded in different fields. The &gpio_chip.of_gpio_bank_shift and
+ * &gpio_chip.of_gpio_bank_mask fields, and &gpio_chip.of_gpio_line_shift and
+ * &gpio_chip.of_gpio_line_mask are used to specify the encoding.
+ *
+ * Returns:
+ * The chip-relative index of the pin given by the GPIO specifier.
+ */
+int of_gpio_banked_xlate(struct gpio_chip *gc,
+			 const struct of_phandle_args *gpiospec, u32 *flags)
+{
+	unsigned int offset = 0, bank, line, i;
+	const u32 *spec = gpiospec->args;
+
+	if (WARN_ON(gc->of_gpio_n_cells < 2))
+		return -EINVAL;
+
+	if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
+		return -EINVAL;
+
+	bank = (spec[0] >> gc->of_gpio_bank_shift) & gc->of_gpio_bank_mask;
+	line = (spec[0] >> gc->of_gpio_line_shift) & gc->of_gpio_line_mask;
+
+	if (bank >= gc->num_banks) {
+		dev_err(gc->parent, "invalid bank number: %u\n", bank);
+		return -EINVAL;
+	}
+
+	if (line >= gc->banks[bank]->num_lines) {
+		dev_err(gc->parent, "invalid line number: %u\n", line);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < bank; i++)
+		offset += gc->banks[i]->num_lines;
+
+	if (flags)
+		*flags = spec[1];
+
+	return offset + line;
+}
+EXPORT_SYMBOL(of_gpio_banked_xlate);
+
 /**
  * of_mm_gpiochip_add_data - Add memory mapped GPIO chip (bank)
  * @np:		device node of the GPIO chip
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index c15fb858848a..b3bd19b793d3 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1765,6 +1765,57 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
 	gpiochip->to_irq = gpiochip_to_irq;
 	gpiochip->irq.default_type = type;
 
+	if (gpiochip->num_banks > 0 && !gpiochip->irq.map) {
+		struct gpio_irq_chip *irq = &gpiochip->irq;
+		unsigned int i, j, offset = 0;
+
+		if (!irq->parents) {
+			chip_err(gpiochip, "no parent interrupts defined\n");
+			return -EINVAL;
+		}
+
+		irq->map = devm_kcalloc(gpiochip->parent, gpiochip->ngpio,
+					sizeof(*irq->map), GFP_KERNEL);
+		if (!irq->map)
+			return -ENOMEM;
+
+		for (i = 0; i < gpiochip->num_banks; i++) {
+			struct gpio_bank *bank = gpiochip->banks[i];
+			unsigned int parent = bank->parent_irq;
+
+			for (j = 0; j < bank->num_lines; j++) {
+				if (parent >= irq->num_parents) {
+					chip_err(gpiochip,
+						 "invalid parent interrupt: %u\n",
+						 parent);
+					return -EINVAL;
+				}
+
+				irq->map[offset + j] = irq->parents[parent];
+			}
+
+			offset += bank->num_lines;
+		}
+	}
+
+	if (gpiochip->num_banks > 0) {
+		unsigned int i;
+
+		for (i = 0; i < gpiochip->num_banks; i++) {
+			struct gpio_bank *bank = gpiochip->banks[i];
+			unsigned int num_lines = bank->num_lines;
+
+			bank->pending = devm_kcalloc(gpiochip->parent,
+						     BITS_TO_LONGS(num_lines),
+						     sizeof(unsigned long),
+						     GFP_KERNEL);
+			if (!bank->pending)
+				return -ENOMEM;
+
+			bank->chip = gpiochip;
+		}
+	}
+
 	if (gpiochip->irq.domain_ops)
 		ops = gpiochip->irq.domain_ops;
 	else
@@ -1973,6 +2024,53 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 }
 EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
 
+/**
+ * gpio_irq_chip_banked_chained_handler - interrupt handler for banked IRQ chips
+ * @desc: IRQ descriptor
+ *
+ * Drivers can use this interrupt handler for banked GPIO controllers. This
+ * implementation iterates over all banks and handles pending interrupts of
+ * the pins associated with the bank.
+ *
+ * This function uses driver specific parts, split out into the
+ * &gpio_chip.update_bank() callback, to retrieves the interrupt pending
+ * state for each of the GPIOs exposed by the given bank.
+ */
+void gpio_irq_chip_banked_chained_handler(struct irq_desc *desc)
+{
+	struct gpio_chip *gpio = irq_desc_get_handler_data(desc);
+	struct irq_chip *irq = irq_desc_get_chip(desc);
+	unsigned int parent = irq_desc_get_irq(desc);
+	struct gpio_irq_chip *chip = &gpio->irq;
+	unsigned int i, offset = 0;
+
+	chained_irq_enter(irq, desc);
+
+	for (i = 0; i < gpio->num_banks; i++) {
+		struct gpio_bank *bank = gpio->banks[i];
+		unsigned int line, virq;
+
+		if (parent != chip->parents[bank->parent_irq])
+			goto skip;
+
+		chip->update_bank(bank);
+
+		for_each_set_bit(line, bank->pending, bank->num_lines) {
+			virq = irq_find_mapping(chip->domain, offset + line);
+			if (WARN_ON(virq == 0))
+				continue;
+
+			generic_handle_irq(virq);
+		}
+
+skip:
+		offset += bank->num_lines;
+	}
+
+	chained_irq_exit(irq, desc);
+}
+EXPORT_SYMBOL_GPL(gpio_irq_chip_banked_chained_handler);
+
 #else /* CONFIG_GPIOLIB_IRQCHIP */
 
 static inline int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index c453e0716228..3caa08b3d2b6 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -19,6 +19,47 @@ struct module;
 
 #ifdef CONFIG_GPIOLIB
 
+/**
+ * struct gpio_bank - GPIO bank
+ *
+ * A GPIO bank, sometimes also referred to as port, represents a subset of the
+ * lines of a GPIO controller. The separation into banks is often caused by the
+ * sharing of one or more resource (register region, interrupt, ...) for each
+ * of the lines in the bank.
+ *
+ * In many cases the banking is transparent, but when it is not, GPIO drivers
+ * can use this code, along with some supporting fields in &struct gpio_chip.
+ */
+struct gpio_bank {
+	/**
+	 * @chip:
+	 *
+	 * A pointer to the &struct gpio_chip that this bank belongs to.
+	 */
+	struct gpio_chip *chip;
+
+	/**
+	 * @parent_irq:
+	 *
+	 * The interrupt parent for this bank.
+	 */
+	unsigned int parent_irq;
+
+	/**
+	 * @num_lines:
+	 *
+	 * The number of lines provided by this bank.
+	 */
+	unsigned int num_lines;
+
+	/**
+	 * @pending:
+	 *
+	 * Current interrupt state of each pin in the bank.
+	 */
+	unsigned long *pending;
+};
+
 #ifdef CONFIG_GPIOLIB_IRQCHIP
 /**
  * struct gpio_irq_chip - GPIO interrupt controller
@@ -136,6 +177,15 @@ struct gpio_irq_chip {
 	 * in IRQ domain of the chip.
 	 */
 	unsigned long *valid_mask;
+
+	/**
+	 * @update_bank:
+	 *
+	 * Callback used by banked interrupt controllers. The driver updates
+	 * the &gpio_bank.pending field of the given @bank with the current
+	 * status for each of the GPIOs that it provides.
+	 */
+	void (*update_bank)(struct gpio_bank *bank);
 };
 
 static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
@@ -281,6 +331,24 @@ struct gpio_chip {
 	struct gpio_irq_chip irq;
 #endif
 
+	/**
+	 * @banks:
+	 *
+	 * If a GPIO controller is subdivided into multiple banks, the driver
+	 * can use this field to store information about these banks.
+	 *
+	 * Note that the driver owns this field and the core will not modify
+	 * it, only reference it.
+	 */
+	struct gpio_bank **banks;
+
+	/**
+	 * @num_banks:
+	 *
+	 * The number of banks described in @banks.
+	 */
+	unsigned int num_banks;
+
 #if defined(CONFIG_OF_GPIO)
 	/*
 	 * If CONFIG_OF is enabled, then all GPIO controllers described in the
@@ -301,6 +369,38 @@ struct gpio_chip {
 	 */
 	unsigned int of_gpio_n_cells;
 
+	/**
+	 * @of_gpio_bank_shift:
+	 *
+	 * The offset of the field in the cell denoting the bank number of a
+	 * specified GPIO.
+	 */
+	unsigned int of_gpio_bank_shift;
+
+	/**
+	 * @of_gpio_bank_mask:
+	 *
+	 * The mask of the field in the cell denoting the bank number of a
+	 * specified GPIO.
+	 */
+	unsigned int of_gpio_bank_mask;
+
+	/**
+	 * @of_gpio_line_shift:
+	 *
+	 * The offset of the field in the cell denoting the line number of a
+	 * specified GPIO within its bank.
+	 */
+	unsigned int of_gpio_line_shift;
+
+	/**
+	 * @of_gpio_line_mask:
+	 *
+	 * The mask of the field in the cell denoting the line number of a
+	 * specified GPIO within its bank.
+	 */
+	unsigned int of_gpio_line_mask;
+
 	/**
 	 * @of_xlate:
 	 *
@@ -374,6 +474,12 @@ 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);
 
+int gpio_banked_irq_domain_xlate(struct irq_domain *domain,
+				 struct device_node *np,
+				 const u32 *spec, unsigned int size,
+				 unsigned long *hwirq,
+				 unsigned int *type);
+
 void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
 		struct irq_chip *irqchip,
 		unsigned int parent_irq,
@@ -391,6 +497,8 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 			     bool nested,
 			     struct lock_class_key *lock_key);
 
+void gpio_irq_chip_banked_chained_handler(struct irq_desc *desc);
+
 #ifdef CONFIG_LOCKDEP
 
 /*
diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h
index ca10f43564de..f85414dc31f4 100644
--- a/include/linux/of_gpio.h
+++ b/include/linux/of_gpio.h
@@ -66,6 +66,9 @@ extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc);
 extern int of_gpio_simple_xlate(struct gpio_chip *gc,
 				const struct of_phandle_args *gpiospec,
 				u32 *flags);
+extern int of_gpio_banked_xlate(struct gpio_chip *gc,
+				const struct of_phandle_args *gpiospec,
+				u32 *flags);
 
 #else /* CONFIG_OF_GPIO */
 
@@ -86,6 +89,13 @@ static inline int of_gpio_simple_xlate(struct gpio_chip *gc,
 	return -ENOSYS;
 }
 
+static inline int of_gpio_banked_xlate(struct gpio_chip *gc,
+				       const struct of_phandle_args *gpiospec,
+				       u32 *flags)
+{
+	return -ENOSYS;
+}
+
 #endif /* CONFIG_OF_GPIO */
 
 /**
-- 
2.14.1

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

* [PATCH v2 14/16] gpio: Add support for banked GPIO controllers
@ 2017-09-28  9:56     ` Thierry Reding
  0 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-09-28  9:56 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

From: Thierry Reding <treding@nvidia.com>

Some GPIO controllers are subdivided into multiple logical blocks called
banks (or ports). This is often caused by the design assigning separate
resources, such as register regions or interrupts, to each bank, or some
set of banks.

This commit adds support for describing controllers that have such a
banked design and provides common code for dealing with them.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/gpio/gpiolib-of.c   | 101 +++++++++++++++++++++++++++++++++++++++++
 drivers/gpio/gpiolib.c      |  98 ++++++++++++++++++++++++++++++++++++++++
 include/linux/gpio/driver.h | 108 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/of_gpio.h     |  10 ++++
 4 files changed, 317 insertions(+)

diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index bfcd20699ec8..9baabe00966d 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -309,6 +309,107 @@ int of_gpio_simple_xlate(struct gpio_chip *gc,
 }
 EXPORT_SYMBOL(of_gpio_simple_xlate);
 
+/**
+ * gpio_banked_irq_domain_xlate - decode an IRQ specifier for banked chips
+ * @domain: IRQ domain
+ * @np: device tree node
+ * @spec: IRQ specifier
+ * @size: number of cells in IRQ specifier
+ * @hwirq: return location for the hardware IRQ number
+ * @type: return location for the IRQ type
+ *
+ * Translates the IRQ specifier found in device tree into a hardware IRQ
+ * number and an interrupt type.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ */
+int gpio_banked_irq_domain_xlate(struct irq_domain *domain,
+				 struct device_node *np,
+				 const u32 *spec, unsigned int size,
+				 unsigned long *hwirq,
+				 unsigned int *type)
+{
+	struct gpio_chip *gc = domain->host_data;
+	unsigned int bank, line, i, offset = 0;
+
+	if (size < 2)
+		return -EINVAL;
+
+	bank = (spec[0] >> gc->of_gpio_bank_mask) & gc->of_gpio_bank_shift;
+	line = (spec[0] >> gc->of_gpio_line_mask) & gc->of_gpio_line_shift;
+
+	if (bank >= gc->num_banks) {
+		dev_err(gc->parent, "invalid bank number: %u\n", bank);
+		return -EINVAL;
+	}
+
+	if (line >= gc->banks[bank]->num_lines) {
+		dev_err(gc->parent, "invalid line number: %u\n", line);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < bank; i++)
+		offset += gc->banks[i]->num_lines;
+
+	*type = spec[1] & IRQ_TYPE_SENSE_MASK;
+	*hwirq = offset + line;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(gpio_banked_irq_domain_xlate);
+
+/**
+ * of_gpio_banked_xlate - translate GPIO specifier to a GPIO number and flags
+ * @gc: GPIO chip
+ * @gpiospec: GPIO specifier
+ * @flags: return location for flags parsed from the GPIO specifier
+ *
+ * This translation function takes into account multiple banks that can make
+ * up a single controller. Each bank can contain one or more pins. A single
+ * cell in the specifier is used to represent a (bank, pin) pair, with each
+ * encoded in different fields. The &gpio_chip.of_gpio_bank_shift and
+ * &gpio_chip.of_gpio_bank_mask fields, and &gpio_chip.of_gpio_line_shift and
+ * &gpio_chip.of_gpio_line_mask are used to specify the encoding.
+ *
+ * Returns:
+ * The chip-relative index of the pin given by the GPIO specifier.
+ */
+int of_gpio_banked_xlate(struct gpio_chip *gc,
+			 const struct of_phandle_args *gpiospec, u32 *flags)
+{
+	unsigned int offset = 0, bank, line, i;
+	const u32 *spec = gpiospec->args;
+
+	if (WARN_ON(gc->of_gpio_n_cells < 2))
+		return -EINVAL;
+
+	if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
+		return -EINVAL;
+
+	bank = (spec[0] >> gc->of_gpio_bank_shift) & gc->of_gpio_bank_mask;
+	line = (spec[0] >> gc->of_gpio_line_shift) & gc->of_gpio_line_mask;
+
+	if (bank >= gc->num_banks) {
+		dev_err(gc->parent, "invalid bank number: %u\n", bank);
+		return -EINVAL;
+	}
+
+	if (line >= gc->banks[bank]->num_lines) {
+		dev_err(gc->parent, "invalid line number: %u\n", line);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < bank; i++)
+		offset += gc->banks[i]->num_lines;
+
+	if (flags)
+		*flags = spec[1];
+
+	return offset + line;
+}
+EXPORT_SYMBOL(of_gpio_banked_xlate);
+
 /**
  * of_mm_gpiochip_add_data - Add memory mapped GPIO chip (bank)
  * @np:		device node of the GPIO chip
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index c15fb858848a..b3bd19b793d3 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1765,6 +1765,57 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
 	gpiochip->to_irq = gpiochip_to_irq;
 	gpiochip->irq.default_type = type;
 
+	if (gpiochip->num_banks > 0 && !gpiochip->irq.map) {
+		struct gpio_irq_chip *irq = &gpiochip->irq;
+		unsigned int i, j, offset = 0;
+
+		if (!irq->parents) {
+			chip_err(gpiochip, "no parent interrupts defined\n");
+			return -EINVAL;
+		}
+
+		irq->map = devm_kcalloc(gpiochip->parent, gpiochip->ngpio,
+					sizeof(*irq->map), GFP_KERNEL);
+		if (!irq->map)
+			return -ENOMEM;
+
+		for (i = 0; i < gpiochip->num_banks; i++) {
+			struct gpio_bank *bank = gpiochip->banks[i];
+			unsigned int parent = bank->parent_irq;
+
+			for (j = 0; j < bank->num_lines; j++) {
+				if (parent >= irq->num_parents) {
+					chip_err(gpiochip,
+						 "invalid parent interrupt: %u\n",
+						 parent);
+					return -EINVAL;
+				}
+
+				irq->map[offset + j] = irq->parents[parent];
+			}
+
+			offset += bank->num_lines;
+		}
+	}
+
+	if (gpiochip->num_banks > 0) {
+		unsigned int i;
+
+		for (i = 0; i < gpiochip->num_banks; i++) {
+			struct gpio_bank *bank = gpiochip->banks[i];
+			unsigned int num_lines = bank->num_lines;
+
+			bank->pending = devm_kcalloc(gpiochip->parent,
+						     BITS_TO_LONGS(num_lines),
+						     sizeof(unsigned long),
+						     GFP_KERNEL);
+			if (!bank->pending)
+				return -ENOMEM;
+
+			bank->chip = gpiochip;
+		}
+	}
+
 	if (gpiochip->irq.domain_ops)
 		ops = gpiochip->irq.domain_ops;
 	else
@@ -1973,6 +2024,53 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 }
 EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
 
+/**
+ * gpio_irq_chip_banked_chained_handler - interrupt handler for banked IRQ chips
+ * @desc: IRQ descriptor
+ *
+ * Drivers can use this interrupt handler for banked GPIO controllers. This
+ * implementation iterates over all banks and handles pending interrupts of
+ * the pins associated with the bank.
+ *
+ * This function uses driver specific parts, split out into the
+ * &gpio_chip.update_bank() callback, to retrieves the interrupt pending
+ * state for each of the GPIOs exposed by the given bank.
+ */
+void gpio_irq_chip_banked_chained_handler(struct irq_desc *desc)
+{
+	struct gpio_chip *gpio = irq_desc_get_handler_data(desc);
+	struct irq_chip *irq = irq_desc_get_chip(desc);
+	unsigned int parent = irq_desc_get_irq(desc);
+	struct gpio_irq_chip *chip = &gpio->irq;
+	unsigned int i, offset = 0;
+
+	chained_irq_enter(irq, desc);
+
+	for (i = 0; i < gpio->num_banks; i++) {
+		struct gpio_bank *bank = gpio->banks[i];
+		unsigned int line, virq;
+
+		if (parent != chip->parents[bank->parent_irq])
+			goto skip;
+
+		chip->update_bank(bank);
+
+		for_each_set_bit(line, bank->pending, bank->num_lines) {
+			virq = irq_find_mapping(chip->domain, offset + line);
+			if (WARN_ON(virq == 0))
+				continue;
+
+			generic_handle_irq(virq);
+		}
+
+skip:
+		offset += bank->num_lines;
+	}
+
+	chained_irq_exit(irq, desc);
+}
+EXPORT_SYMBOL_GPL(gpio_irq_chip_banked_chained_handler);
+
 #else /* CONFIG_GPIOLIB_IRQCHIP */
 
 static inline int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index c453e0716228..3caa08b3d2b6 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -19,6 +19,47 @@ struct module;
 
 #ifdef CONFIG_GPIOLIB
 
+/**
+ * struct gpio_bank - GPIO bank
+ *
+ * A GPIO bank, sometimes also referred to as port, represents a subset of the
+ * lines of a GPIO controller. The separation into banks is often caused by the
+ * sharing of one or more resource (register region, interrupt, ...) for each
+ * of the lines in the bank.
+ *
+ * In many cases the banking is transparent, but when it is not, GPIO drivers
+ * can use this code, along with some supporting fields in &struct gpio_chip.
+ */
+struct gpio_bank {
+	/**
+	 * @chip:
+	 *
+	 * A pointer to the &struct gpio_chip that this bank belongs to.
+	 */
+	struct gpio_chip *chip;
+
+	/**
+	 * @parent_irq:
+	 *
+	 * The interrupt parent for this bank.
+	 */
+	unsigned int parent_irq;
+
+	/**
+	 * @num_lines:
+	 *
+	 * The number of lines provided by this bank.
+	 */
+	unsigned int num_lines;
+
+	/**
+	 * @pending:
+	 *
+	 * Current interrupt state of each pin in the bank.
+	 */
+	unsigned long *pending;
+};
+
 #ifdef CONFIG_GPIOLIB_IRQCHIP
 /**
  * struct gpio_irq_chip - GPIO interrupt controller
@@ -136,6 +177,15 @@ struct gpio_irq_chip {
 	 * in IRQ domain of the chip.
 	 */
 	unsigned long *valid_mask;
+
+	/**
+	 * @update_bank:
+	 *
+	 * Callback used by banked interrupt controllers. The driver updates
+	 * the &gpio_bank.pending field of the given @bank with the current
+	 * status for each of the GPIOs that it provides.
+	 */
+	void (*update_bank)(struct gpio_bank *bank);
 };
 
 static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
@@ -281,6 +331,24 @@ struct gpio_chip {
 	struct gpio_irq_chip irq;
 #endif
 
+	/**
+	 * @banks:
+	 *
+	 * If a GPIO controller is subdivided into multiple banks, the driver
+	 * can use this field to store information about these banks.
+	 *
+	 * Note that the driver owns this field and the core will not modify
+	 * it, only reference it.
+	 */
+	struct gpio_bank **banks;
+
+	/**
+	 * @num_banks:
+	 *
+	 * The number of banks described in @banks.
+	 */
+	unsigned int num_banks;
+
 #if defined(CONFIG_OF_GPIO)
 	/*
 	 * If CONFIG_OF is enabled, then all GPIO controllers described in the
@@ -301,6 +369,38 @@ struct gpio_chip {
 	 */
 	unsigned int of_gpio_n_cells;
 
+	/**
+	 * @of_gpio_bank_shift:
+	 *
+	 * The offset of the field in the cell denoting the bank number of a
+	 * specified GPIO.
+	 */
+	unsigned int of_gpio_bank_shift;
+
+	/**
+	 * @of_gpio_bank_mask:
+	 *
+	 * The mask of the field in the cell denoting the bank number of a
+	 * specified GPIO.
+	 */
+	unsigned int of_gpio_bank_mask;
+
+	/**
+	 * @of_gpio_line_shift:
+	 *
+	 * The offset of the field in the cell denoting the line number of a
+	 * specified GPIO within its bank.
+	 */
+	unsigned int of_gpio_line_shift;
+
+	/**
+	 * @of_gpio_line_mask:
+	 *
+	 * The mask of the field in the cell denoting the line number of a
+	 * specified GPIO within its bank.
+	 */
+	unsigned int of_gpio_line_mask;
+
 	/**
 	 * @of_xlate:
 	 *
@@ -374,6 +474,12 @@ 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);
 
+int gpio_banked_irq_domain_xlate(struct irq_domain *domain,
+				 struct device_node *np,
+				 const u32 *spec, unsigned int size,
+				 unsigned long *hwirq,
+				 unsigned int *type);
+
 void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
 		struct irq_chip *irqchip,
 		unsigned int parent_irq,
@@ -391,6 +497,8 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 			     bool nested,
 			     struct lock_class_key *lock_key);
 
+void gpio_irq_chip_banked_chained_handler(struct irq_desc *desc);
+
 #ifdef CONFIG_LOCKDEP
 
 /*
diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h
index ca10f43564de..f85414dc31f4 100644
--- a/include/linux/of_gpio.h
+++ b/include/linux/of_gpio.h
@@ -66,6 +66,9 @@ extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc);
 extern int of_gpio_simple_xlate(struct gpio_chip *gc,
 				const struct of_phandle_args *gpiospec,
 				u32 *flags);
+extern int of_gpio_banked_xlate(struct gpio_chip *gc,
+				const struct of_phandle_args *gpiospec,
+				u32 *flags);
 
 #else /* CONFIG_OF_GPIO */
 
@@ -86,6 +89,13 @@ static inline int of_gpio_simple_xlate(struct gpio_chip *gc,
 	return -ENOSYS;
 }
 
+static inline int of_gpio_banked_xlate(struct gpio_chip *gc,
+				       const struct of_phandle_args *gpiospec,
+				       u32 *flags)
+{
+	return -ENOSYS;
+}
+
 #endif /* CONFIG_OF_GPIO */
 
 /**
-- 
2.14.1

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

* [PATCH v2 15/16] gpio: tegra: Use banked GPIO infrastructure
  2017-09-28  9:56 ` Thierry Reding
@ 2017-09-28  9:56     ` Thierry Reding
  -1 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-09-28  9:56 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Jonathan Hunter, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

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

Convert the Tegra GPIO driver to use the banked GPIO infrastructure,
which simplifies some parts of the driver.

Signed-off-by: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 drivers/gpio/Kconfig      |   1 +
 drivers/gpio/gpio-tegra.c | 203 ++++++++++++++++++++++------------------------
 2 files changed, 98 insertions(+), 106 deletions(-)

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index db3e446ad9b3..458157d6d491 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -439,6 +439,7 @@ config GPIO_TEGRA
 	default ARCH_TEGRA
 	depends on ARCH_TEGRA || COMPILE_TEST
 	depends on OF_GPIO
+	select GPIOLIB_IRQCHIP
 	help
 	  Say yes here to support GPIO pins on NVIDIA Tegra SoCs.
 
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index fbaf974277df..bfa0abec743b 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -67,8 +67,8 @@
 struct tegra_gpio_info;
 
 struct tegra_gpio_bank {
-	unsigned int bank;
-	unsigned int irq;
+	struct gpio_bank bank;
+	unsigned int index;
 	spinlock_t lvl_lock[4];
 	spinlock_t dbc_lock[4];	/* Lock for updating debounce count register */
 #ifdef CONFIG_PM_SLEEP
@@ -84,6 +84,11 @@ struct tegra_gpio_bank {
 	struct tegra_gpio_info *tgi;
 };
 
+static struct tegra_gpio_bank *to_tegra_gpio_bank(struct gpio_bank *bank)
+{
+	return container_of(bank, struct tegra_gpio_bank, bank);
+}
+
 struct tegra_gpio_soc_config {
 	bool debounce_supported;
 	u32 bank_stride;
@@ -98,9 +103,14 @@ struct tegra_gpio_info {
 	const struct tegra_gpio_soc_config	*soc;
 	struct gpio_chip			gc;
 	struct irq_chip				ic;
-	u32					bank_count;
 };
 
+static inline struct tegra_gpio_info *
+to_tegra_gpio_info(struct gpio_chip *chip)
+{
+	return container_of(chip, struct tegra_gpio_info, gc);
+}
+
 static inline void tegra_gpio_writel(struct tegra_gpio_info *tgi,
 				     u32 val, u32 reg)
 {
@@ -264,8 +274,8 @@ static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
 
 static void tegra_gpio_irq_ack(struct irq_data *d)
 {
-	struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
-	struct tegra_gpio_info *tgi = bank->tgi;
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	struct tegra_gpio_info *tgi = to_tegra_gpio_info(chip);
 	unsigned int gpio = d->hwirq;
 
 	tegra_gpio_writel(tgi, 1 << GPIO_BIT(gpio), GPIO_INT_CLR(tgi, gpio));
@@ -273,8 +283,8 @@ static void tegra_gpio_irq_ack(struct irq_data *d)
 
 static void tegra_gpio_irq_mask(struct irq_data *d)
 {
-	struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
-	struct tegra_gpio_info *tgi = bank->tgi;
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	struct tegra_gpio_info *tgi = to_tegra_gpio_info(chip);
 	unsigned int gpio = d->hwirq;
 
 	tegra_gpio_mask_write(tgi, GPIO_MSK_INT_ENB(tgi, gpio), gpio, 0);
@@ -282,8 +292,8 @@ static void tegra_gpio_irq_mask(struct irq_data *d)
 
 static void tegra_gpio_irq_unmask(struct irq_data *d)
 {
-	struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
-	struct tegra_gpio_info *tgi = bank->tgi;
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	struct tegra_gpio_info *tgi = to_tegra_gpio_info(chip);
 	unsigned int gpio = d->hwirq;
 
 	tegra_gpio_mask_write(tgi, GPIO_MSK_INT_ENB(tgi, gpio), gpio, 1);
@@ -292,12 +302,15 @@ static void tegra_gpio_irq_unmask(struct irq_data *d)
 static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 {
 	unsigned int gpio = d->hwirq, port = GPIO_PORT(gpio), lvl_type;
-	struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
-	struct tegra_gpio_info *tgi = bank->tgi;
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	struct tegra_gpio_info *tgi = to_tegra_gpio_info(chip);
+	struct tegra_gpio_bank *bank;
 	unsigned long flags;
 	u32 val;
 	int ret;
 
+	bank = &tgi->bank_info[GPIO_BANK(gpio)];
+
 	switch (type & IRQ_TYPE_SENSE_MASK) {
 	case IRQ_TYPE_EDGE_RISING:
 		lvl_type = GPIO_INT_LVL_EDGE_RISING;
@@ -352,52 +365,27 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 
 static void tegra_gpio_irq_shutdown(struct irq_data *d)
 {
-	struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
-	struct tegra_gpio_info *tgi = bank->tgi;
-	unsigned int gpio = d->hwirq;
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
 
-	gpiochip_unlock_as_irq(&tgi->gc, gpio);
+	gpiochip_unlock_as_irq(chip, d->hwirq);
 }
 
-static void tegra_gpio_irq_handler(struct irq_desc *desc)
+static void tegra_gpio_update_bank(struct gpio_bank *bank)
 {
-	unsigned int port, pin, gpio;
-	bool unmasked = false;
-	u32 lvl;
-	unsigned long sta;
-	struct irq_chip *chip = irq_desc_get_chip(desc);
-	struct tegra_gpio_bank *bank = irq_desc_get_handler_data(desc);
-	struct tegra_gpio_info *tgi = bank->tgi;
-
-	chained_irq_enter(chip, desc);
+	struct tegra_gpio_info *tgi = to_tegra_gpio_info(bank->chip);
+	struct tegra_gpio_bank *b = to_tegra_gpio_bank(bank);
+	unsigned int port;
 
 	for (port = 0; port < 4; port++) {
-		gpio = tegra_gpio_compose(bank->bank, port, 0);
-		sta = tegra_gpio_readl(tgi, GPIO_INT_STA(tgi, gpio)) &
-			tegra_gpio_readl(tgi, GPIO_INT_ENB(tgi, gpio));
-		lvl = tegra_gpio_readl(tgi, GPIO_INT_LVL(tgi, gpio));
-
-		for_each_set_bit(pin, &sta, 8) {
-			tegra_gpio_writel(tgi, 1 << pin,
-					  GPIO_INT_CLR(tgi, gpio));
-
-			/* if gpio is edge triggered, clear condition
-			 * before executing the handler so that we don't
-			 * miss edges
-			 */
-			if (!unmasked && lvl & (0x100 << pin)) {
-				unmasked = true;
-				chained_irq_exit(chip, desc);
-			}
+		unsigned int gpio = tegra_gpio_compose(b->index, port, 0);
+		u8 *pending = (u8 *)bank->pending;
+		u32 status, enable;
 
-			generic_handle_irq(irq_find_mapping(tgi->irq_domain,
-							    gpio + pin));
-		}
-	}
-
-	if (!unmasked)
-		chained_irq_exit(chip, desc);
+		status = tegra_gpio_readl(tgi, GPIO_INT_STA(tgi, gpio));
+		enable = tegra_gpio_readl(tgi, GPIO_INT_ENB(tgi, gpio));
 
+		pending[port] = status & enable;
+	}
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -410,7 +398,7 @@ static int tegra_gpio_resume(struct device *dev)
 
 	local_irq_save(flags);
 
-	for (b = 0; b < tgi->bank_count; b++) {
+	for (b = 0; b < tgi->gc.num_banks; b++) {
 		struct tegra_gpio_bank *bank = &tgi->bank_info[b];
 
 		for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
@@ -449,7 +437,7 @@ static int tegra_gpio_suspend(struct device *dev)
 	unsigned int b, p;
 
 	local_irq_save(flags);
-	for (b = 0; b < tgi->bank_count; b++) {
+	for (b = 0; b < tgi->gc.num_banks; b++) {
 		struct tegra_gpio_bank *bank = &tgi->bank_info[b];
 
 		for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
@@ -484,20 +472,26 @@ static int tegra_gpio_suspend(struct device *dev)
 
 static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable)
 {
-	struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
-	unsigned int gpio = d->hwirq;
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	unsigned int gpio = d->hwirq, parent_irq;
+	struct tegra_gpio_bank *b;
+	struct gpio_bank *bank;
 	u32 port, bit, mask;
 
+	bank = chip->banks[GPIO_BANK(gpio)];
+	b = to_tegra_gpio_bank(bank);
 	port = GPIO_PORT(gpio);
 	bit = GPIO_BIT(gpio);
 	mask = BIT(bit);
 
 	if (enable)
-		bank->wake_enb[port] |= mask;
+		b->wake_enb[port] |= mask;
 	else
-		bank->wake_enb[port] &= ~mask;
+		b->wake_enb[port] &= ~mask;
+
+	parent_irq = chip->irq.parents[bank->parent_irq];
 
-	return irq_set_irq_wake(bank->irq, enable);
+	return irq_set_irq_wake(parent_irq, enable);
 }
 #endif
 
@@ -511,7 +505,7 @@ static int dbg_gpio_show(struct seq_file *s, void *unused)
 	struct tegra_gpio_info *tgi = s->private;
 	unsigned int i, j;
 
-	for (i = 0; i < tgi->bank_count; i++) {
+	for (i = 0; i < tgi->gc.num_banks; i++) {
 		for (j = 0; j < 4; j++) {
 			unsigned int gpio = tegra_gpio_compose(i, j, 0);
 
@@ -561,17 +555,18 @@ static const struct dev_pm_ops tegra_gpio_pm_ops = {
 };
 
 /*
- * This lock class tells lockdep that GPIO irqs are in a different category
+ * This lock class tells lockdep that GPIO IRQs are in a different category
  * than their parents, so it won't report false recursion.
  */
-static struct lock_class_key gpio_lock_class;
+static struct lock_class_key tegra_gpio_lock_class;
 
 static int tegra_gpio_probe(struct platform_device *pdev)
 {
 	struct tegra_gpio_info *tgi;
 	struct resource *res;
 	struct tegra_gpio_bank *bank;
-	unsigned int gpio, i, j;
+	struct gpio_irq_chip *irq;
+	unsigned int i, j;
 	int ret;
 
 	tgi = devm_kzalloc(&pdev->dev, sizeof(*tgi), GFP_KERNEL);
@@ -580,14 +575,20 @@ static int tegra_gpio_probe(struct platform_device *pdev)
 
 	tgi->soc = of_device_get_match_data(&pdev->dev);
 	tgi->dev = &pdev->dev;
+	irq = &tgi->gc.irq;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	tgi->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(tgi->regs))
+		return PTR_ERR(tgi->regs);
 
 	ret = platform_irq_count(pdev);
 	if (ret < 0)
 		return ret;
 
-	tgi->bank_count = ret;
+	tgi->gc.num_banks = ret;
 
-	if (!tgi->bank_count) {
+	if (!tgi->gc.num_banks) {
 		dev_err(&pdev->dev, "Missing IRQ resource\n");
 		return -ENODEV;
 	}
@@ -602,7 +603,7 @@ static int tegra_gpio_probe(struct platform_device *pdev)
 	tgi->gc.get_direction		= tegra_gpio_get_direction;
 	tgi->gc.to_irq			= tegra_gpio_to_irq;
 	tgi->gc.base			= 0;
-	tgi->gc.ngpio			= tgi->bank_count * 32;
+	tgi->gc.ngpio			= tgi->gc.num_banks * 32;
 	tgi->gc.parent			= &pdev->dev;
 	tgi->gc.of_node			= pdev->dev.of_node;
 
@@ -616,76 +617,66 @@ static int tegra_gpio_probe(struct platform_device *pdev)
 	tgi->ic.irq_set_wake		= tegra_gpio_irq_set_wake;
 #endif
 
+	irq = &tgi->gc.irq;
+	irq->chip = &tgi->ic;
+	irq->handler = handle_simple_irq;
+	irq->lock_key = &tegra_gpio_lock_class;
+	irq->default_type = IRQ_TYPE_NONE;
+	irq->parent_handler = gpio_irq_chip_banked_chained_handler;
+	irq->update_bank = tegra_gpio_update_bank;
+
+	irq->parents = devm_kcalloc(&pdev->dev, tgi->gc.num_banks,
+				    sizeof(unsigned int), GFP_KERNEL);
+	if (!irq->parents)
+		return -ENOMEM;
+
+	irq->num_parents = tgi->gc.num_banks;
+
 	platform_set_drvdata(pdev, tgi);
 
 	if (tgi->soc->debounce_supported)
 		tgi->gc.set_config = tegra_gpio_set_config;
 
-	tgi->bank_info = devm_kcalloc(&pdev->dev, tgi->bank_count,
+	tgi->bank_info = devm_kcalloc(&pdev->dev, tgi->gc.num_banks,
 				      sizeof(*tgi->bank_info), GFP_KERNEL);
 	if (!tgi->bank_info)
 		return -ENOMEM;
 
-	tgi->irq_domain = irq_domain_add_linear(pdev->dev.of_node,
-						tgi->gc.ngpio,
-						&irq_domain_simple_ops, NULL);
-	if (!tgi->irq_domain)
-		return -ENODEV;
+	tgi->gc.banks = devm_kcalloc(&pdev->dev, tgi->gc.num_banks,
+				     sizeof(struct gpio_bank *),
+				     GFP_KERNEL);
+	if (!tgi->gc.banks)
+		return -ENOMEM;
 
-	for (i = 0; i < tgi->bank_count; i++) {
+	for (i = 0; i < tgi->gc.num_banks; i++) {
 		ret = platform_get_irq(pdev, i);
 		if (ret < 0) {
 			dev_err(&pdev->dev, "Missing IRQ resource: %d\n", ret);
 			return ret;
 		}
 
+		irq->parents[i] = ret;
+
 		bank = &tgi->bank_info[i];
-		bank->bank = i;
-		bank->irq = ret;
-		bank->tgi = tgi;
-	}
+		bank->bank.chip = &tgi->gc;
+		bank->bank.parent_irq = i;
+		bank->bank.num_lines = 32;
+		bank->index = i;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	tgi->regs = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(tgi->regs))
-		return PTR_ERR(tgi->regs);
+		tgi->gc.banks[i] = &bank->bank;
 
-	for (i = 0; i < tgi->bank_count; i++) {
 		for (j = 0; j < 4; j++) {
-			int gpio = tegra_gpio_compose(i, j, 0);
+			unsigned int gpio = tegra_gpio_compose(i, j, 0);
 
 			tegra_gpio_writel(tgi, 0x00, GPIO_INT_ENB(tgi, gpio));
+			spin_lock_init(&bank->lvl_lock[j]);
+			spin_lock_init(&bank->dbc_lock[j]);
 		}
 	}
 
 	ret = devm_gpiochip_add_data(&pdev->dev, &tgi->gc, tgi);
-	if (ret < 0) {
-		irq_domain_remove(tgi->irq_domain);
+	if (ret < 0)
 		return ret;
-	}
-
-	for (gpio = 0; gpio < tgi->gc.ngpio; gpio++) {
-		int irq = irq_create_mapping(tgi->irq_domain, gpio);
-		/* No validity check; all Tegra GPIOs are valid IRQs */
-
-		bank = &tgi->bank_info[GPIO_BANK(gpio)];
-
-		irq_set_lockdep_class(irq, &gpio_lock_class);
-		irq_set_chip_data(irq, bank);
-		irq_set_chip_and_handler(irq, &tgi->ic, handle_simple_irq);
-	}
-
-	for (i = 0; i < tgi->bank_count; i++) {
-		bank = &tgi->bank_info[i];
-
-		irq_set_chained_handler_and_data(bank->irq,
-						 tegra_gpio_irq_handler, bank);
-
-		for (j = 0; j < 4; j++) {
-			spin_lock_init(&bank->lvl_lock[j]);
-			spin_lock_init(&bank->dbc_lock[j]);
-		}
-	}
 
 	tegra_gpio_debuginit(tgi);
 
-- 
2.14.1

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

* [PATCH v2 15/16] gpio: tegra: Use banked GPIO infrastructure
@ 2017-09-28  9:56     ` Thierry Reding
  0 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-09-28  9:56 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

From: Thierry Reding <treding@nvidia.com>

Convert the Tegra GPIO driver to use the banked GPIO infrastructure,
which simplifies some parts of the driver.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/gpio/Kconfig      |   1 +
 drivers/gpio/gpio-tegra.c | 203 ++++++++++++++++++++++------------------------
 2 files changed, 98 insertions(+), 106 deletions(-)

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index db3e446ad9b3..458157d6d491 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -439,6 +439,7 @@ config GPIO_TEGRA
 	default ARCH_TEGRA
 	depends on ARCH_TEGRA || COMPILE_TEST
 	depends on OF_GPIO
+	select GPIOLIB_IRQCHIP
 	help
 	  Say yes here to support GPIO pins on NVIDIA Tegra SoCs.
 
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index fbaf974277df..bfa0abec743b 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -67,8 +67,8 @@
 struct tegra_gpio_info;
 
 struct tegra_gpio_bank {
-	unsigned int bank;
-	unsigned int irq;
+	struct gpio_bank bank;
+	unsigned int index;
 	spinlock_t lvl_lock[4];
 	spinlock_t dbc_lock[4];	/* Lock for updating debounce count register */
 #ifdef CONFIG_PM_SLEEP
@@ -84,6 +84,11 @@ struct tegra_gpio_bank {
 	struct tegra_gpio_info *tgi;
 };
 
+static struct tegra_gpio_bank *to_tegra_gpio_bank(struct gpio_bank *bank)
+{
+	return container_of(bank, struct tegra_gpio_bank, bank);
+}
+
 struct tegra_gpio_soc_config {
 	bool debounce_supported;
 	u32 bank_stride;
@@ -98,9 +103,14 @@ struct tegra_gpio_info {
 	const struct tegra_gpio_soc_config	*soc;
 	struct gpio_chip			gc;
 	struct irq_chip				ic;
-	u32					bank_count;
 };
 
+static inline struct tegra_gpio_info *
+to_tegra_gpio_info(struct gpio_chip *chip)
+{
+	return container_of(chip, struct tegra_gpio_info, gc);
+}
+
 static inline void tegra_gpio_writel(struct tegra_gpio_info *tgi,
 				     u32 val, u32 reg)
 {
@@ -264,8 +274,8 @@ static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
 
 static void tegra_gpio_irq_ack(struct irq_data *d)
 {
-	struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
-	struct tegra_gpio_info *tgi = bank->tgi;
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	struct tegra_gpio_info *tgi = to_tegra_gpio_info(chip);
 	unsigned int gpio = d->hwirq;
 
 	tegra_gpio_writel(tgi, 1 << GPIO_BIT(gpio), GPIO_INT_CLR(tgi, gpio));
@@ -273,8 +283,8 @@ static void tegra_gpio_irq_ack(struct irq_data *d)
 
 static void tegra_gpio_irq_mask(struct irq_data *d)
 {
-	struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
-	struct tegra_gpio_info *tgi = bank->tgi;
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	struct tegra_gpio_info *tgi = to_tegra_gpio_info(chip);
 	unsigned int gpio = d->hwirq;
 
 	tegra_gpio_mask_write(tgi, GPIO_MSK_INT_ENB(tgi, gpio), gpio, 0);
@@ -282,8 +292,8 @@ static void tegra_gpio_irq_mask(struct irq_data *d)
 
 static void tegra_gpio_irq_unmask(struct irq_data *d)
 {
-	struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
-	struct tegra_gpio_info *tgi = bank->tgi;
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	struct tegra_gpio_info *tgi = to_tegra_gpio_info(chip);
 	unsigned int gpio = d->hwirq;
 
 	tegra_gpio_mask_write(tgi, GPIO_MSK_INT_ENB(tgi, gpio), gpio, 1);
@@ -292,12 +302,15 @@ static void tegra_gpio_irq_unmask(struct irq_data *d)
 static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 {
 	unsigned int gpio = d->hwirq, port = GPIO_PORT(gpio), lvl_type;
-	struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
-	struct tegra_gpio_info *tgi = bank->tgi;
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	struct tegra_gpio_info *tgi = to_tegra_gpio_info(chip);
+	struct tegra_gpio_bank *bank;
 	unsigned long flags;
 	u32 val;
 	int ret;
 
+	bank = &tgi->bank_info[GPIO_BANK(gpio)];
+
 	switch (type & IRQ_TYPE_SENSE_MASK) {
 	case IRQ_TYPE_EDGE_RISING:
 		lvl_type = GPIO_INT_LVL_EDGE_RISING;
@@ -352,52 +365,27 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 
 static void tegra_gpio_irq_shutdown(struct irq_data *d)
 {
-	struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
-	struct tegra_gpio_info *tgi = bank->tgi;
-	unsigned int gpio = d->hwirq;
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
 
-	gpiochip_unlock_as_irq(&tgi->gc, gpio);
+	gpiochip_unlock_as_irq(chip, d->hwirq);
 }
 
-static void tegra_gpio_irq_handler(struct irq_desc *desc)
+static void tegra_gpio_update_bank(struct gpio_bank *bank)
 {
-	unsigned int port, pin, gpio;
-	bool unmasked = false;
-	u32 lvl;
-	unsigned long sta;
-	struct irq_chip *chip = irq_desc_get_chip(desc);
-	struct tegra_gpio_bank *bank = irq_desc_get_handler_data(desc);
-	struct tegra_gpio_info *tgi = bank->tgi;
-
-	chained_irq_enter(chip, desc);
+	struct tegra_gpio_info *tgi = to_tegra_gpio_info(bank->chip);
+	struct tegra_gpio_bank *b = to_tegra_gpio_bank(bank);
+	unsigned int port;
 
 	for (port = 0; port < 4; port++) {
-		gpio = tegra_gpio_compose(bank->bank, port, 0);
-		sta = tegra_gpio_readl(tgi, GPIO_INT_STA(tgi, gpio)) &
-			tegra_gpio_readl(tgi, GPIO_INT_ENB(tgi, gpio));
-		lvl = tegra_gpio_readl(tgi, GPIO_INT_LVL(tgi, gpio));
-
-		for_each_set_bit(pin, &sta, 8) {
-			tegra_gpio_writel(tgi, 1 << pin,
-					  GPIO_INT_CLR(tgi, gpio));
-
-			/* if gpio is edge triggered, clear condition
-			 * before executing the handler so that we don't
-			 * miss edges
-			 */
-			if (!unmasked && lvl & (0x100 << pin)) {
-				unmasked = true;
-				chained_irq_exit(chip, desc);
-			}
+		unsigned int gpio = tegra_gpio_compose(b->index, port, 0);
+		u8 *pending = (u8 *)bank->pending;
+		u32 status, enable;
 
-			generic_handle_irq(irq_find_mapping(tgi->irq_domain,
-							    gpio + pin));
-		}
-	}
-
-	if (!unmasked)
-		chained_irq_exit(chip, desc);
+		status = tegra_gpio_readl(tgi, GPIO_INT_STA(tgi, gpio));
+		enable = tegra_gpio_readl(tgi, GPIO_INT_ENB(tgi, gpio));
 
+		pending[port] = status & enable;
+	}
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -410,7 +398,7 @@ static int tegra_gpio_resume(struct device *dev)
 
 	local_irq_save(flags);
 
-	for (b = 0; b < tgi->bank_count; b++) {
+	for (b = 0; b < tgi->gc.num_banks; b++) {
 		struct tegra_gpio_bank *bank = &tgi->bank_info[b];
 
 		for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
@@ -449,7 +437,7 @@ static int tegra_gpio_suspend(struct device *dev)
 	unsigned int b, p;
 
 	local_irq_save(flags);
-	for (b = 0; b < tgi->bank_count; b++) {
+	for (b = 0; b < tgi->gc.num_banks; b++) {
 		struct tegra_gpio_bank *bank = &tgi->bank_info[b];
 
 		for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
@@ -484,20 +472,26 @@ static int tegra_gpio_suspend(struct device *dev)
 
 static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable)
 {
-	struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
-	unsigned int gpio = d->hwirq;
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	unsigned int gpio = d->hwirq, parent_irq;
+	struct tegra_gpio_bank *b;
+	struct gpio_bank *bank;
 	u32 port, bit, mask;
 
+	bank = chip->banks[GPIO_BANK(gpio)];
+	b = to_tegra_gpio_bank(bank);
 	port = GPIO_PORT(gpio);
 	bit = GPIO_BIT(gpio);
 	mask = BIT(bit);
 
 	if (enable)
-		bank->wake_enb[port] |= mask;
+		b->wake_enb[port] |= mask;
 	else
-		bank->wake_enb[port] &= ~mask;
+		b->wake_enb[port] &= ~mask;
+
+	parent_irq = chip->irq.parents[bank->parent_irq];
 
-	return irq_set_irq_wake(bank->irq, enable);
+	return irq_set_irq_wake(parent_irq, enable);
 }
 #endif
 
@@ -511,7 +505,7 @@ static int dbg_gpio_show(struct seq_file *s, void *unused)
 	struct tegra_gpio_info *tgi = s->private;
 	unsigned int i, j;
 
-	for (i = 0; i < tgi->bank_count; i++) {
+	for (i = 0; i < tgi->gc.num_banks; i++) {
 		for (j = 0; j < 4; j++) {
 			unsigned int gpio = tegra_gpio_compose(i, j, 0);
 
@@ -561,17 +555,18 @@ static const struct dev_pm_ops tegra_gpio_pm_ops = {
 };
 
 /*
- * This lock class tells lockdep that GPIO irqs are in a different category
+ * This lock class tells lockdep that GPIO IRQs are in a different category
  * than their parents, so it won't report false recursion.
  */
-static struct lock_class_key gpio_lock_class;
+static struct lock_class_key tegra_gpio_lock_class;
 
 static int tegra_gpio_probe(struct platform_device *pdev)
 {
 	struct tegra_gpio_info *tgi;
 	struct resource *res;
 	struct tegra_gpio_bank *bank;
-	unsigned int gpio, i, j;
+	struct gpio_irq_chip *irq;
+	unsigned int i, j;
 	int ret;
 
 	tgi = devm_kzalloc(&pdev->dev, sizeof(*tgi), GFP_KERNEL);
@@ -580,14 +575,20 @@ static int tegra_gpio_probe(struct platform_device *pdev)
 
 	tgi->soc = of_device_get_match_data(&pdev->dev);
 	tgi->dev = &pdev->dev;
+	irq = &tgi->gc.irq;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	tgi->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(tgi->regs))
+		return PTR_ERR(tgi->regs);
 
 	ret = platform_irq_count(pdev);
 	if (ret < 0)
 		return ret;
 
-	tgi->bank_count = ret;
+	tgi->gc.num_banks = ret;
 
-	if (!tgi->bank_count) {
+	if (!tgi->gc.num_banks) {
 		dev_err(&pdev->dev, "Missing IRQ resource\n");
 		return -ENODEV;
 	}
@@ -602,7 +603,7 @@ static int tegra_gpio_probe(struct platform_device *pdev)
 	tgi->gc.get_direction		= tegra_gpio_get_direction;
 	tgi->gc.to_irq			= tegra_gpio_to_irq;
 	tgi->gc.base			= 0;
-	tgi->gc.ngpio			= tgi->bank_count * 32;
+	tgi->gc.ngpio			= tgi->gc.num_banks * 32;
 	tgi->gc.parent			= &pdev->dev;
 	tgi->gc.of_node			= pdev->dev.of_node;
 
@@ -616,76 +617,66 @@ static int tegra_gpio_probe(struct platform_device *pdev)
 	tgi->ic.irq_set_wake		= tegra_gpio_irq_set_wake;
 #endif
 
+	irq = &tgi->gc.irq;
+	irq->chip = &tgi->ic;
+	irq->handler = handle_simple_irq;
+	irq->lock_key = &tegra_gpio_lock_class;
+	irq->default_type = IRQ_TYPE_NONE;
+	irq->parent_handler = gpio_irq_chip_banked_chained_handler;
+	irq->update_bank = tegra_gpio_update_bank;
+
+	irq->parents = devm_kcalloc(&pdev->dev, tgi->gc.num_banks,
+				    sizeof(unsigned int), GFP_KERNEL);
+	if (!irq->parents)
+		return -ENOMEM;
+
+	irq->num_parents = tgi->gc.num_banks;
+
 	platform_set_drvdata(pdev, tgi);
 
 	if (tgi->soc->debounce_supported)
 		tgi->gc.set_config = tegra_gpio_set_config;
 
-	tgi->bank_info = devm_kcalloc(&pdev->dev, tgi->bank_count,
+	tgi->bank_info = devm_kcalloc(&pdev->dev, tgi->gc.num_banks,
 				      sizeof(*tgi->bank_info), GFP_KERNEL);
 	if (!tgi->bank_info)
 		return -ENOMEM;
 
-	tgi->irq_domain = irq_domain_add_linear(pdev->dev.of_node,
-						tgi->gc.ngpio,
-						&irq_domain_simple_ops, NULL);
-	if (!tgi->irq_domain)
-		return -ENODEV;
+	tgi->gc.banks = devm_kcalloc(&pdev->dev, tgi->gc.num_banks,
+				     sizeof(struct gpio_bank *),
+				     GFP_KERNEL);
+	if (!tgi->gc.banks)
+		return -ENOMEM;
 
-	for (i = 0; i < tgi->bank_count; i++) {
+	for (i = 0; i < tgi->gc.num_banks; i++) {
 		ret = platform_get_irq(pdev, i);
 		if (ret < 0) {
 			dev_err(&pdev->dev, "Missing IRQ resource: %d\n", ret);
 			return ret;
 		}
 
+		irq->parents[i] = ret;
+
 		bank = &tgi->bank_info[i];
-		bank->bank = i;
-		bank->irq = ret;
-		bank->tgi = tgi;
-	}
+		bank->bank.chip = &tgi->gc;
+		bank->bank.parent_irq = i;
+		bank->bank.num_lines = 32;
+		bank->index = i;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	tgi->regs = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(tgi->regs))
-		return PTR_ERR(tgi->regs);
+		tgi->gc.banks[i] = &bank->bank;
 
-	for (i = 0; i < tgi->bank_count; i++) {
 		for (j = 0; j < 4; j++) {
-			int gpio = tegra_gpio_compose(i, j, 0);
+			unsigned int gpio = tegra_gpio_compose(i, j, 0);
 
 			tegra_gpio_writel(tgi, 0x00, GPIO_INT_ENB(tgi, gpio));
+			spin_lock_init(&bank->lvl_lock[j]);
+			spin_lock_init(&bank->dbc_lock[j]);
 		}
 	}
 
 	ret = devm_gpiochip_add_data(&pdev->dev, &tgi->gc, tgi);
-	if (ret < 0) {
-		irq_domain_remove(tgi->irq_domain);
+	if (ret < 0)
 		return ret;
-	}
-
-	for (gpio = 0; gpio < tgi->gc.ngpio; gpio++) {
-		int irq = irq_create_mapping(tgi->irq_domain, gpio);
-		/* No validity check; all Tegra GPIOs are valid IRQs */
-
-		bank = &tgi->bank_info[GPIO_BANK(gpio)];
-
-		irq_set_lockdep_class(irq, &gpio_lock_class);
-		irq_set_chip_data(irq, bank);
-		irq_set_chip_and_handler(irq, &tgi->ic, handle_simple_irq);
-	}
-
-	for (i = 0; i < tgi->bank_count; i++) {
-		bank = &tgi->bank_info[i];
-
-		irq_set_chained_handler_and_data(bank->irq,
-						 tegra_gpio_irq_handler, bank);
-
-		for (j = 0; j < 4; j++) {
-			spin_lock_init(&bank->lvl_lock[j]);
-			spin_lock_init(&bank->dbc_lock[j]);
-		}
-	}
 
 	tegra_gpio_debuginit(tgi);
 
-- 
2.14.1

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

* [PATCH v2 16/16] gpio: tegra186: Use banked GPIO infrastructure
  2017-09-28  9:56 ` Thierry Reding
                   ` (11 preceding siblings ...)
  (?)
@ 2017-09-28  9:56 ` Thierry Reding
  -1 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-09-28  9:56 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

From: Thierry Reding <treding@nvidia.com>

Convert the Tegra186 GPIO driver to use the banked GPIO infrastructure,
which simplifies some parts of the driver.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/gpio/gpio-tegra186.c | 211 ++++++++++++++++---------------------------
 1 file changed, 79 insertions(+), 132 deletions(-)

diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c
index 162dc6b41ae8..7da8e5248d15 100644
--- a/drivers/gpio/gpio-tegra186.c
+++ b/drivers/gpio/gpio-tegra186.c
@@ -13,6 +13,7 @@
 #include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
+#include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 
 #include <dt-bindings/gpio/tegra186-gpio.h>
@@ -44,15 +45,27 @@
 
 #define TEGRA186_GPIO_INTERRUPT_STATUS(x) (0x100 + (x) * 4)
 
-struct tegra_gpio_port {
+struct tegra_gpio_port_soc {
 	const char *name;
 	unsigned int offset;
 	unsigned int pins;
 	unsigned int irq;
 };
 
+struct tegra_gpio_port {
+	struct gpio_bank bank;
+	unsigned int offset;
+	const char *name;
+};
+
+static inline struct tegra_gpio_port *
+to_tegra_gpio_port(struct gpio_bank *bank)
+{
+	return container_of(bank, struct tegra_gpio_port, bank);
+}
+
 struct tegra_gpio_soc {
-	const struct tegra_gpio_port *ports;
+	const struct tegra_gpio_port_soc *ports;
 	unsigned int num_ports;
 	const char *name;
 };
@@ -60,21 +73,21 @@ struct tegra_gpio_soc {
 struct tegra_gpio {
 	struct gpio_chip gpio;
 	struct irq_chip intc;
-	unsigned int num_irq;
-	unsigned int *irq;
 
 	const struct tegra_gpio_soc *soc;
 
+	struct tegra_gpio_port *ports;
+
 	void __iomem *base;
 };
 
-static const struct tegra_gpio_port *
+static const struct tegra_gpio_port_soc *
 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];
+		const struct tegra_gpio_port_soc *port = &gpio->soc->ports[i];
 
 		if (*pin >= start && *pin < start + port->pins) {
 			*pin -= start;
@@ -90,7 +103,7 @@ tegra186_gpio_get_port(struct tegra_gpio *gpio, unsigned int *pin)
 static void __iomem *tegra186_gpio_get_base(struct tegra_gpio *gpio,
 					    unsigned int pin)
 {
-	const struct tegra_gpio_port *port;
+	const struct tegra_gpio_port_soc *port;
 
 	port = tegra186_gpio_get_port(gpio, &pin);
 	if (!port)
@@ -206,39 +219,10 @@ static void tegra186_gpio_set(struct gpio_chip *chip, unsigned int offset,
 	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);
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+	struct tegra_gpio *gpio = gpiochip_get_data(chip);
 	void __iomem *base;
 
 	base = tegra186_gpio_get_base(gpio, data->hwirq);
@@ -250,7 +234,8 @@ static void tegra186_irq_ack(struct irq_data *data)
 
 static void tegra186_irq_mask(struct irq_data *data)
 {
-	struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+	struct tegra_gpio *gpio = gpiochip_get_data(chip);
 	void __iomem *base;
 	u32 value;
 
@@ -265,7 +250,8 @@ static void tegra186_irq_mask(struct irq_data *data)
 
 static void tegra186_irq_unmask(struct irq_data *data)
 {
-	struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+	struct tegra_gpio *gpio = gpiochip_get_data(chip);
 	void __iomem *base;
 	u32 value;
 
@@ -280,7 +266,8 @@ static void tegra186_irq_unmask(struct irq_data *data)
 
 static int tegra186_irq_set_type(struct irq_data *data, unsigned int flow)
 {
-	struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+	struct tegra_gpio *gpio = gpiochip_get_data(chip);
 	void __iomem *base;
 	u32 value;
 
@@ -332,76 +319,22 @@ static int tegra186_irq_set_type(struct irq_data *data, unsigned int flow)
 	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)
+static void tegra186_gpio_update_bank(struct gpio_bank *bank)
 {
-	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;
+	struct tegra_gpio_port *port = to_tegra_gpio_port(bank);
+	struct tegra_gpio *gpio = gpiochip_get_data(bank->chip);
+	void __iomem *base = gpio->base + port->offset;
+	u32 value;
 
-	*type = spec[1] & IRQ_TYPE_SENSE_MASK;
-	*hwirq = offset + pin;
+	value = readl(base + TEGRA186_GPIO_INTERRUPT_STATUS(1));
 
-	return 0;
+	bank->pending[0] = value;
 }
 
 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,
+	.xlate = gpio_banked_irq_domain_xlate,
 };
 
 static struct lock_class_key tegra186_gpio_lock_class;
@@ -420,6 +353,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	gpio->soc = of_device_get_match_data(&pdev->dev);
+	irq = &gpio->gpio.irq;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpio");
 	gpio->base = devm_ioremap_resource(&pdev->dev, res);
@@ -430,21 +364,47 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
 	if (err < 0)
 		return err;
 
-	gpio->num_irq = err;
+	irq->num_parents = err;
 
-	gpio->irq = devm_kcalloc(&pdev->dev, gpio->num_irq, sizeof(*gpio->irq),
-				 GFP_KERNEL);
-	if (!gpio->irq)
+	irq->parents = devm_kcalloc(&pdev->dev, irq->num_parents,
+				    sizeof(*irq->parents), GFP_KERNEL);
+	if (!irq->parents)
 		return -ENOMEM;
 
-	for (i = 0; i < gpio->num_irq; i++) {
+	for (i = 0; i < irq->num_parents; i++) {
 		err = platform_get_irq(pdev, i);
 		if (err < 0)
 			return err;
 
-		gpio->irq[i] = err;
+		irq->parents[i] = err;
 	}
 
+	gpio->ports = devm_kcalloc(&pdev->dev, gpio->soc->num_ports,
+				   sizeof(struct tegra_gpio_port),
+				   GFP_KERNEL);
+	if (!gpio->ports)
+		return -ENOMEM;
+
+	gpio->gpio.banks = devm_kcalloc(&pdev->dev, gpio->soc->num_ports,
+					sizeof(struct gpio_bank *),
+					GFP_KERNEL);
+	if (!gpio->gpio.banks)
+		return -ENOMEM;
+
+	for (i = 0; i < gpio->soc->num_ports; i++) {
+		const struct tegra_gpio_port_soc *soc = &gpio->soc->ports[i];
+		struct tegra_gpio_port *port = &gpio->ports[i];
+
+		gpio->gpio.banks[i] = &port->bank;
+		port->bank.parent_irq = soc->irq;
+		port->bank.num_lines = soc->pins;
+
+		port->offset = soc->offset;
+		port->name = soc->name;
+	}
+
+	gpio->gpio.num_banks = gpio->soc->num_ports;
+
 	gpio->gpio.label = gpio->soc->name;
 	gpio->gpio.parent = &pdev->dev;
 
@@ -465,7 +425,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	for (i = 0, offset = 0; i < gpio->soc->num_ports; i++) {
-		const struct tegra_gpio_port *port = &gpio->soc->ports[i];
+		const struct tegra_gpio_port_soc *port = &gpio->soc->ports[i];
 		char *name;
 
 		for (j = 0; j < port->pins; j++) {
@@ -484,7 +444,11 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
 
 	gpio->gpio.of_node = pdev->dev.of_node;
 	gpio->gpio.of_gpio_n_cells = 2;
-	gpio->gpio.of_xlate = tegra186_gpio_of_xlate;
+	gpio->gpio.of_gpio_bank_shift = 3;
+	gpio->gpio.of_gpio_bank_mask = 0x1fffffff;
+	gpio->gpio.of_gpio_line_shift = 0;
+	gpio->gpio.of_gpio_line_mask = 0x7;
+	gpio->gpio.of_xlate = of_gpio_banked_xlate;
 
 	gpio->intc.name = pdev->dev.of_node->name;
 	gpio->intc.irq_ack = tegra186_irq_ack;
@@ -492,31 +456,14 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
 	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;
-	}
+	irq->parent_handler = gpio_irq_chip_banked_chained_handler;
+	irq->update_bank = tegra186_gpio_update_bank;
 
 	platform_set_drvdata(pdev, gpio);
 
@@ -540,7 +487,7 @@ static int tegra186_gpio_remove(struct platform_device *pdev)
 		.irq = controller,				\
 	}
 
-static const struct tegra_gpio_port tegra186_main_ports[] = {
+static const struct tegra_gpio_port_soc 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),
@@ -580,7 +527,7 @@ static const struct tegra_gpio_soc tegra186_main_soc = {
 		.irq = controller,				\
 	}
 
-static const struct tegra_gpio_port tegra186_aon_ports[] = {
+static const struct tegra_gpio_port_soc 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),
-- 
2.14.1

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

* Re: [PATCH v2 00/16] gpio: Tight IRQ chip integration and banked infrastructure
  2017-09-28  9:56 ` Thierry Reding
@ 2017-09-28 14:22     ` Grygorii Strashko
  -1 siblings, 0 replies; 56+ messages in thread
From: Grygorii Strashko @ 2017-09-28 14:22 UTC (permalink / raw)
  To: Thierry Reding, Linus Walleij
  Cc: Jonathan Hunter, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA



On 09/28/2017 04:56 AM, Thierry Reding wrote:
> From: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> 
> Hi Linus,
> 
> here's the latest series of patches that implement the tighter IRQ chip
> integration as well as the banked GPIO infrastructure that we had
> discussed a couple of weeks/months back.
> 
> The first couple of patches are mostly preparatory work in order to
> consolidate all IRQ chip related fields in a new structure and create
> the base functionality for adding IRQ chips.
> 
> After that, I've added the Tegra186 GPIO support patch that makes use of
> the new tight integration.
> 
> To round things off the new banked GPIO infrastructure is added (along
> with some more preparatory work), followed by the conversion of the two
> Tegra GPIO drivers to the new infrastructure.

Hm. So you've ignored my comments [1].

Sry, but I do not agree with this series.
- no prof that it can be re-used by other drivers than tegra
 (at least I do not see reasons to re-use it for any TI drivers)
- no split
- all GPIO IRQs mapped statically
- irq->map[offset + j] = irq->parents[parent]; holds IRQs for all pins
  which is waste of memory
- DT binding changes not documented and no DT examples
- below is ugly ;)
+	bank = (spec[0] >> gc->of_gpio_bank_mask) & gc->of_gpio_bank_shift;
+	pin = (spec[0] >> gc->of_gpio_pin_mask) & gc->of_gpio_pin_shift;

[1] https://lkml.org/lkml/2017/9/15/442

> 
> Changes in v2:
> - rename pins to lines for consistent terminology
> - rename gpio_irq_chip_banked_handler() to
>    gpio_irq_chip_banked_chained_handler()
> 
> Thierry
> 
> Thierry Reding (16):
>    gpio: Implement tighter IRQ chip integration
>    gpio: Move irqchip into struct gpio_irq_chip
>    gpio: Move irqdomain into struct gpio_irq_chip
>    gpio: Move irq_base to struct gpio_irq_chip
>    gpio: Move irq_handler to struct gpio_irq_chip
>    gpio: Move irq_default_type to struct gpio_irq_chip
>    gpio: Move irq_chained_parent to struct gpio_irq_chip
>    gpio: Move irq_nested 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: Add Tegra186 support
>    gpio: omap: Fix checkpatch warnings
>    gpio: omap: Rename struct gpio_bank to struct omap_gpio_bank
>    gpio: Add support for banked GPIO controllers
>    gpio: tegra: Use banked GPIO infrastructure
>    gpio: tegra186: Use banked GPIO infrastructure
> 
>   Documentation/gpio/driver.txt               |   6 +-
>   drivers/bcma/driver_gpio.c                  |   2 +-
>   drivers/gpio/Kconfig                        |  10 +
>   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-ingenic.c                 |   2 +-
>   drivers/gpio/gpio-intel-mid.c               |   2 +-
>   drivers/gpio/gpio-lynxpoint.c               |   2 +-
>   drivers/gpio/gpio-max732x.c                 |   2 +-
>   drivers/gpio/gpio-merrifield.c              |   2 +-
>   drivers/gpio/gpio-omap.c                    | 222 ++++++-----
>   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-tegra.c                   | 203 +++++-----
>   drivers/gpio/gpio-tegra186.c                | 571 ++++++++++++++++++++++++++++
>   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-of.c                   | 101 +++++
>   drivers/gpio/gpiolib.c                      | 320 ++++++++++++++--
>   drivers/pinctrl/bcm/pinctrl-bcm2835.c       |   5 +-
>   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/mvebu/pinctrl-armada-37xx.c |   4 +-
>   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-mcp23s08.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 +-
>   drivers/platform/x86/intel_int0002_vgpio.c  |   6 +-
>   include/linux/gpio/driver.h                 | 272 +++++++++++--
>   include/linux/of_gpio.h                     |  10 +
>   63 files changed, 1505 insertions(+), 348 deletions(-)
>   create mode 100644 drivers/gpio/gpio-tegra186.c
> 

-- 
regards,
-grygorii

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

* Re: [PATCH v2 00/16] gpio: Tight IRQ chip integration and banked infrastructure
@ 2017-09-28 14:22     ` Grygorii Strashko
  0 siblings, 0 replies; 56+ messages in thread
From: Grygorii Strashko @ 2017-09-28 14:22 UTC (permalink / raw)
  To: Thierry Reding, Linus Walleij
  Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel



On 09/28/2017 04:56 AM, Thierry Reding wrote:
> From: Thierry Reding <treding@nvidia.com>
> 
> Hi Linus,
> 
> here's the latest series of patches that implement the tighter IRQ chip
> integration as well as the banked GPIO infrastructure that we had
> discussed a couple of weeks/months back.
> 
> The first couple of patches are mostly preparatory work in order to
> consolidate all IRQ chip related fields in a new structure and create
> the base functionality for adding IRQ chips.
> 
> After that, I've added the Tegra186 GPIO support patch that makes use of
> the new tight integration.
> 
> To round things off the new banked GPIO infrastructure is added (along
> with some more preparatory work), followed by the conversion of the two
> Tegra GPIO drivers to the new infrastructure.

Hm. So you've ignored my comments [1].

Sry, but I do not agree with this series.
- no prof that it can be re-used by other drivers than tegra
 (at least I do not see reasons to re-use it for any TI drivers)
- no split
- all GPIO IRQs mapped statically
- irq->map[offset + j] = irq->parents[parent]; holds IRQs for all pins
  which is waste of memory
- DT binding changes not documented and no DT examples
- below is ugly ;)
+	bank = (spec[0] >> gc->of_gpio_bank_mask) & gc->of_gpio_bank_shift;
+	pin = (spec[0] >> gc->of_gpio_pin_mask) & gc->of_gpio_pin_shift;

[1] https://lkml.org/lkml/2017/9/15/442

> 
> Changes in v2:
> - rename pins to lines for consistent terminology
> - rename gpio_irq_chip_banked_handler() to
>    gpio_irq_chip_banked_chained_handler()
> 
> Thierry
> 
> Thierry Reding (16):
>    gpio: Implement tighter IRQ chip integration
>    gpio: Move irqchip into struct gpio_irq_chip
>    gpio: Move irqdomain into struct gpio_irq_chip
>    gpio: Move irq_base to struct gpio_irq_chip
>    gpio: Move irq_handler to struct gpio_irq_chip
>    gpio: Move irq_default_type to struct gpio_irq_chip
>    gpio: Move irq_chained_parent to struct gpio_irq_chip
>    gpio: Move irq_nested 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: Add Tegra186 support
>    gpio: omap: Fix checkpatch warnings
>    gpio: omap: Rename struct gpio_bank to struct omap_gpio_bank
>    gpio: Add support for banked GPIO controllers
>    gpio: tegra: Use banked GPIO infrastructure
>    gpio: tegra186: Use banked GPIO infrastructure
> 
>   Documentation/gpio/driver.txt               |   6 +-
>   drivers/bcma/driver_gpio.c                  |   2 +-
>   drivers/gpio/Kconfig                        |  10 +
>   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-ingenic.c                 |   2 +-
>   drivers/gpio/gpio-intel-mid.c               |   2 +-
>   drivers/gpio/gpio-lynxpoint.c               |   2 +-
>   drivers/gpio/gpio-max732x.c                 |   2 +-
>   drivers/gpio/gpio-merrifield.c              |   2 +-
>   drivers/gpio/gpio-omap.c                    | 222 ++++++-----
>   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-tegra.c                   | 203 +++++-----
>   drivers/gpio/gpio-tegra186.c                | 571 ++++++++++++++++++++++++++++
>   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-of.c                   | 101 +++++
>   drivers/gpio/gpiolib.c                      | 320 ++++++++++++++--
>   drivers/pinctrl/bcm/pinctrl-bcm2835.c       |   5 +-
>   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/mvebu/pinctrl-armada-37xx.c |   4 +-
>   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-mcp23s08.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 +-
>   drivers/platform/x86/intel_int0002_vgpio.c  |   6 +-
>   include/linux/gpio/driver.h                 | 272 +++++++++++--
>   include/linux/of_gpio.h                     |  10 +
>   63 files changed, 1505 insertions(+), 348 deletions(-)
>   create mode 100644 drivers/gpio/gpio-tegra186.c
> 

-- 
regards,
-grygorii

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

* Re: [PATCH v2 01/16] gpio: Implement tighter IRQ chip integration
  2017-09-28  9:56 ` [PATCH v2 01/16] gpio: Implement tighter IRQ chip integration Thierry Reding
@ 2017-09-28 14:22       ` Grygorii Strashko
  0 siblings, 0 replies; 56+ messages in thread
From: Grygorii Strashko @ 2017-09-28 14:22 UTC (permalink / raw)
  To: Thierry Reding, Linus Walleij
  Cc: Jonathan Hunter, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA



On 09/28/2017 04:56 AM, Thierry Reding wrote:
> From: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> 
> 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-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> ---
>   drivers/gpio/gpiolib.c      | 146 +++++++++++++++++++++++++++++++++++++++++++-
>   include/linux/gpio/driver.h |  64 +++++++++++++++++++
>   2 files changed, 207 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> index eb80dac4e26a..b34d9cbd5809 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);
> @@ -1260,6 +1261,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;
> @@ -1626,8 +1631,8 @@ 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;
>   
> @@ -1655,8 +1660,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;
>   
> @@ -1665,6 +1671,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,
> @@ -1705,6 +1712,124 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
>   	return irq_create_mapping(chip->irqdomain, 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->irqchip;
> +	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->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_base,
> +						    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]);

IRQs should be mapped dynamically.
Pls, see commit dc749a0 "gpiolib: allow gpio irqchip to map irqs dynamically"

> +	}
> +
> +	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
> @@ -1722,6 +1847,16 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
>   		irq_set_handler_data(gpiochip->irq_chained_parent, NULL);
>   	}
>   
> +	if (gpiochip->irqchip) {
> +		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++) {
> @@ -1842,6 +1977,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 c97f8325e8bf..6100b171817e 100644
> --- a/include/linux/gpio/driver.h
> +++ b/include/linux/gpio/driver.h
> @@ -19,6 +19,58 @@ struct module;
>   
>   #ifdef CONFIG_GPIOLIB
>   
> +#ifdef CONFIG_GPIOLIB_IRQCHIP
> +/**
> + * struct gpio_irq_chip - GPIO interrupt controller
> + */
> +struct gpio_irq_chip {
> +	/**
> +	 * @domain_ops:
> +	 *
> +	 * Table of interrupt domain operations for this IRQ chip.
> +	 */
> +	const struct irq_domain_ops *domain_ops;
> +
> +	/**
> +	 * @parent_handler:
> +	 *
> +	 * The interrupt handler for the GPIO chip's parent interrupts, may be
> +	 * NULL if the parent interrupts are nested rather than cascaded.
> +	 */
> +	irq_flow_handler_t parent_handler;
> +
> +	/**
> +	 * @parent_handler_data:
> +	 *
> +	 * Data associated, and passed to, the handler for the parent
> +	 * interrupt.
> +	 */
> +	void *parent_handler_data;
> +
> +	/**
> +	 * @num_parents:
> +	 *
> +	 * The number of interrupt parents of a GPIO chip.
> +	 */
> +	unsigned int num_parents;
> +
> +	/**
> +	 * @parents:
> +	 *
> +	 * A list of interrupt parents of a GPIO chip. This is owned by the
> +	 * driver, so the core will only reference this list, not modify it.
> +	 */
> +	unsigned int *parents;
> +
> +	/**
> +	 * @map:
> +	 *
> +	 * A list of interrupt parents for each line of a GPIO chip.
> +	 */
> +	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 +225,14 @@ struct gpio_chip {
>   	bool			irq_need_valid_mask;
>   	unsigned long		*irq_valid_mask;
>   	struct lock_class_key	*lock_key;
> +
> +	/**
> +	 * @irq:
> +	 *
> +	 * Integrates interrupt chip functionality with the GPIO chip. Can be
> +	 * used to handle IRQs for most practical cases.
> +	 */
> +	struct gpio_irq_chip irq;
>   #endif
>   
>   #if defined(CONFIG_OF_GPIO)
> @@ -264,6 +324,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,
> 

-- 
regards,
-grygorii

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

* Re: [PATCH v2 01/16] gpio: Implement tighter IRQ chip integration
@ 2017-09-28 14:22       ` Grygorii Strashko
  0 siblings, 0 replies; 56+ messages in thread
From: Grygorii Strashko @ 2017-09-28 14:22 UTC (permalink / raw)
  To: Thierry Reding, Linus Walleij
  Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel



On 09/28/2017 04:56 AM, Thierry Reding wrote:
> 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      | 146 +++++++++++++++++++++++++++++++++++++++++++-
>   include/linux/gpio/driver.h |  64 +++++++++++++++++++
>   2 files changed, 207 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> index eb80dac4e26a..b34d9cbd5809 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);
> @@ -1260,6 +1261,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;
> @@ -1626,8 +1631,8 @@ 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;
>   
> @@ -1655,8 +1660,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;
>   
> @@ -1665,6 +1671,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,
> @@ -1705,6 +1712,124 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
>   	return irq_create_mapping(chip->irqdomain, 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->irqchip;
> +	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->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_base,
> +						    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]);

IRQs should be mapped dynamically.
Pls, see commit dc749a0 "gpiolib: allow gpio irqchip to map irqs dynamically"

> +	}
> +
> +	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
> @@ -1722,6 +1847,16 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
>   		irq_set_handler_data(gpiochip->irq_chained_parent, NULL);
>   	}
>   
> +	if (gpiochip->irqchip) {
> +		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++) {
> @@ -1842,6 +1977,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 c97f8325e8bf..6100b171817e 100644
> --- a/include/linux/gpio/driver.h
> +++ b/include/linux/gpio/driver.h
> @@ -19,6 +19,58 @@ struct module;
>   
>   #ifdef CONFIG_GPIOLIB
>   
> +#ifdef CONFIG_GPIOLIB_IRQCHIP
> +/**
> + * struct gpio_irq_chip - GPIO interrupt controller
> + */
> +struct gpio_irq_chip {
> +	/**
> +	 * @domain_ops:
> +	 *
> +	 * Table of interrupt domain operations for this IRQ chip.
> +	 */
> +	const struct irq_domain_ops *domain_ops;
> +
> +	/**
> +	 * @parent_handler:
> +	 *
> +	 * The interrupt handler for the GPIO chip's parent interrupts, may be
> +	 * NULL if the parent interrupts are nested rather than cascaded.
> +	 */
> +	irq_flow_handler_t parent_handler;
> +
> +	/**
> +	 * @parent_handler_data:
> +	 *
> +	 * Data associated, and passed to, the handler for the parent
> +	 * interrupt.
> +	 */
> +	void *parent_handler_data;
> +
> +	/**
> +	 * @num_parents:
> +	 *
> +	 * The number of interrupt parents of a GPIO chip.
> +	 */
> +	unsigned int num_parents;
> +
> +	/**
> +	 * @parents:
> +	 *
> +	 * A list of interrupt parents of a GPIO chip. This is owned by the
> +	 * driver, so the core will only reference this list, not modify it.
> +	 */
> +	unsigned int *parents;
> +
> +	/**
> +	 * @map:
> +	 *
> +	 * A list of interrupt parents for each line of a GPIO chip.
> +	 */
> +	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 +225,14 @@ struct gpio_chip {
>   	bool			irq_need_valid_mask;
>   	unsigned long		*irq_valid_mask;
>   	struct lock_class_key	*lock_key;
> +
> +	/**
> +	 * @irq:
> +	 *
> +	 * Integrates interrupt chip functionality with the GPIO chip. Can be
> +	 * used to handle IRQs for most practical cases.
> +	 */
> +	struct gpio_irq_chip irq;
>   #endif
>   
>   #if defined(CONFIG_OF_GPIO)
> @@ -264,6 +324,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,
> 

-- 
regards,
-grygorii

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

* Re: [PATCH v2 00/16] gpio: Tight IRQ chip integration and banked infrastructure
  2017-09-28 14:22     ` Grygorii Strashko
  (?)
@ 2017-10-02  7:55     ` Linus Walleij
       [not found]       ` <CACRpkdagAxotP=VZr1NUvmNmHgACfr4x2aHkh=nyyEhUWWgzPw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  -1 siblings, 1 reply; 56+ messages in thread
From: Linus Walleij @ 2017-10-02  7:55 UTC (permalink / raw)
  To: Grygorii Strashko, Andrew Bresticker, James Hogan, Shawn Guo
  Cc: Thierry Reding, Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

On Thu, Sep 28, 2017 at 4:22 PM, Grygorii Strashko
<grygorii.strashko@ti.com> wrote:

> Sry, but I do not agree with this series.
> - no prof that it can be re-used by other drivers than tegra
>  (at least I do not see reasons to re-use it for any TI drivers)

This is not necessarily a blocker if it can be shown that others than
TI/OMAP can reuse it.

I've looked at things like the imagination pistachio:

pinctrl@18101C00 {
        compatible = "img,pistachio-system-pinctrl";
        reg = <0x18101C00 0x400>;

        gpio0: gpio0 {
                interrupts = <GIC_SHARED 71 IRQ_TYPE_LEVEL_HIGH>;

                gpio-controller;
                #gpio-cells = <2>;

                interrupt-controller;
                #interrupt-cells = <2>;
        };

        ...

        gpio5: gpio5 {
                interrupts = <GIC_SHARED 76 IRQ_TYPE_LEVEL_HIGH>;

                gpio-controller;
                #gpio-cells = <2>;

                interrupt-controller;
                #interrupt-cells = <2>;
        };

This looks like a clear candidate.
CC: to  Andrew Bresticker, can you look into this?

Another example would be gpio-tz1090, notably with interrupt optional:

       gpios: gpio-controller@02005800 {
                #address-cells = <1>;
                #size-cells = <0>;
                compatible = "img,tz1090-gpio";
                reg = <0x02005800 0x90>;

                /* bank 0 with an interrupt */
                gpios0: bank@0 {
                        #gpio-cells = <2>;
                        #interrupt-cells = <2>;
                        reg = <0>;
                        interrupts = <13 IRQ_TYPE_LEVEL_HIGH>;
                        gpio-controller;
                        gpio-ranges = <&pinctrl 0 0 30>;
                        interrupt-controller;
                };

                /* bank 2 without interrupt */
                gpios2: bank@2 {
                        #gpio-cells = <2>;
                        reg = <2>;
                        gpio-controller;
                        gpio-ranges = <&pinctrl 0 60 30>;
                };
        };

CC to James Hogan to look at the series from this perspective.

A third is gpio-mxs.c:

pinctrl@80018000 {
        compatible = "fsl,imx28-pinctrl", "simple-bus";
        reg = <0x80018000 2000>;

        gpio0: gpio@0 {
                compatible = "fsl,imx28-gpio";
                interrupts = <127>;
                gpio-controller;
                #gpio-cells = <2>;
                interrupt-controller;
                #interrupt-cells = <2>;
        };

        gpio1: gpio@1 {
                compatible = "fsl,imx28-gpio";
                interrupts = <126>;
                gpio-controller;
                #gpio-cells = <2>;
                interrupt-controller;
                #interrupt-cells = <2>;
        };

        gpio2: gpio@2 {
                compatible = "fsl,imx28-gpio";
                interrupts = <125>;
                gpio-controller;
                #gpio-cells = <2>;
                interrupt-controller;
                #interrupt-cells = <2>;
        };
(...)

CC to Shawn Guo to look into this.

So in short I think there can be others that can make good use of this
infrastructure.

> - all GPIO IRQs mapped statically

This really needs to be fixed.

> - irq->map[offset + j] = irq->parents[parent]; holds IRQs for all pins
>   which is waste of memory
> - DT binding changes not documented and no DT examples
> - below is ugly ;)
> +       bank = (spec[0] >> gc->of_gpio_bank_mask) & gc->of_gpio_bank_shift;
> +       pin = (spec[0] >> gc->of_gpio_pin_mask) & gc->of_gpio_pin_shift;

These should be fixable quite easily I think. Thierry?

Yours,
Linus Walleij

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

* Re: [PATCH v2 00/16] gpio: Tight IRQ chip integration and banked infrastructure
  2017-10-02  7:55     ` Linus Walleij
@ 2017-10-03 18:26           ` Grygorii Strashko
  0 siblings, 0 replies; 56+ messages in thread
From: Grygorii Strashko @ 2017-10-03 18:26 UTC (permalink / raw)
  To: Linus Walleij, Andrew Bresticker, James Hogan, Shawn Guo
  Cc: Thierry Reding, Jonathan Hunter,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA



On 10/02/2017 02:55 AM, Linus Walleij wrote:
> On Thu, Sep 28, 2017 at 4:22 PM, Grygorii Strashko
> <grygorii.strashko-l0cyMroinI0@public.gmane.org> wrote:
> 
>> Sry, but I do not agree with this series.
>> - no prof that it can be re-used by other drivers than tegra
>>   (at least I do not see reasons to re-use it for any TI drivers)
> 
> This is not necessarily a blocker if it can be shown that others than
> TI/OMAP can reuse it.

sure. My point is - this is big change in gpiolib, which is > 1000 lines,
but current re-usability just 2 drivers (I'm comparing with your work when
gpio irq infra was introduced - you did it bottom-up, by refactoring
existing drivers and moving common code in gpiolib, so re usability is great). 

> 
> I've looked at things like the imagination pistachio:
> 
> pinctrl@18101C00 {
>          compatible = "img,pistachio-system-pinctrl";
>          reg = <0x18101C00 0x400>;
> 
>          gpio0: gpio0 {
>                  interrupts = <GIC_SHARED 71 IRQ_TYPE_LEVEL_HIGH>;
> 
>                  gpio-controller;
>                  #gpio-cells = <2>;
> 
>                  interrupt-controller;
>                  #interrupt-cells = <2>;
>          };
> 
>          ...
> 
>          gpio5: gpio5 {
>                  interrupts = <GIC_SHARED 76 IRQ_TYPE_LEVEL_HIGH>;
> 
>                  gpio-controller;
>                  #gpio-cells = <2>;
> 
>                  interrupt-controller;
>                  #interrupt-cells = <2>;
>          };
> 
> This looks like a clear candidate.
> CC: to  Andrew Bresticker, can you look into this?
> 

[...]

		gpio: gpio@226000 {
			compatible = "ti,dm6441-gpio";
			gpio-controller;
			#gpio-cells = <2>;
			reg = <0x226000 0x1000>;
			interrupts = <42 IRQ_TYPE_EDGE_BOTH
				43 IRQ_TYPE_EDGE_BOTH 44 IRQ_TYPE_EDGE_BOTH
				45 IRQ_TYPE_EDGE_BOTH 46 IRQ_TYPE_EDGE_BOTH
				47 IRQ_TYPE_EDGE_BOTH 48 IRQ_TYPE_EDGE_BOTH
				49 IRQ_TYPE_EDGE_BOTH 50 IRQ_TYPE_EDGE_BOTH>;
			ti,ngpio = <144>;
			ti,davinci-gpio-unbanked = <0>;
			status = "disabled";
			interrupt-controller;
			#interrupt-cells = <2>;
		};

FYI. Above is gpio-dvinci example which defines the same, but without coding
gpio banks in DT (note 2 IRQ lines per bank, bank 32 pins).

> 
> CC to Shawn Guo to look into this.
> 
> So in short I think there can be others that can make good use of this
> infrastructure.
> 
>> - all GPIO IRQs mapped statically
> 
> This really needs to be fixed.
> 
>> - irq->map[offset + j] = irq->parents[parent]; holds IRQs for all pins
>>    which is waste of memory
>> - DT binding changes not documented and no DT examples
>> - below is ugly ;)
>> +       bank = (spec[0] >> gc->of_gpio_bank_mask) & gc->of_gpio_bank_shift;
>> +       pin = (spec[0] >> gc->of_gpio_pin_mask) & gc->of_gpio_pin_shift;
> 
> These should be fixable quite easily I think. Thierry?

What I'm trying to understand is how GPIO client bindings will look like?
Now it is: gpios = <&gpio2 14 GPIO_ACTIVE_LOW>; (pistachio_marduk.dts)

But as per of_gpio_banked_xlate() it expected to be
gpios = <&gpio [Linear gpio num] GPIO_ACTIVE_LOW>;
Wouldn't this break DT compatibility and prevent re-using of this feature
for pistachio, for example? (or i'm missing smth).

-- 
regards,
-grygorii

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

* Re: [PATCH v2 00/16] gpio: Tight IRQ chip integration and banked infrastructure
@ 2017-10-03 18:26           ` Grygorii Strashko
  0 siblings, 0 replies; 56+ messages in thread
From: Grygorii Strashko @ 2017-10-03 18:26 UTC (permalink / raw)
  To: Linus Walleij, Andrew Bresticker, James Hogan, Shawn Guo
  Cc: Thierry Reding, Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel



On 10/02/2017 02:55 AM, Linus Walleij wrote:
> On Thu, Sep 28, 2017 at 4:22 PM, Grygorii Strashko
> <grygorii.strashko@ti.com> wrote:
> 
>> Sry, but I do not agree with this series.
>> - no prof that it can be re-used by other drivers than tegra
>>   (at least I do not see reasons to re-use it for any TI drivers)
> 
> This is not necessarily a blocker if it can be shown that others than
> TI/OMAP can reuse it.

sure. My point is - this is big change in gpiolib, which is > 1000 lines,
but current re-usability just 2 drivers (I'm comparing with your work when
gpio irq infra was introduced - you did it bottom-up, by refactoring
existing drivers and moving common code in gpiolib, so re usability is great). 

> 
> I've looked at things like the imagination pistachio:
> 
> pinctrl@18101C00 {
>          compatible = "img,pistachio-system-pinctrl";
>          reg = <0x18101C00 0x400>;
> 
>          gpio0: gpio0 {
>                  interrupts = <GIC_SHARED 71 IRQ_TYPE_LEVEL_HIGH>;
> 
>                  gpio-controller;
>                  #gpio-cells = <2>;
> 
>                  interrupt-controller;
>                  #interrupt-cells = <2>;
>          };
> 
>          ...
> 
>          gpio5: gpio5 {
>                  interrupts = <GIC_SHARED 76 IRQ_TYPE_LEVEL_HIGH>;
> 
>                  gpio-controller;
>                  #gpio-cells = <2>;
> 
>                  interrupt-controller;
>                  #interrupt-cells = <2>;
>          };
> 
> This looks like a clear candidate.
> CC: to  Andrew Bresticker, can you look into this?
> 

[...]

		gpio: gpio@226000 {
			compatible = "ti,dm6441-gpio";
			gpio-controller;
			#gpio-cells = <2>;
			reg = <0x226000 0x1000>;
			interrupts = <42 IRQ_TYPE_EDGE_BOTH
				43 IRQ_TYPE_EDGE_BOTH 44 IRQ_TYPE_EDGE_BOTH
				45 IRQ_TYPE_EDGE_BOTH 46 IRQ_TYPE_EDGE_BOTH
				47 IRQ_TYPE_EDGE_BOTH 48 IRQ_TYPE_EDGE_BOTH
				49 IRQ_TYPE_EDGE_BOTH 50 IRQ_TYPE_EDGE_BOTH>;
			ti,ngpio = <144>;
			ti,davinci-gpio-unbanked = <0>;
			status = "disabled";
			interrupt-controller;
			#interrupt-cells = <2>;
		};

FYI. Above is gpio-dvinci example which defines the same, but without coding
gpio banks in DT (note 2 IRQ lines per bank, bank 32 pins).

> 
> CC to Shawn Guo to look into this.
> 
> So in short I think there can be others that can make good use of this
> infrastructure.
> 
>> - all GPIO IRQs mapped statically
> 
> This really needs to be fixed.
> 
>> - irq->map[offset + j] = irq->parents[parent]; holds IRQs for all pins
>>    which is waste of memory
>> - DT binding changes not documented and no DT examples
>> - below is ugly ;)
>> +       bank = (spec[0] >> gc->of_gpio_bank_mask) & gc->of_gpio_bank_shift;
>> +       pin = (spec[0] >> gc->of_gpio_pin_mask) & gc->of_gpio_pin_shift;
> 
> These should be fixable quite easily I think. Thierry?

What I'm trying to understand is how GPIO client bindings will look like?
Now it is: gpios = <&gpio2 14 GPIO_ACTIVE_LOW>; (pistachio_marduk.dts)

But as per of_gpio_banked_xlate() it expected to be
gpios = <&gpio [Linear gpio num] GPIO_ACTIVE_LOW>;
Wouldn't this break DT compatibility and prevent re-using of this feature
for pistachio, for example? (or i'm missing smth).

-- 
regards,
-grygorii

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

* Re: [PATCH v2 00/16] gpio: Tight IRQ chip integration and banked infrastructure
  2017-10-02  7:55     ` Linus Walleij
@ 2017-10-05 11:14           ` Linus Walleij
  0 siblings, 0 replies; 56+ messages in thread
From: Linus Walleij @ 2017-10-05 11:14 UTC (permalink / raw)
  To: Grygorii Strashko, Andrew Bresticker, James Hogan, Shawn Guo, Hoan Tran
  Cc: Thierry Reding, Jonathan Hunter,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

On Mon, Oct 2, 2017 at 9:55 AM, Linus Walleij <linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:

> This is not necessarily a blocker if it can be shown that others than
> TI/OMAP can reuse it.
>
> I've looked at things like the imagination pistachio:
>
> pinctrl@18101C00 {
>         compatible = "img,pistachio-system-pinctrl";
>         reg = <0x18101C00 0x400>;
>
>         gpio0: gpio0 {
>                 interrupts = <GIC_SHARED 71 IRQ_TYPE_LEVEL_HIGH>;
>
>                 gpio-controller;
>                 #gpio-cells = <2>;
>
>                 interrupt-controller;
>                 #interrupt-cells = <2>;
>         };
>
>         ...
>
>         gpio5: gpio5 {
>                 interrupts = <GIC_SHARED 76 IRQ_TYPE_LEVEL_HIGH>;
>
>                 gpio-controller;
>                 #gpio-cells = <2>;
>
>                 interrupt-controller;
>                 #interrupt-cells = <2>;
>         };
>
> This looks like a clear candidate.
> CC: to  Andrew Bresticker, can you look into this?
>
> Another example would be gpio-tz1090, notably with interrupt optional:
>
>        gpios: gpio-controller@02005800 {
>                 #address-cells = <1>;
>                 #size-cells = <0>;
>                 compatible = "img,tz1090-gpio";
>                 reg = <0x02005800 0x90>;
>
>                 /* bank 0 with an interrupt */
>                 gpios0: bank@0 {
>                         #gpio-cells = <2>;
>                         #interrupt-cells = <2>;
>                         reg = <0>;
>                         interrupts = <13 IRQ_TYPE_LEVEL_HIGH>;
>                         gpio-controller;
>                         gpio-ranges = <&pinctrl 0 0 30>;
>                         interrupt-controller;
>                 };
>
>                 /* bank 2 without interrupt */
>                 gpios2: bank@2 {
>                         #gpio-cells = <2>;
>                         reg = <2>;
>                         gpio-controller;
>                         gpio-ranges = <&pinctrl 0 60 30>;
>                 };
>         };
>
> CC to James Hogan to look at the series from this perspective.
>
> A third is gpio-mxs.c:
>
> pinctrl@80018000 {
>         compatible = "fsl,imx28-pinctrl", "simple-bus";
>         reg = <0x80018000 2000>;
>
>         gpio0: gpio@0 {
>                 compatible = "fsl,imx28-gpio";
>                 interrupts = <127>;
>                 gpio-controller;
>                 #gpio-cells = <2>;
>                 interrupt-controller;
>                 #interrupt-cells = <2>;
>         };
>
>         gpio1: gpio@1 {
>                 compatible = "fsl,imx28-gpio";
>                 interrupts = <126>;
>                 gpio-controller;
>                 #gpio-cells = <2>;
>                 interrupt-controller;
>                 #interrupt-cells = <2>;
>         };
>
>         gpio2: gpio@2 {
>                 compatible = "fsl,imx28-gpio";
>                 interrupts = <125>;
>                 gpio-controller;
>                 #gpio-cells = <2>;
>                 interrupt-controller;
>                 #interrupt-cells = <2>;
>         };
> (...)
>
> CC to Shawn Guo to look into this.
>
> So in short I think there can be others that can make good use of this
> infrastructure.

It also looks like the "ports" in the gpio-dwapb can be modeled using this
bank infrastructure, cutting down on per-driver overhead and adding
good much needed abstraction for these ports/banks.

Paging Hoan Tran on this as well, to keep an eye on the series.

Yours,
Linus Walleij

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

* Re: [PATCH v2 00/16] gpio: Tight IRQ chip integration and banked infrastructure
@ 2017-10-05 11:14           ` Linus Walleij
  0 siblings, 0 replies; 56+ messages in thread
From: Linus Walleij @ 2017-10-05 11:14 UTC (permalink / raw)
  To: Grygorii Strashko, Andrew Bresticker, James Hogan, Shawn Guo, Hoan Tran
  Cc: Thierry Reding, Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

On Mon, Oct 2, 2017 at 9:55 AM, Linus Walleij <linus.walleij@linaro.org> wrote:

> This is not necessarily a blocker if it can be shown that others than
> TI/OMAP can reuse it.
>
> I've looked at things like the imagination pistachio:
>
> pinctrl@18101C00 {
>         compatible = "img,pistachio-system-pinctrl";
>         reg = <0x18101C00 0x400>;
>
>         gpio0: gpio0 {
>                 interrupts = <GIC_SHARED 71 IRQ_TYPE_LEVEL_HIGH>;
>
>                 gpio-controller;
>                 #gpio-cells = <2>;
>
>                 interrupt-controller;
>                 #interrupt-cells = <2>;
>         };
>
>         ...
>
>         gpio5: gpio5 {
>                 interrupts = <GIC_SHARED 76 IRQ_TYPE_LEVEL_HIGH>;
>
>                 gpio-controller;
>                 #gpio-cells = <2>;
>
>                 interrupt-controller;
>                 #interrupt-cells = <2>;
>         };
>
> This looks like a clear candidate.
> CC: to  Andrew Bresticker, can you look into this?
>
> Another example would be gpio-tz1090, notably with interrupt optional:
>
>        gpios: gpio-controller@02005800 {
>                 #address-cells = <1>;
>                 #size-cells = <0>;
>                 compatible = "img,tz1090-gpio";
>                 reg = <0x02005800 0x90>;
>
>                 /* bank 0 with an interrupt */
>                 gpios0: bank@0 {
>                         #gpio-cells = <2>;
>                         #interrupt-cells = <2>;
>                         reg = <0>;
>                         interrupts = <13 IRQ_TYPE_LEVEL_HIGH>;
>                         gpio-controller;
>                         gpio-ranges = <&pinctrl 0 0 30>;
>                         interrupt-controller;
>                 };
>
>                 /* bank 2 without interrupt */
>                 gpios2: bank@2 {
>                         #gpio-cells = <2>;
>                         reg = <2>;
>                         gpio-controller;
>                         gpio-ranges = <&pinctrl 0 60 30>;
>                 };
>         };
>
> CC to James Hogan to look at the series from this perspective.
>
> A third is gpio-mxs.c:
>
> pinctrl@80018000 {
>         compatible = "fsl,imx28-pinctrl", "simple-bus";
>         reg = <0x80018000 2000>;
>
>         gpio0: gpio@0 {
>                 compatible = "fsl,imx28-gpio";
>                 interrupts = <127>;
>                 gpio-controller;
>                 #gpio-cells = <2>;
>                 interrupt-controller;
>                 #interrupt-cells = <2>;
>         };
>
>         gpio1: gpio@1 {
>                 compatible = "fsl,imx28-gpio";
>                 interrupts = <126>;
>                 gpio-controller;
>                 #gpio-cells = <2>;
>                 interrupt-controller;
>                 #interrupt-cells = <2>;
>         };
>
>         gpio2: gpio@2 {
>                 compatible = "fsl,imx28-gpio";
>                 interrupts = <125>;
>                 gpio-controller;
>                 #gpio-cells = <2>;
>                 interrupt-controller;
>                 #interrupt-cells = <2>;
>         };
> (...)
>
> CC to Shawn Guo to look into this.
>
> So in short I think there can be others that can make good use of this
> infrastructure.

It also looks like the "ports" in the gpio-dwapb can be modeled using this
bank infrastructure, cutting down on per-driver overhead and adding
good much needed abstraction for these ports/banks.

Paging Hoan Tran on this as well, to keep an eye on the series.

Yours,
Linus Walleij

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

* Re: [PATCH v2 00/16] gpio: Tight IRQ chip integration and banked infrastructure
  2017-10-03 18:26           ` Grygorii Strashko
  (?)
@ 2017-10-05 11:19           ` Linus Walleij
  -1 siblings, 0 replies; 56+ messages in thread
From: Linus Walleij @ 2017-10-05 11:19 UTC (permalink / raw)
  To: Grygorii Strashko, Hoan Tran, thierry.reding
  Cc: Andrew Bresticker, James Hogan, Shawn Guo, Jonathan Hunter,
	linux-gpio, linux-tegra, linux-kernel

On Tue, Oct 3, 2017 at 8:26 PM, Grygorii Strashko
<grygorii.strashko@ti.com> wrote:
> On 10/02/2017 02:55 AM, Linus Walleij wrote:
>> On Thu, Sep 28, 2017 at 4:22 PM, Grygorii Strashko
>> <grygorii.strashko@ti.com> wrote:
>>
>>> Sry, but I do not agree with this series.
>>> - no prof that it can be re-used by other drivers than tegra
>>>   (at least I do not see reasons to re-use it for any TI drivers)
>>
>> This is not necessarily a blocker if it can be shown that others than
>> TI/OMAP can reuse it.
>
> sure. My point is - this is big change in gpiolib, which is > 1000 lines,
> but current re-usability just 2 drivers (I'm comparing with your work when
> gpio irq infra was introduced - you did it bottom-up, by refactoring
> existing drivers and moving common code in gpiolib, so re usability is great).

Yes I am leaning toward adding this infrastructure also with switching as many
candidates as possible over to using the new infrastructure. So I'm trying
to align a few maintainers to this cause. Maybe OMAP will not be one
of them as I thought initially :/

>                 gpio: gpio@226000 {
>                         compatible = "ti,dm6441-gpio";
>                         gpio-controller;
>                         #gpio-cells = <2>;
>                         reg = <0x226000 0x1000>;
>                         interrupts = <42 IRQ_TYPE_EDGE_BOTH
>                                 43 IRQ_TYPE_EDGE_BOTH 44 IRQ_TYPE_EDGE_BOTH
>                                 45 IRQ_TYPE_EDGE_BOTH 46 IRQ_TYPE_EDGE_BOTH
>                                 47 IRQ_TYPE_EDGE_BOTH 48 IRQ_TYPE_EDGE_BOTH
>                                 49 IRQ_TYPE_EDGE_BOTH 50 IRQ_TYPE_EDGE_BOTH>;
>                         ti,ngpio = <144>;
>                         ti,davinci-gpio-unbanked = <0>;
>                         status = "disabled";
>                         interrupt-controller;
>                         #interrupt-cells = <2>;
>                 };
>
> FYI. Above is gpio-dvinci example which defines the same, but without coding
> gpio banks in DT (note 2 IRQ lines per bank, bank 32 pins).

Yeah. This case would be nice to cover too.

>>> - irq->map[offset + j] = irq->parents[parent]; holds IRQs for all pins
>>>    which is waste of memory
>>> - DT binding changes not documented and no DT examples
>>> - below is ugly ;)
>>> +       bank = (spec[0] >> gc->of_gpio_bank_mask) & gc->of_gpio_bank_shift;
>>> +       pin = (spec[0] >> gc->of_gpio_pin_mask) & gc->of_gpio_pin_shift;
>>
>> These should be fixable quite easily I think. Thierry?
>
> What I'm trying to understand is how GPIO client bindings will look like?
> Now it is: gpios = <&gpio2 14 GPIO_ACTIVE_LOW>; (pistachio_marduk.dts)
>
> But as per of_gpio_banked_xlate() it expected to be
> gpios = <&gpio [Linear gpio num] GPIO_ACTIVE_LOW>;
> Wouldn't this break DT compatibility and prevent re-using of this feature
> for pistachio, for example? (or i'm missing smth).

I was hoping we could introduce infrastructure that can be used
by the existing in-tree banked/port GPIO drivers without any
changes to the consumer side of bindings.

So that is the patch set I'm imagining.

Else we're not really getting reusability.

Yours,
Linus Walleij

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

* Re: [PATCH v2 00/16] gpio: Tight IRQ chip integration and banked infrastructure
  2017-09-28 14:22     ` Grygorii Strashko
@ 2017-10-06 11:07         ` Thierry Reding
  -1 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-10-06 11:07 UTC (permalink / raw)
  To: Grygorii Strashko
  Cc: Linus Walleij, Jonathan Hunter,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

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

On Thu, Sep 28, 2017 at 09:22:17AM -0500, Grygorii Strashko wrote:
> 
> 
> On 09/28/2017 04:56 AM, Thierry Reding wrote:
> > From: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> > 
> > Hi Linus,
> > 
> > here's the latest series of patches that implement the tighter IRQ chip
> > integration as well as the banked GPIO infrastructure that we had
> > discussed a couple of weeks/months back.
> > 
> > The first couple of patches are mostly preparatory work in order to
> > consolidate all IRQ chip related fields in a new structure and create
> > the base functionality for adding IRQ chips.
> > 
> > After that, I've added the Tegra186 GPIO support patch that makes use of
> > the new tight integration.
> > 
> > To round things off the new banked GPIO infrastructure is added (along
> > with some more preparatory work), followed by the conversion of the two
> > Tegra GPIO drivers to the new infrastructure.
> 
> Hm. So you've ignored my comments [1].
> 
> Sry, but I do not agree with this series.
> - no prof that it can be re-used by other drivers than tegra
>  (at least I do not see reasons to re-use it for any TI drivers)

I had done some research based on Linus' feedback from an earlier series
and identified the following potential candidates[0] that could move to
this new infrastructure:

	- gpio-intel-mid.c
	- gpio-merrifield.c
	- gpio-pca953x.c
	- gpio-stmpe.c
	- gpio-tc3589x.c
	- gpio-ws16c48.c

Note that this is based on code inspection rather than DT inspection,
because that's fundamentally flawed. If you look at this from a DT
perspective you're going to be tempted to change the DT bindings, but
you can't do that because of backwards compatiblity. This new framework
also doesn't address the issues at that level, but rather tries to be
some common code that is otherwise duplicated in one way or another in
various drivers and therefore hard to maintain. This is what Linus had
originally requested, and that's what the series does.

> - no split

What does this mean? The series is nicely split into separate patches,
so each one individually is easy to review. I've also gone through quite
some trouble to make sure everything builds fine after each patch, so
it's possible to apply individual bits of the series. For example we
could opt to apply everything up to the banked GPIO support if that's
still contentious.

> - all GPIO IRQs mapped statically

This series predates your work on the dynamic IRQ mapping, so I hadn't
picked up those changes. This should be easily solved by the attached
patch, though.

> - irq->map[offset + j] = irq->parents[parent]; holds IRQs for all pins
>   which is waste of memory

It's the only way to generically do this. Also I don't think this wastes
that much memory. We have one unsigned int per pin, which even for very
large GPIO controllers is unlikely to exceed one 4 KiB page.

> - DT binding changes not documented and no DT examples

That's because this is completely orthogonal to DT bindings. We can't
make any changes to the bindings because of ABI stability.

> - below is ugly ;)
> +	bank = (spec[0] >> gc->of_gpio_bank_mask) & gc->of_gpio_bank_shift;
> +	pin = (spec[0] >> gc->of_gpio_pin_mask) & gc->of_gpio_pin_shift;

If by ugly you mean wrong, then yes, it's actually the wrong way around.
It should be:

	bank = (spec[0] >> gc->of_gpio_bank_shift) & gc->of_gpio_bank_mask;
	line = (spec[0] >> gc->of_gpio_line_shift) & gc->of_gpio_line_mask;

Thierry

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

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

* Re: [PATCH v2 00/16] gpio: Tight IRQ chip integration and banked infrastructure
@ 2017-10-06 11:07         ` Thierry Reding
  0 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-10-06 11:07 UTC (permalink / raw)
  To: Grygorii Strashko
  Cc: Linus Walleij, Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

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

On Thu, Sep 28, 2017 at 09:22:17AM -0500, Grygorii Strashko wrote:
> 
> 
> On 09/28/2017 04:56 AM, Thierry Reding wrote:
> > From: Thierry Reding <treding@nvidia.com>
> > 
> > Hi Linus,
> > 
> > here's the latest series of patches that implement the tighter IRQ chip
> > integration as well as the banked GPIO infrastructure that we had
> > discussed a couple of weeks/months back.
> > 
> > The first couple of patches are mostly preparatory work in order to
> > consolidate all IRQ chip related fields in a new structure and create
> > the base functionality for adding IRQ chips.
> > 
> > After that, I've added the Tegra186 GPIO support patch that makes use of
> > the new tight integration.
> > 
> > To round things off the new banked GPIO infrastructure is added (along
> > with some more preparatory work), followed by the conversion of the two
> > Tegra GPIO drivers to the new infrastructure.
> 
> Hm. So you've ignored my comments [1].
> 
> Sry, but I do not agree with this series.
> - no prof that it can be re-used by other drivers than tegra
>  (at least I do not see reasons to re-use it for any TI drivers)

I had done some research based on Linus' feedback from an earlier series
and identified the following potential candidates[0] that could move to
this new infrastructure:

	- gpio-intel-mid.c
	- gpio-merrifield.c
	- gpio-pca953x.c
	- gpio-stmpe.c
	- gpio-tc3589x.c
	- gpio-ws16c48.c

Note that this is based on code inspection rather than DT inspection,
because that's fundamentally flawed. If you look at this from a DT
perspective you're going to be tempted to change the DT bindings, but
you can't do that because of backwards compatiblity. This new framework
also doesn't address the issues at that level, but rather tries to be
some common code that is otherwise duplicated in one way or another in
various drivers and therefore hard to maintain. This is what Linus had
originally requested, and that's what the series does.

> - no split

What does this mean? The series is nicely split into separate patches,
so each one individually is easy to review. I've also gone through quite
some trouble to make sure everything builds fine after each patch, so
it's possible to apply individual bits of the series. For example we
could opt to apply everything up to the banked GPIO support if that's
still contentious.

> - all GPIO IRQs mapped statically

This series predates your work on the dynamic IRQ mapping, so I hadn't
picked up those changes. This should be easily solved by the attached
patch, though.

> - irq->map[offset + j] = irq->parents[parent]; holds IRQs for all pins
>   which is waste of memory

It's the only way to generically do this. Also I don't think this wastes
that much memory. We have one unsigned int per pin, which even for very
large GPIO controllers is unlikely to exceed one 4 KiB page.

> - DT binding changes not documented and no DT examples

That's because this is completely orthogonal to DT bindings. We can't
make any changes to the bindings because of ABI stability.

> - below is ugly ;)
> +	bank = (spec[0] >> gc->of_gpio_bank_mask) & gc->of_gpio_bank_shift;
> +	pin = (spec[0] >> gc->of_gpio_pin_mask) & gc->of_gpio_pin_shift;

If by ugly you mean wrong, then yes, it's actually the wrong way around.
It should be:

	bank = (spec[0] >> gc->of_gpio_bank_shift) & gc->of_gpio_bank_mask;
	line = (spec[0] >> gc->of_gpio_line_shift) & gc->of_gpio_line_mask;

Thierry

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

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

* Re: [PATCH v2 00/16] gpio: Tight IRQ chip integration and banked infrastructure
  2017-10-06 11:07         ` Thierry Reding
@ 2017-10-06 11:11           ` Thierry Reding
  -1 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-10-06 11:11 UTC (permalink / raw)
  To: Grygorii Strashko
  Cc: Linus Walleij, Jonathan Hunter,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

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

On Fri, Oct 06, 2017 at 01:07:49PM +0200, Thierry Reding wrote:
> On Thu, Sep 28, 2017 at 09:22:17AM -0500, Grygorii Strashko wrote:
[...]
> > - all GPIO IRQs mapped statically
> 
> This series predates your work on the dynamic IRQ mapping, so I hadn't
> picked up those changes. This should be easily solved by the attached
> patch, though.

Here's the patch.

Thierry

--- >8 ---
commit 139c254bf963bf373d83970e530a56599f1832cc
Author: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Date:   Fri Oct 6 12:12:27 2017 +0200

    fixup! gpio: Implement tighter IRQ chip integration

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index b3bd19b793d3..2e450afe61b3 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1708,9 +1708,23 @@ static void gpiochip_irq_relres(struct irq_data *d)
 
 static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
 {
+	unsigned int irq;
+	int err;
+
 	if (!gpiochip_irqchip_irq_valid(chip, offset))
 		return -ENXIO;
-	return irq_create_mapping(chip->irq.domain, offset);
+
+	irq = irq_create_mapping(chip->irq.domain, offset);
+	if (!irq)
+		return 0;
+
+	if (chip->irq.map) {
+		err = irq_set_parent(irq, chip->irq.map[offset]);
+		if (err < 0)
+			return err;
+	}
+
+	return irq;
 }
 
 /**
@@ -1856,27 +1870,6 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
 		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->irq.domain, 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;

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

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

* Re: [PATCH v2 00/16] gpio: Tight IRQ chip integration and banked infrastructure
@ 2017-10-06 11:11           ` Thierry Reding
  0 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-10-06 11:11 UTC (permalink / raw)
  To: Grygorii Strashko
  Cc: Linus Walleij, Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

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

On Fri, Oct 06, 2017 at 01:07:49PM +0200, Thierry Reding wrote:
> On Thu, Sep 28, 2017 at 09:22:17AM -0500, Grygorii Strashko wrote:
[...]
> > - all GPIO IRQs mapped statically
> 
> This series predates your work on the dynamic IRQ mapping, so I hadn't
> picked up those changes. This should be easily solved by the attached
> patch, though.

Here's the patch.

Thierry

--- >8 ---
commit 139c254bf963bf373d83970e530a56599f1832cc
Author: Thierry Reding <treding@nvidia.com>
Date:   Fri Oct 6 12:12:27 2017 +0200

    fixup! gpio: Implement tighter IRQ chip integration

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index b3bd19b793d3..2e450afe61b3 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1708,9 +1708,23 @@ static void gpiochip_irq_relres(struct irq_data *d)
 
 static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
 {
+	unsigned int irq;
+	int err;
+
 	if (!gpiochip_irqchip_irq_valid(chip, offset))
 		return -ENXIO;
-	return irq_create_mapping(chip->irq.domain, offset);
+
+	irq = irq_create_mapping(chip->irq.domain, offset);
+	if (!irq)
+		return 0;
+
+	if (chip->irq.map) {
+		err = irq_set_parent(irq, chip->irq.map[offset]);
+		if (err < 0)
+			return err;
+	}
+
+	return irq;
 }
 
 /**
@@ -1856,27 +1870,6 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
 		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->irq.domain, 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;

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

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

* Re: [PATCH v2 15/16] gpio: tegra: Use banked GPIO infrastructure
  2017-09-28  9:56     ` Thierry Reding
@ 2017-10-09 21:22         ` Grygorii Strashko
  -1 siblings, 0 replies; 56+ messages in thread
From: Grygorii Strashko @ 2017-10-09 21:22 UTC (permalink / raw)
  To: Thierry Reding, Linus Walleij
  Cc: Jonathan Hunter, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA



On 09/28/2017 04:56 AM, Thierry Reding wrote:
> From: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> 
> Convert the Tegra GPIO driver to use the banked GPIO infrastructure,
> which simplifies some parts of the driver.
> 
> Signed-off-by: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> ---
>   drivers/gpio/Kconfig      |   1 +
>   drivers/gpio/gpio-tegra.c | 203 ++++++++++++++++++++++------------------------
>   2 files changed, 98 insertions(+), 106 deletions(-)
> 
> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> index db3e446ad9b3..458157d6d491 100644
> --- a/drivers/gpio/Kconfig
> +++ b/drivers/gpio/Kconfig
> @@ -439,6 +439,7 @@ config GPIO_TEGRA
>   	default ARCH_TEGRA
>   	depends on ARCH_TEGRA || COMPILE_TEST

... 

> @@ -616,76 +617,66 @@ static int tegra_gpio_probe(struct platform_device *pdev)
>   	tgi->ic.irq_set_wake		= tegra_gpio_irq_set_wake;
>   #endif
>   
> +	irq = &tgi->gc.irq;
> +	irq->chip = &tgi->ic;
> +	irq->handler = handle_simple_irq;
> +	irq->lock_key = &tegra_gpio_lock_class;

As per current gpiolib design lockdep lock_class_key is assigned 
automatically and hidden from gpiolib users. 
Why do you need to do the same manually?

> +	irq->default_type = IRQ_TYPE_NONE;
> +	irq->parent_handler = gpio_irq_chip_banked_chained_handler;
> +	irq->update_bank = tegra_gpio_update_bank;
> +
> +	irq->parents = devm_kcalloc(&pdev->dev, tgi->gc.num_banks,
> +				    sizeof(unsigned int), GFP_KERNEL);
> +	if (!irq->parents)
> +		return -ENOMEM;
> +

...

>   
>   	tegra_gpio_debuginit(tgi);
>   
> 

-- 
regards,
-grygorii

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

* Re: [PATCH v2 15/16] gpio: tegra: Use banked GPIO infrastructure
@ 2017-10-09 21:22         ` Grygorii Strashko
  0 siblings, 0 replies; 56+ messages in thread
From: Grygorii Strashko @ 2017-10-09 21:22 UTC (permalink / raw)
  To: Thierry Reding, Linus Walleij
  Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel



On 09/28/2017 04:56 AM, Thierry Reding wrote:
> From: Thierry Reding <treding@nvidia.com>
> 
> Convert the Tegra GPIO driver to use the banked GPIO infrastructure,
> which simplifies some parts of the driver.
> 
> Signed-off-by: Thierry Reding <treding@nvidia.com>
> ---
>   drivers/gpio/Kconfig      |   1 +
>   drivers/gpio/gpio-tegra.c | 203 ++++++++++++++++++++++------------------------
>   2 files changed, 98 insertions(+), 106 deletions(-)
> 
> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> index db3e446ad9b3..458157d6d491 100644
> --- a/drivers/gpio/Kconfig
> +++ b/drivers/gpio/Kconfig
> @@ -439,6 +439,7 @@ config GPIO_TEGRA
>   	default ARCH_TEGRA
>   	depends on ARCH_TEGRA || COMPILE_TEST

... 

> @@ -616,76 +617,66 @@ static int tegra_gpio_probe(struct platform_device *pdev)
>   	tgi->ic.irq_set_wake		= tegra_gpio_irq_set_wake;
>   #endif
>   
> +	irq = &tgi->gc.irq;
> +	irq->chip = &tgi->ic;
> +	irq->handler = handle_simple_irq;
> +	irq->lock_key = &tegra_gpio_lock_class;

As per current gpiolib design lockdep lock_class_key is assigned 
automatically and hidden from gpiolib users. 
Why do you need to do the same manually?

> +	irq->default_type = IRQ_TYPE_NONE;
> +	irq->parent_handler = gpio_irq_chip_banked_chained_handler;
> +	irq->update_bank = tegra_gpio_update_bank;
> +
> +	irq->parents = devm_kcalloc(&pdev->dev, tgi->gc.num_banks,
> +				    sizeof(unsigned int), GFP_KERNEL);
> +	if (!irq->parents)
> +		return -ENOMEM;
> +

...

>   
>   	tegra_gpio_debuginit(tgi);
>   
> 

-- 
regards,
-grygorii

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

* Re: [PATCH v2 14/16] gpio: Add support for banked GPIO controllers
  2017-09-28  9:56     ` Thierry Reding
@ 2017-10-09 21:52         ` Grygorii Strashko
  -1 siblings, 0 replies; 56+ messages in thread
From: Grygorii Strashko @ 2017-10-09 21:52 UTC (permalink / raw)
  To: Thierry Reding, Linus Walleij
  Cc: Jonathan Hunter, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA



On 09/28/2017 04:56 AM, Thierry Reding wrote:
> From: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> 
> Some GPIO controllers are subdivided into multiple logical blocks called
> banks (or ports). This is often caused by the design assigning separate
> resources, such as register regions or interrupts, to each bank, or some
> set of banks.
> 
> This commit adds support for describing controllers that have such a
> banked design and provides common code for dealing with them.
> 
> Signed-off-by: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> ---
>   drivers/gpio/gpiolib-of.c   | 101 +++++++++++++++++++++++++++++++++++++++++
>   drivers/gpio/gpiolib.c      |  98 ++++++++++++++++++++++++++++++++++++++++
>   include/linux/gpio/driver.h | 108 ++++++++++++++++++++++++++++++++++++++++++++
>   include/linux/of_gpio.h     |  10 ++++
>   4 files changed, 317 insertions(+)
> 
> diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
> index bfcd20699ec8..9baabe00966d 100644
> --- a/drivers/gpio/gpiolib-of.c
> +++ b/drivers/gpio/gpiolib-of.c
> @@ -309,6 +309,107 @@ int of_gpio_simple_xlate(struct gpio_chip *gc,
>   }
>   EXPORT_SYMBOL(of_gpio_simple_xlate);
>   
> +/**
> + * gpio_banked_irq_domain_xlate - decode an IRQ specifier for banked chips
> + * @domain: IRQ domain
> + * @np: device tree node
> + * @spec: IRQ specifier
> + * @size: number of cells in IRQ specifier
> + * @hwirq: return location for the hardware IRQ number
> + * @type: return location for the IRQ type
> + *
> + * Translates the IRQ specifier found in device tree into a hardware IRQ
> + * number and an interrupt type.
> + *
> + * Returns:
> + * 0 on success or a negative error code on failure.
> + */
> +int gpio_banked_irq_domain_xlate(struct irq_domain *domain,
> +				 struct device_node *np,
> +				 const u32 *spec, unsigned int size,
> +				 unsigned long *hwirq,
> +				 unsigned int *type)
> +{
> +	struct gpio_chip *gc = domain->host_data;
> +	unsigned int bank, line, i, offset = 0;
> +
> +	if (size < 2)
> +		return -EINVAL;
> +
> +	bank = (spec[0] >> gc->of_gpio_bank_mask) & gc->of_gpio_bank_shift;
> +	line = (spec[0] >> gc->of_gpio_line_mask) & gc->of_gpio_line_shift;
> +
> +	if (bank >= gc->num_banks) {
> +		dev_err(gc->parent, "invalid bank number: %u\n", bank);
> +		return -EINVAL;
> +	}
> +
> +	if (line >= gc->banks[bank]->num_lines) {
> +		dev_err(gc->parent, "invalid line number: %u\n", line);
> +		return -EINVAL;
> +	}
> +
> +	for (i = 0; i < bank; i++)
> +		offset += gc->banks[i]->num_lines;

Just to clarify, why is above iteration required?

> +
> +	*type = spec[1] & IRQ_TYPE_SENSE_MASK;
> +	*hwirq = offset + line;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(gpio_banked_irq_domain_xlate);
> +
> +/**
> + * of_gpio_banked_xlate - translate GPIO specifier to a GPIO number and flags
> + * @gc: GPIO chip
> + * @gpiospec: GPIO specifier
> + * @flags: return location for flags parsed from the GPIO specifier
> + *
> + * This translation function takes into account multiple banks that can make
> + * up a single controller. Each bank can contain one or more pins. A single
> + * cell in the specifier is used to represent a (bank, pin) pair, with each
> + * encoded in different fields. The &gpio_chip.of_gpio_bank_shift and
> + * &gpio_chip.of_gpio_bank_mask fields, and &gpio_chip.of_gpio_line_shift and
> + * &gpio_chip.of_gpio_line_mask are used to specify the encoding.
> + *
> + * Returns:
> + * The chip-relative index of the pin given by the GPIO specifier.
> + */
> +int of_gpio_banked_xlate(struct gpio_chip *gc,
> +			 const struct of_phandle_args *gpiospec, u32 *flags)
> +{
> +	unsigned int offset = 0, bank, line, i;
> +	const u32 *spec = gpiospec->args;
> +
> +	if (WARN_ON(gc->of_gpio_n_cells < 2))
> +		return -EINVAL;
> +
> +	if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
> +		return -EINVAL;
> +
> +	bank = (spec[0] >> gc->of_gpio_bank_shift) & gc->of_gpio_bank_mask;
> +	line = (spec[0] >> gc->of_gpio_line_shift) & gc->of_gpio_line_mask;
> +
> +	if (bank >= gc->num_banks) {
> +		dev_err(gc->parent, "invalid bank number: %u\n", bank);
> +		return -EINVAL;
> +	}
> +
> +	if (line >= gc->banks[bank]->num_lines) {
> +		dev_err(gc->parent, "invalid line number: %u\n", line);
> +		return -EINVAL;
> +	}
> +
> +	for (i = 0; i < bank; i++)
> +		offset += gc->banks[i]->num_lines;
> +
> +	if (flags)
> +		*flags = spec[1];
> +
> +	return offset + line;
> +}
> +EXPORT_SYMBOL(of_gpio_banked_xlate);

Adding above two functions means adding new GPIO bindings (may be optional,
but common).

> +
>   /**
>    * of_mm_gpiochip_add_data - Add memory mapped GPIO chip (bank)
>    * @np:		device node of the GPIO chip
> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> index c15fb858848a..b3bd19b793d3 100644
> --- a/drivers/gpio/gpiolib.c
> +++ b/drivers/gpio/gpiolib.c
> @@ -1765,6 +1765,57 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
>   	gpiochip->to_irq = gpiochip_to_irq;
>   	gpiochip->irq.default_type = type;
>   
> +	if (gpiochip->num_banks > 0 && !gpiochip->irq.map) {
> +		struct gpio_irq_chip *irq = &gpiochip->irq;
> +		unsigned int i, j, offset = 0;
> +
> +		if (!irq->parents) {
> +			chip_err(gpiochip, "no parent interrupts defined\n");
> +			return -EINVAL;
> +		}
> +
> +		irq->map = devm_kcalloc(gpiochip->parent, gpiochip->ngpio,
> +					sizeof(*irq->map), GFP_KERNEL);
> +		if (!irq->map)
> +			return -ENOMEM;
> +
> +		for (i = 0; i < gpiochip->num_banks; i++) {
> +			struct gpio_bank *bank = gpiochip->banks[i];
> +			unsigned int parent = bank->parent_irq;



> +
> +			for (j = 0; j < bank->num_lines; j++) {
> +				if (parent >= irq->num_parents) {
> +					chip_err(gpiochip,
> +						 "invalid parent interrupt: %u\n",
> +						 parent);
> +					return -EINVAL;
> +				}
> +
> +				irq->map[offset + j] = irq->parents[parent];
> +			}
> +
> +			offset += bank->num_lines;

Most of gpio drivers, you've listed in [1], have only one parent
(waste of memory). There should be way not to store it permanently.

> +		}
> +	}
> +
> +	if (gpiochip->num_banks > 0) {
> +		unsigned int i;
> +
> +		for (i = 0; i < gpiochip->num_banks; i++) {
> +			struct gpio_bank *bank = gpiochip->banks[i];
> +			unsigned int num_lines = bank->num_lines;
> +
> +			bank->pending = devm_kcalloc(gpiochip->parent,
> +						     BITS_TO_LONGS(num_lines),
> +						     sizeof(unsigned long),
> +						     GFP_KERNEL);
> +			if (!bank->pending)
> +				return -ENOMEM;
> +
> +			bank->chip = gpiochip;
> +		}
> +	}
> +
>   	if (gpiochip->irq.domain_ops)
>   		ops = gpiochip->irq.domain_ops;
>   	else
> @@ -1973,6 +2024,53 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
>   }
>   EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
>   
> +/**
> + * gpio_irq_chip_banked_chained_handler - interrupt handler for banked IRQ chips
> + * @desc: IRQ descriptor
> + *
> + * Drivers can use this interrupt handler for banked GPIO controllers. This
> + * implementation iterates over all banks and handles pending interrupts of
> + * the pins associated with the bank.
> + *
> + * This function uses driver specific parts, split out into the
> + * &gpio_chip.update_bank() callback, to retrieves the interrupt pending
> + * state for each of the GPIOs exposed by the given bank.
> + */
> +void gpio_irq_chip_banked_chained_handler(struct irq_desc *desc)
> +{
> +	struct gpio_chip *gpio = irq_desc_get_handler_data(desc);

As per Patch 1 - there are no restriction to use parent_handler_data with
this standard handler - in this case parent_handler_data might not be struct gpio_chip.

> +	struct irq_chip *irq = irq_desc_get_chip(desc);
> +	unsigned int parent = irq_desc_get_irq(desc);
> +	struct gpio_irq_chip *chip = &gpio->irq;
> +	unsigned int i, offset = 0;
> +
> +	chained_irq_enter(irq, desc);
> +
> +	for (i = 0; i < gpio->num_banks; i++) {
> +		struct gpio_bank *bank = gpio->banks[i];
> +		unsigned int line, virq;
> +
> +		if (parent != chip->parents[bank->parent_irq])
> +			goto skip;

You've used this handler in gpio-tegra.c. 
So for compatible = "nvidia,tegra20-gpio":
- there are will be 7 parent irqs/banks.
- gpiochip will be used as chained_handler data.

So, how will it work:
- for bank0 it will take 1 iteration to get correct bank structure
- but for bank7 - 7 iteration always (in hot path?)

> +
> +		chip->update_bank(bank);

Half of gpio drivers, you've listed in [1] required access to common
Interrupt status registers before proceeding to banks.

> +
> +		for_each_set_bit(line, bank->pending, bank->num_lines) {
> +			virq = irq_find_mapping(chip->domain, offset + line);
> +			if (WARN_ON(virq == 0))
> +				continue;

drivers might require to do additional action before/after generic_handle_irq()
(intel_mid_irq_handler())

> +
> +			generic_handle_irq(virq);
> +		}
> +
> +skip:
> +		offset += bank->num_lines;
> +	}
> +
> +	chained_irq_exit(irq, desc);
> +}
> +EXPORT_SYMBOL_GPL(gpio_irq_chip_banked_chained_handler);

chained IRQ handler is not RT friendly (no control from User space)

> +
>   #else /* CONFIG_GPIOLIB_IRQCHIP */
>   
>   static inline int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
> diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
> index c453e0716228..3caa08b3d2b6 100644

[...]

>   
>   /**
> 



[1] https://www.spinics.net/lists/linux-tegra/msg31105.html

-- 
regards,
-grygorii

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

* Re: [PATCH v2 14/16] gpio: Add support for banked GPIO controllers
@ 2017-10-09 21:52         ` Grygorii Strashko
  0 siblings, 0 replies; 56+ messages in thread
From: Grygorii Strashko @ 2017-10-09 21:52 UTC (permalink / raw)
  To: Thierry Reding, Linus Walleij
  Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel



On 09/28/2017 04:56 AM, Thierry Reding wrote:
> From: Thierry Reding <treding@nvidia.com>
> 
> Some GPIO controllers are subdivided into multiple logical blocks called
> banks (or ports). This is often caused by the design assigning separate
> resources, such as register regions or interrupts, to each bank, or some
> set of banks.
> 
> This commit adds support for describing controllers that have such a
> banked design and provides common code for dealing with them.
> 
> Signed-off-by: Thierry Reding <treding@nvidia.com>
> ---
>   drivers/gpio/gpiolib-of.c   | 101 +++++++++++++++++++++++++++++++++++++++++
>   drivers/gpio/gpiolib.c      |  98 ++++++++++++++++++++++++++++++++++++++++
>   include/linux/gpio/driver.h | 108 ++++++++++++++++++++++++++++++++++++++++++++
>   include/linux/of_gpio.h     |  10 ++++
>   4 files changed, 317 insertions(+)
> 
> diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
> index bfcd20699ec8..9baabe00966d 100644
> --- a/drivers/gpio/gpiolib-of.c
> +++ b/drivers/gpio/gpiolib-of.c
> @@ -309,6 +309,107 @@ int of_gpio_simple_xlate(struct gpio_chip *gc,
>   }
>   EXPORT_SYMBOL(of_gpio_simple_xlate);
>   
> +/**
> + * gpio_banked_irq_domain_xlate - decode an IRQ specifier for banked chips
> + * @domain: IRQ domain
> + * @np: device tree node
> + * @spec: IRQ specifier
> + * @size: number of cells in IRQ specifier
> + * @hwirq: return location for the hardware IRQ number
> + * @type: return location for the IRQ type
> + *
> + * Translates the IRQ specifier found in device tree into a hardware IRQ
> + * number and an interrupt type.
> + *
> + * Returns:
> + * 0 on success or a negative error code on failure.
> + */
> +int gpio_banked_irq_domain_xlate(struct irq_domain *domain,
> +				 struct device_node *np,
> +				 const u32 *spec, unsigned int size,
> +				 unsigned long *hwirq,
> +				 unsigned int *type)
> +{
> +	struct gpio_chip *gc = domain->host_data;
> +	unsigned int bank, line, i, offset = 0;
> +
> +	if (size < 2)
> +		return -EINVAL;
> +
> +	bank = (spec[0] >> gc->of_gpio_bank_mask) & gc->of_gpio_bank_shift;
> +	line = (spec[0] >> gc->of_gpio_line_mask) & gc->of_gpio_line_shift;
> +
> +	if (bank >= gc->num_banks) {
> +		dev_err(gc->parent, "invalid bank number: %u\n", bank);
> +		return -EINVAL;
> +	}
> +
> +	if (line >= gc->banks[bank]->num_lines) {
> +		dev_err(gc->parent, "invalid line number: %u\n", line);
> +		return -EINVAL;
> +	}
> +
> +	for (i = 0; i < bank; i++)
> +		offset += gc->banks[i]->num_lines;

Just to clarify, why is above iteration required?

> +
> +	*type = spec[1] & IRQ_TYPE_SENSE_MASK;
> +	*hwirq = offset + line;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(gpio_banked_irq_domain_xlate);
> +
> +/**
> + * of_gpio_banked_xlate - translate GPIO specifier to a GPIO number and flags
> + * @gc: GPIO chip
> + * @gpiospec: GPIO specifier
> + * @flags: return location for flags parsed from the GPIO specifier
> + *
> + * This translation function takes into account multiple banks that can make
> + * up a single controller. Each bank can contain one or more pins. A single
> + * cell in the specifier is used to represent a (bank, pin) pair, with each
> + * encoded in different fields. The &gpio_chip.of_gpio_bank_shift and
> + * &gpio_chip.of_gpio_bank_mask fields, and &gpio_chip.of_gpio_line_shift and
> + * &gpio_chip.of_gpio_line_mask are used to specify the encoding.
> + *
> + * Returns:
> + * The chip-relative index of the pin given by the GPIO specifier.
> + */
> +int of_gpio_banked_xlate(struct gpio_chip *gc,
> +			 const struct of_phandle_args *gpiospec, u32 *flags)
> +{
> +	unsigned int offset = 0, bank, line, i;
> +	const u32 *spec = gpiospec->args;
> +
> +	if (WARN_ON(gc->of_gpio_n_cells < 2))
> +		return -EINVAL;
> +
> +	if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
> +		return -EINVAL;
> +
> +	bank = (spec[0] >> gc->of_gpio_bank_shift) & gc->of_gpio_bank_mask;
> +	line = (spec[0] >> gc->of_gpio_line_shift) & gc->of_gpio_line_mask;
> +
> +	if (bank >= gc->num_banks) {
> +		dev_err(gc->parent, "invalid bank number: %u\n", bank);
> +		return -EINVAL;
> +	}
> +
> +	if (line >= gc->banks[bank]->num_lines) {
> +		dev_err(gc->parent, "invalid line number: %u\n", line);
> +		return -EINVAL;
> +	}
> +
> +	for (i = 0; i < bank; i++)
> +		offset += gc->banks[i]->num_lines;
> +
> +	if (flags)
> +		*flags = spec[1];
> +
> +	return offset + line;
> +}
> +EXPORT_SYMBOL(of_gpio_banked_xlate);

Adding above two functions means adding new GPIO bindings (may be optional,
but common).

> +
>   /**
>    * of_mm_gpiochip_add_data - Add memory mapped GPIO chip (bank)
>    * @np:		device node of the GPIO chip
> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> index c15fb858848a..b3bd19b793d3 100644
> --- a/drivers/gpio/gpiolib.c
> +++ b/drivers/gpio/gpiolib.c
> @@ -1765,6 +1765,57 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
>   	gpiochip->to_irq = gpiochip_to_irq;
>   	gpiochip->irq.default_type = type;
>   
> +	if (gpiochip->num_banks > 0 && !gpiochip->irq.map) {
> +		struct gpio_irq_chip *irq = &gpiochip->irq;
> +		unsigned int i, j, offset = 0;
> +
> +		if (!irq->parents) {
> +			chip_err(gpiochip, "no parent interrupts defined\n");
> +			return -EINVAL;
> +		}
> +
> +		irq->map = devm_kcalloc(gpiochip->parent, gpiochip->ngpio,
> +					sizeof(*irq->map), GFP_KERNEL);
> +		if (!irq->map)
> +			return -ENOMEM;
> +
> +		for (i = 0; i < gpiochip->num_banks; i++) {
> +			struct gpio_bank *bank = gpiochip->banks[i];
> +			unsigned int parent = bank->parent_irq;



> +
> +			for (j = 0; j < bank->num_lines; j++) {
> +				if (parent >= irq->num_parents) {
> +					chip_err(gpiochip,
> +						 "invalid parent interrupt: %u\n",
> +						 parent);
> +					return -EINVAL;
> +				}
> +
> +				irq->map[offset + j] = irq->parents[parent];
> +			}
> +
> +			offset += bank->num_lines;

Most of gpio drivers, you've listed in [1], have only one parent
(waste of memory). There should be way not to store it permanently.

> +		}
> +	}
> +
> +	if (gpiochip->num_banks > 0) {
> +		unsigned int i;
> +
> +		for (i = 0; i < gpiochip->num_banks; i++) {
> +			struct gpio_bank *bank = gpiochip->banks[i];
> +			unsigned int num_lines = bank->num_lines;
> +
> +			bank->pending = devm_kcalloc(gpiochip->parent,
> +						     BITS_TO_LONGS(num_lines),
> +						     sizeof(unsigned long),
> +						     GFP_KERNEL);
> +			if (!bank->pending)
> +				return -ENOMEM;
> +
> +			bank->chip = gpiochip;
> +		}
> +	}
> +
>   	if (gpiochip->irq.domain_ops)
>   		ops = gpiochip->irq.domain_ops;
>   	else
> @@ -1973,6 +2024,53 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
>   }
>   EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
>   
> +/**
> + * gpio_irq_chip_banked_chained_handler - interrupt handler for banked IRQ chips
> + * @desc: IRQ descriptor
> + *
> + * Drivers can use this interrupt handler for banked GPIO controllers. This
> + * implementation iterates over all banks and handles pending interrupts of
> + * the pins associated with the bank.
> + *
> + * This function uses driver specific parts, split out into the
> + * &gpio_chip.update_bank() callback, to retrieves the interrupt pending
> + * state for each of the GPIOs exposed by the given bank.
> + */
> +void gpio_irq_chip_banked_chained_handler(struct irq_desc *desc)
> +{
> +	struct gpio_chip *gpio = irq_desc_get_handler_data(desc);

As per Patch 1 - there are no restriction to use parent_handler_data with
this standard handler - in this case parent_handler_data might not be struct gpio_chip.

> +	struct irq_chip *irq = irq_desc_get_chip(desc);
> +	unsigned int parent = irq_desc_get_irq(desc);
> +	struct gpio_irq_chip *chip = &gpio->irq;
> +	unsigned int i, offset = 0;
> +
> +	chained_irq_enter(irq, desc);
> +
> +	for (i = 0; i < gpio->num_banks; i++) {
> +		struct gpio_bank *bank = gpio->banks[i];
> +		unsigned int line, virq;
> +
> +		if (parent != chip->parents[bank->parent_irq])
> +			goto skip;

You've used this handler in gpio-tegra.c. 
So for compatible = "nvidia,tegra20-gpio":
- there are will be 7 parent irqs/banks.
- gpiochip will be used as chained_handler data.

So, how will it work:
- for bank0 it will take 1 iteration to get correct bank structure
- but for bank7 - 7 iteration always (in hot path?)

> +
> +		chip->update_bank(bank);

Half of gpio drivers, you've listed in [1] required access to common
Interrupt status registers before proceeding to banks.

> +
> +		for_each_set_bit(line, bank->pending, bank->num_lines) {
> +			virq = irq_find_mapping(chip->domain, offset + line);
> +			if (WARN_ON(virq == 0))
> +				continue;

drivers might require to do additional action before/after generic_handle_irq()
(intel_mid_irq_handler())

> +
> +			generic_handle_irq(virq);
> +		}
> +
> +skip:
> +		offset += bank->num_lines;
> +	}
> +
> +	chained_irq_exit(irq, desc);
> +}
> +EXPORT_SYMBOL_GPL(gpio_irq_chip_banked_chained_handler);

chained IRQ handler is not RT friendly (no control from User space)

> +
>   #else /* CONFIG_GPIOLIB_IRQCHIP */
>   
>   static inline int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
> diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
> index c453e0716228..3caa08b3d2b6 100644

[...]

>   
>   /**
> 



[1] https://www.spinics.net/lists/linux-tegra/msg31105.html

-- 
regards,
-grygorii

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

* Re: [PATCH v2 00/16] gpio: Tight IRQ chip integration and banked infrastructure
  2017-10-06 11:07         ` Thierry Reding
@ 2017-10-09 21:56           ` Grygorii Strashko
  -1 siblings, 0 replies; 56+ messages in thread
From: Grygorii Strashko @ 2017-10-09 21:56 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Linus Walleij, Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel



On 10/06/2017 06:07 AM, Thierry Reding wrote:
> On Thu, Sep 28, 2017 at 09:22:17AM -0500, Grygorii Strashko wrote:
>>
>>
>> On 09/28/2017 04:56 AM, Thierry Reding wrote:
>>> From: Thierry Reding <treding@nvidia.com>
>>>
>>> Hi Linus,
>>>
>>> here's the latest series of patches that implement the tighter IRQ chip
>>> integration as well as the banked GPIO infrastructure that we had
>>> discussed a couple of weeks/months back.
>>>
>>> The first couple of patches are mostly preparatory work in order to
>>> consolidate all IRQ chip related fields in a new structure and create
>>> the base functionality for adding IRQ chips.
>>>
>>> After that, I've added the Tegra186 GPIO support patch that makes use of
>>> the new tight integration.
>>>
>>> To round things off the new banked GPIO infrastructure is added (along
>>> with some more preparatory work), followed by the conversion of the two
>>> Tegra GPIO drivers to the new infrastructure.
>>
>> Hm. So you've ignored my comments [1].
>>
>> Sry, but I do not agree with this series.
>> - no prof that it can be re-used by other drivers than tegra
>>   (at least I do not see reasons to re-use it for any TI drivers)
> 
> I had done some research based on Linus' feedback from an earlier series
> and identified the following potential candidates[0] that could move to
> this new infrastructure:
> 

below based on code check:

> 	- gpio-intel-mid.c

one irq per all gpios in controller

> 	- gpio-merrifield.c

one irq per all gpios in controller

> 	- gpio-pca953x.c
one irq per all gpios in controller

> 	- gpio-stmpe.c
one irq per all gpios in controller
> 	- gpio-tc3589x.c
one irq per all gpios in controller
> 	- gpio-ws16c48.c

one irq per all gpios in controller

> 
> Note that this is based on code inspection rather than DT inspection,
> because that's fundamentally flawed. If you look at this from a DT
> perspective you're going to be tempted to change the DT bindings, but
> you can't do that because of backwards compatiblity. This new framework
> also doesn't address the issues at that level, but rather tries to be
> some common code that is otherwise duplicated in one way or another in
> various drivers and therefore hard to maintain. This is what Linus had
> originally requested, and that's what the series does.

I've looked at this again, and again. I've looked on drivers listed above.
Sry, I do not see how this change can improve/simplify above drivers :(
May be it will clean up my doubts, if it will be possible to convert more drivers?

> 
>> - no split
> 
> What does this mean? The series is nicely split into separate patches,
> so each one individually is easy to review. I've also gone through quite
> some trouble to make sure everything builds fine after each patch, so
> it's possible to apply individual bits of the series. For example we
> could opt to apply everything up to the banked GPIO support if that's
> still contentious.

i've commented it in [1]. copy paste here

>>
So, can it be split? I think, patches which reorganize gpio irqchip specific fields placement 
and move them in gpio_irq_chip can be considered separately if they will not introduce
functional changes. Also, omap changes can be considered separately.
(Pay attention that new fields introduced in patch 1). 
>>

This will reduce size of your series and concentrate review attention on actual functional changes.


[1] https://lkml.org/lkml/2017/9/15/442

> 
>> - all GPIO IRQs mapped statically
> 
> This series predates your work on the dynamic IRQ mapping, so I hadn't
> picked up those changes. This should be easily solved by the attached
> patch, though.
> 
>> - irq->map[offset + j] = irq->parents[parent]; holds IRQs for all pins
>>    which is waste of memory
> 
> It's the only way to generically do this. Also I don't think this wastes
> that much memory. We have one unsigned int per pin, which even for very
> large GPIO controllers is unlikely to exceed one 4 KiB page.

for system with <128M of memory even 4k is a win.


> 
>> - DT binding changes not documented and no DT examples
> 
> That's because this is completely orthogonal to DT bindings. We can't
> make any changes to the bindings because of ABI stability.
> 
>> - below is ugly ;)
>> +	bank = (spec[0] >> gc->of_gpio_bank_mask) & gc->of_gpio_bank_shift;
>> +	pin = (spec[0] >> gc->of_gpio_pin_mask) & gc->of_gpio_pin_shift;
> 
> If by ugly you mean wrong, then yes, it's actually the wrong way around.
> It should be:
> 
> 	bank = (spec[0] >> gc->of_gpio_bank_shift) & gc->of_gpio_bank_mask;
> 	line = (spec[0] >> gc->of_gpio_line_shift) & gc->of_gpio_line_mask;

 
Wrong yep. And No. What I do not like is encoding bank & line in the same field.
It creates some not clear DT standard bindings requirements as for me, comparing to the
current well known GPIO bindings 
 gpios = <&[controller] [line number in controller] [flags]>;
line number in controller ::= [0..max lines]

Actually, as per gpio.txt:
"Note that gpio-specifier length is controller dependent.  In the
above example, &gpio1 uses 2 cells to specify a gpio, while &gpio2
only uses one.", 
so, if this going to be part of gpiolib it should be
 described in bindings/gpio/gpio.txt (or some other documents), as
 above note will not be exactly correct and new "banked" gpio controllers
will be expected to use thin new binding.



-- 
regards,
-grygorii

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

* Re: [PATCH v2 00/16] gpio: Tight IRQ chip integration and banked infrastructure
@ 2017-10-09 21:56           ` Grygorii Strashko
  0 siblings, 0 replies; 56+ messages in thread
From: Grygorii Strashko @ 2017-10-09 21:56 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Linus Walleij, Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel



On 10/06/2017 06:07 AM, Thierry Reding wrote:
> On Thu, Sep 28, 2017 at 09:22:17AM -0500, Grygorii Strashko wrote:
>>
>>
>> On 09/28/2017 04:56 AM, Thierry Reding wrote:
>>> From: Thierry Reding <treding@nvidia.com>
>>>
>>> Hi Linus,
>>>
>>> here's the latest series of patches that implement the tighter IRQ chip
>>> integration as well as the banked GPIO infrastructure that we had
>>> discussed a couple of weeks/months back.
>>>
>>> The first couple of patches are mostly preparatory work in order to
>>> consolidate all IRQ chip related fields in a new structure and create
>>> the base functionality for adding IRQ chips.
>>>
>>> After that, I've added the Tegra186 GPIO support patch that makes use of
>>> the new tight integration.
>>>
>>> To round things off the new banked GPIO infrastructure is added (along
>>> with some more preparatory work), followed by the conversion of the two
>>> Tegra GPIO drivers to the new infrastructure.
>>
>> Hm. So you've ignored my comments [1].
>>
>> Sry, but I do not agree with this series.
>> - no prof that it can be re-used by other drivers than tegra
>>   (at least I do not see reasons to re-use it for any TI drivers)
> 
> I had done some research based on Linus' feedback from an earlier series
> and identified the following potential candidates[0] that could move to
> this new infrastructure:
> 

below based on code check:

> 	- gpio-intel-mid.c

one irq per all gpios in controller

> 	- gpio-merrifield.c

one irq per all gpios in controller

> 	- gpio-pca953x.c
one irq per all gpios in controller

> 	- gpio-stmpe.c
one irq per all gpios in controller
> 	- gpio-tc3589x.c
one irq per all gpios in controller
> 	- gpio-ws16c48.c

one irq per all gpios in controller

> 
> Note that this is based on code inspection rather than DT inspection,
> because that's fundamentally flawed. If you look at this from a DT
> perspective you're going to be tempted to change the DT bindings, but
> you can't do that because of backwards compatiblity. This new framework
> also doesn't address the issues at that level, but rather tries to be
> some common code that is otherwise duplicated in one way or another in
> various drivers and therefore hard to maintain. This is what Linus had
> originally requested, and that's what the series does.

I've looked at this again, and again. I've looked on drivers listed above.
Sry, I do not see how this change can improve/simplify above drivers :(
May be it will clean up my doubts, if it will be possible to convert more drivers?

> 
>> - no split
> 
> What does this mean? The series is nicely split into separate patches,
> so each one individually is easy to review. I've also gone through quite
> some trouble to make sure everything builds fine after each patch, so
> it's possible to apply individual bits of the series. For example we
> could opt to apply everything up to the banked GPIO support if that's
> still contentious.

i've commented it in [1]. copy paste here

>>
So, can it be split? I think, patches which reorganize gpio irqchip specific fields placement 
and move them in gpio_irq_chip can be considered separately if they will not introduce
functional changes. Also, omap changes can be considered separately.
(Pay attention that new fields introduced in patch 1). 
>>

This will reduce size of your series and concentrate review attention on actual functional changes.


[1] https://lkml.org/lkml/2017/9/15/442

> 
>> - all GPIO IRQs mapped statically
> 
> This series predates your work on the dynamic IRQ mapping, so I hadn't
> picked up those changes. This should be easily solved by the attached
> patch, though.
> 
>> - irq->map[offset + j] = irq->parents[parent]; holds IRQs for all pins
>>    which is waste of memory
> 
> It's the only way to generically do this. Also I don't think this wastes
> that much memory. We have one unsigned int per pin, which even for very
> large GPIO controllers is unlikely to exceed one 4 KiB page.

for system with <128M of memory even 4k is a win.


> 
>> - DT binding changes not documented and no DT examples
> 
> That's because this is completely orthogonal to DT bindings. We can't
> make any changes to the bindings because of ABI stability.
> 
>> - below is ugly ;)
>> +	bank = (spec[0] >> gc->of_gpio_bank_mask) & gc->of_gpio_bank_shift;
>> +	pin = (spec[0] >> gc->of_gpio_pin_mask) & gc->of_gpio_pin_shift;
> 
> If by ugly you mean wrong, then yes, it's actually the wrong way around.
> It should be:
> 
> 	bank = (spec[0] >> gc->of_gpio_bank_shift) & gc->of_gpio_bank_mask;
> 	line = (spec[0] >> gc->of_gpio_line_shift) & gc->of_gpio_line_mask;

 
Wrong yep. And No. What I do not like is encoding bank & line in the same field.
It creates some not clear DT standard bindings requirements as for me, comparing to the
current well known GPIO bindings 
 gpios = <&[controller] [line number in controller] [flags]>;
line number in controller ::= [0..max lines]

Actually, as per gpio.txt:
"Note that gpio-specifier length is controller dependent.  In the
above example, &gpio1 uses 2 cells to specify a gpio, while &gpio2
only uses one.", 
so, if this going to be part of gpiolib it should be
 described in bindings/gpio/gpio.txt (or some other documents), as
 above note will not be exactly correct and new "banked" gpio controllers
will be expected to use thin new binding.



-- 
regards,
-grygorii

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

* Re: [PATCH v2 15/16] gpio: tegra: Use banked GPIO infrastructure
  2017-10-09 21:22         ` Grygorii Strashko
  (?)
@ 2017-10-10 10:27         ` Thierry Reding
  2017-10-10 19:31             ` Grygorii Strashko
  -1 siblings, 1 reply; 56+ messages in thread
From: Thierry Reding @ 2017-10-10 10:27 UTC (permalink / raw)
  To: Grygorii Strashko
  Cc: Linus Walleij, Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

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

On Mon, Oct 09, 2017 at 04:22:29PM -0500, Grygorii Strashko wrote:
> 
> 
> On 09/28/2017 04:56 AM, Thierry Reding wrote:
> > From: Thierry Reding <treding@nvidia.com>
> > 
> > Convert the Tegra GPIO driver to use the banked GPIO infrastructure,
> > which simplifies some parts of the driver.
> > 
> > Signed-off-by: Thierry Reding <treding@nvidia.com>
> > ---
> >   drivers/gpio/Kconfig      |   1 +
> >   drivers/gpio/gpio-tegra.c | 203 ++++++++++++++++++++++------------------------
> >   2 files changed, 98 insertions(+), 106 deletions(-)
> > 
> > diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> > index db3e446ad9b3..458157d6d491 100644
> > --- a/drivers/gpio/Kconfig
> > +++ b/drivers/gpio/Kconfig
> > @@ -439,6 +439,7 @@ config GPIO_TEGRA
> >   	default ARCH_TEGRA
> >   	depends on ARCH_TEGRA || COMPILE_TEST
> 
> ... 
> 
> > @@ -616,76 +617,66 @@ static int tegra_gpio_probe(struct platform_device *pdev)
> >   	tgi->ic.irq_set_wake		= tegra_gpio_irq_set_wake;
> >   #endif
> >   
> > +	irq = &tgi->gc.irq;
> > +	irq->chip = &tgi->ic;
> > +	irq->handler = handle_simple_irq;
> > +	irq->lock_key = &tegra_gpio_lock_class;
> 
> As per current gpiolib design lockdep lock_class_key is assigned 
> automatically and hidden from gpiolib users. 
> Why do you need to do the same manually?

Can you elaborate? I don't see the lock class key getting set anywhere.
gpiolib does set if for interrupts, but only if the drivers assigned it
before adding the chip.

Thierry

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

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

* Re: [PATCH v2 14/16] gpio: Add support for banked GPIO controllers
  2017-10-09 21:52         ` Grygorii Strashko
@ 2017-10-10 11:00             ` Thierry Reding
  -1 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-10-10 11:00 UTC (permalink / raw)
  To: Grygorii Strashko
  Cc: Linus Walleij, Jonathan Hunter,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

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

On Mon, Oct 09, 2017 at 04:52:21PM -0500, Grygorii Strashko wrote:
> 
> 
> On 09/28/2017 04:56 AM, Thierry Reding wrote:
> > From: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> > 
> > Some GPIO controllers are subdivided into multiple logical blocks called
> > banks (or ports). This is often caused by the design assigning separate
> > resources, such as register regions or interrupts, to each bank, or some
> > set of banks.
> > 
> > This commit adds support for describing controllers that have such a
> > banked design and provides common code for dealing with them.
> > 
> > Signed-off-by: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> > ---
> >   drivers/gpio/gpiolib-of.c   | 101 +++++++++++++++++++++++++++++++++++++++++
> >   drivers/gpio/gpiolib.c      |  98 ++++++++++++++++++++++++++++++++++++++++
> >   include/linux/gpio/driver.h | 108 ++++++++++++++++++++++++++++++++++++++++++++
> >   include/linux/of_gpio.h     |  10 ++++
> >   4 files changed, 317 insertions(+)
> > 
> > diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
> > index bfcd20699ec8..9baabe00966d 100644
> > --- a/drivers/gpio/gpiolib-of.c
> > +++ b/drivers/gpio/gpiolib-of.c
> > @@ -309,6 +309,107 @@ int of_gpio_simple_xlate(struct gpio_chip *gc,
> >   }
> >   EXPORT_SYMBOL(of_gpio_simple_xlate);
> >   
> > +/**
> > + * gpio_banked_irq_domain_xlate - decode an IRQ specifier for banked chips
> > + * @domain: IRQ domain
> > + * @np: device tree node
> > + * @spec: IRQ specifier
> > + * @size: number of cells in IRQ specifier
> > + * @hwirq: return location for the hardware IRQ number
> > + * @type: return location for the IRQ type
> > + *
> > + * Translates the IRQ specifier found in device tree into a hardware IRQ
> > + * number and an interrupt type.
> > + *
> > + * Returns:
> > + * 0 on success or a negative error code on failure.
> > + */
> > +int gpio_banked_irq_domain_xlate(struct irq_domain *domain,
> > +				 struct device_node *np,
> > +				 const u32 *spec, unsigned int size,
> > +				 unsigned long *hwirq,
> > +				 unsigned int *type)
> > +{
> > +	struct gpio_chip *gc = domain->host_data;
> > +	unsigned int bank, line, i, offset = 0;
> > +
> > +	if (size < 2)
> > +		return -EINVAL;
> > +
> > +	bank = (spec[0] >> gc->of_gpio_bank_mask) & gc->of_gpio_bank_shift;
> > +	line = (spec[0] >> gc->of_gpio_line_mask) & gc->of_gpio_line_shift;
> > +
> > +	if (bank >= gc->num_banks) {
> > +		dev_err(gc->parent, "invalid bank number: %u\n", bank);
> > +		return -EINVAL;
> > +	}
> > +
> > +	if (line >= gc->banks[bank]->num_lines) {
> > +		dev_err(gc->parent, "invalid line number: %u\n", line);
> > +		return -EINVAL;
> > +	}
> > +
> > +	for (i = 0; i < bank; i++)
> > +		offset += gc->banks[i]->num_lines;
> 
> Just to clarify, why is above iteration required?

This is used to handle the generic case where not all banks have the
same number of lines. In order to avoid having to separately deal with
non-existing lines, drivers are supposed to register only the exact
number of lines they support.

However, the binding may be written such that the (bank, line) pair is
encoded in one cell. To make that easier to construct and parse, simple
OR'ing is used, perhaps like this:

	index = (((bank) << 3) | (line))

However, if not all banks have 8 lines, this leaves blanks in the number
space when working your way back.

So the above iteration maps the sparse number space of the specifier to
the dense number space of per-chip lines.

> > +	*type = spec[1] & IRQ_TYPE_SENSE_MASK;
> > +	*hwirq = offset + line;
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(gpio_banked_irq_domain_xlate);
> > +
> > +/**
> > + * of_gpio_banked_xlate - translate GPIO specifier to a GPIO number and flags
> > + * @gc: GPIO chip
> > + * @gpiospec: GPIO specifier
> > + * @flags: return location for flags parsed from the GPIO specifier
> > + *
> > + * This translation function takes into account multiple banks that can make
> > + * up a single controller. Each bank can contain one or more pins. A single
> > + * cell in the specifier is used to represent a (bank, pin) pair, with each
> > + * encoded in different fields. The &gpio_chip.of_gpio_bank_shift and
> > + * &gpio_chip.of_gpio_bank_mask fields, and &gpio_chip.of_gpio_line_shift and
> > + * &gpio_chip.of_gpio_line_mask are used to specify the encoding.
> > + *
> > + * Returns:
> > + * The chip-relative index of the pin given by the GPIO specifier.
> > + */
> > +int of_gpio_banked_xlate(struct gpio_chip *gc,
> > +			 const struct of_phandle_args *gpiospec, u32 *flags)
> > +{
> > +	unsigned int offset = 0, bank, line, i;
> > +	const u32 *spec = gpiospec->args;
> > +
> > +	if (WARN_ON(gc->of_gpio_n_cells < 2))
> > +		return -EINVAL;
> > +
> > +	if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
> > +		return -EINVAL;
> > +
> > +	bank = (spec[0] >> gc->of_gpio_bank_shift) & gc->of_gpio_bank_mask;
> > +	line = (spec[0] >> gc->of_gpio_line_shift) & gc->of_gpio_line_mask;
> > +
> > +	if (bank >= gc->num_banks) {
> > +		dev_err(gc->parent, "invalid bank number: %u\n", bank);
> > +		return -EINVAL;
> > +	}
> > +
> > +	if (line >= gc->banks[bank]->num_lines) {
> > +		dev_err(gc->parent, "invalid line number: %u\n", line);
> > +		return -EINVAL;
> > +	}
> > +
> > +	for (i = 0; i < bank; i++)
> > +		offset += gc->banks[i]->num_lines;
> > +
> > +	if (flags)
> > +		*flags = spec[1];
> > +
> > +	return offset + line;
> > +}
> > +EXPORT_SYMBOL(of_gpio_banked_xlate);
> 
> Adding above two functions means adding new GPIO bindings (may be optional,
> but common).

No. This function is used to parse bindings that use an encoding of
(bank, line) pairs in one cell. Tegra and Tegra186 are two such
examples, though they seem to be the only ones doing this.

> 
> > +
> >   /**
> >    * of_mm_gpiochip_add_data - Add memory mapped GPIO chip (bank)
> >    * @np:		device node of the GPIO chip
> > diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> > index c15fb858848a..b3bd19b793d3 100644
> > --- a/drivers/gpio/gpiolib.c
> > +++ b/drivers/gpio/gpiolib.c
> > @@ -1765,6 +1765,57 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
> >   	gpiochip->to_irq = gpiochip_to_irq;
> >   	gpiochip->irq.default_type = type;
> >   
> > +	if (gpiochip->num_banks > 0 && !gpiochip->irq.map) {
> > +		struct gpio_irq_chip *irq = &gpiochip->irq;
> > +		unsigned int i, j, offset = 0;
> > +
> > +		if (!irq->parents) {
> > +			chip_err(gpiochip, "no parent interrupts defined\n");
> > +			return -EINVAL;
> > +		}
> > +
> > +		irq->map = devm_kcalloc(gpiochip->parent, gpiochip->ngpio,
> > +					sizeof(*irq->map), GFP_KERNEL);
> > +		if (!irq->map)
> > +			return -ENOMEM;
> > +
> > +		for (i = 0; i < gpiochip->num_banks; i++) {
> > +			struct gpio_bank *bank = gpiochip->banks[i];
> > +			unsigned int parent = bank->parent_irq;
> 
> 
> 
> > +
> > +			for (j = 0; j < bank->num_lines; j++) {
> > +				if (parent >= irq->num_parents) {
> > +					chip_err(gpiochip,
> > +						 "invalid parent interrupt: %u\n",
> > +						 parent);
> > +					return -EINVAL;
> > +				}
> > +
> > +				irq->map[offset + j] = irq->parents[parent];
> > +			}
> > +
> > +			offset += bank->num_lines;
> 
> Most of gpio drivers, you've listed in [1], have only one parent
> (waste of memory). There should be way not to store it permanently.

I'm sure we can find a way to special-case this for optimization. The
condition above could be extended to include

	gpiochip->irq.num_parents > 1

And a similar special case added to gpiochip_to_irq() to set the single
parent if no map is available.

> > +		}
> > +	}
> > +
> > +	if (gpiochip->num_banks > 0) {
> > +		unsigned int i;
> > +
> > +		for (i = 0; i < gpiochip->num_banks; i++) {
> > +			struct gpio_bank *bank = gpiochip->banks[i];
> > +			unsigned int num_lines = bank->num_lines;
> > +
> > +			bank->pending = devm_kcalloc(gpiochip->parent,
> > +						     BITS_TO_LONGS(num_lines),
> > +						     sizeof(unsigned long),
> > +						     GFP_KERNEL);
> > +			if (!bank->pending)
> > +				return -ENOMEM;
> > +
> > +			bank->chip = gpiochip;
> > +		}
> > +	}
> > +
> >   	if (gpiochip->irq.domain_ops)
> >   		ops = gpiochip->irq.domain_ops;
> >   	else
> > @@ -1973,6 +2024,53 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
> >   }
> >   EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
> >   
> > +/**
> > + * gpio_irq_chip_banked_chained_handler - interrupt handler for banked IRQ chips
> > + * @desc: IRQ descriptor
> > + *
> > + * Drivers can use this interrupt handler for banked GPIO controllers. This
> > + * implementation iterates over all banks and handles pending interrupts of
> > + * the pins associated with the bank.
> > + *
> > + * This function uses driver specific parts, split out into the
> > + * &gpio_chip.update_bank() callback, to retrieves the interrupt pending
> > + * state for each of the GPIOs exposed by the given bank.
> > + */
> > +void gpio_irq_chip_banked_chained_handler(struct irq_desc *desc)
> > +{
> > +	struct gpio_chip *gpio = irq_desc_get_handler_data(desc);
> 
> As per Patch 1 - there are no restriction to use parent_handler_data with
> this standard handler - in this case parent_handler_data might not be struct gpio_chip.

Well, that would have to be considered a driver bug. I can add a comment
to the kerneldoc about this if you have any concerns.

> > +	struct irq_chip *irq = irq_desc_get_chip(desc);
> > +	unsigned int parent = irq_desc_get_irq(desc);
> > +	struct gpio_irq_chip *chip = &gpio->irq;
> > +	unsigned int i, offset = 0;
> > +
> > +	chained_irq_enter(irq, desc);
> > +
> > +	for (i = 0; i < gpio->num_banks; i++) {
> > +		struct gpio_bank *bank = gpio->banks[i];
> > +		unsigned int line, virq;
> > +
> > +		if (parent != chip->parents[bank->parent_irq])
> > +			goto skip;
> 
> You've used this handler in gpio-tegra.c. 
> So for compatible = "nvidia,tegra20-gpio":
> - there are will be 7 parent irqs/banks.
> - gpiochip will be used as chained_handler data.
> 
> So, how will it work:
> - for bank0 it will take 1 iteration to get correct bank structure
> - but for bank7 - 7 iteration always (in hot path?)

Yes, that's correct. This could potentially be optimized by passing in
the right bank as handler data. I think the above code is fairly simple
and straightforward, and this is quite little overhead, so I'm not sure
it's very useful to optimize at this point.

> > +
> > +		chip->update_bank(bank);
> 
> Half of gpio drivers, you've listed in [1] required access to common
> Interrupt status registers before proceeding to banks.

I'm sure we can add some additional callback(s) to account for those
cases.

> > +
> > +		for_each_set_bit(line, bank->pending, bank->num_lines) {
> > +			virq = irq_find_mapping(chip->domain, offset + line);
> > +			if (WARN_ON(virq == 0))
> > +				continue;
> 
> drivers might require to do additional action before/after generic_handle_irq()
> (intel_mid_irq_handler())

That could be done from within ->update_bank(). Or it could be done in
an additional callback if necessary. Alternatively they may just not be
able to use this particular implementation and just provide their own
instead. This isn't meant to be a universal solution for every case, but
rather provide a meaningful helper that can be used when appropriate to
reduce boilerplate.

> > +
> > +			generic_handle_irq(virq);
> > +		}
> > +
> > +skip:
> > +		offset += bank->num_lines;
> > +	}
> > +
> > +	chained_irq_exit(irq, desc);
> > +}
> > +EXPORT_SYMBOL_GPL(gpio_irq_chip_banked_chained_handler);
> 
> chained IRQ handler is not RT friendly (no control from User space)

I don't understand this comment. What are you suggesting?

Thierry

> > +
> >   #else /* CONFIG_GPIOLIB_IRQCHIP */
> >   
> >   static inline int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
> > diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
> > index c453e0716228..3caa08b3d2b6 100644
> 
> [...]
> 
> >   
> >   /**
> > 
> 
> 
> 
> [1] https://www.spinics.net/lists/linux-tegra/msg31105.html
> 
> -- 
> regards,
> -grygorii

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

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

* Re: [PATCH v2 14/16] gpio: Add support for banked GPIO controllers
@ 2017-10-10 11:00             ` Thierry Reding
  0 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-10-10 11:00 UTC (permalink / raw)
  To: Grygorii Strashko
  Cc: Linus Walleij, Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

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

On Mon, Oct 09, 2017 at 04:52:21PM -0500, Grygorii Strashko wrote:
> 
> 
> On 09/28/2017 04:56 AM, Thierry Reding wrote:
> > From: Thierry Reding <treding@nvidia.com>
> > 
> > Some GPIO controllers are subdivided into multiple logical blocks called
> > banks (or ports). This is often caused by the design assigning separate
> > resources, such as register regions or interrupts, to each bank, or some
> > set of banks.
> > 
> > This commit adds support for describing controllers that have such a
> > banked design and provides common code for dealing with them.
> > 
> > Signed-off-by: Thierry Reding <treding@nvidia.com>
> > ---
> >   drivers/gpio/gpiolib-of.c   | 101 +++++++++++++++++++++++++++++++++++++++++
> >   drivers/gpio/gpiolib.c      |  98 ++++++++++++++++++++++++++++++++++++++++
> >   include/linux/gpio/driver.h | 108 ++++++++++++++++++++++++++++++++++++++++++++
> >   include/linux/of_gpio.h     |  10 ++++
> >   4 files changed, 317 insertions(+)
> > 
> > diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
> > index bfcd20699ec8..9baabe00966d 100644
> > --- a/drivers/gpio/gpiolib-of.c
> > +++ b/drivers/gpio/gpiolib-of.c
> > @@ -309,6 +309,107 @@ int of_gpio_simple_xlate(struct gpio_chip *gc,
> >   }
> >   EXPORT_SYMBOL(of_gpio_simple_xlate);
> >   
> > +/**
> > + * gpio_banked_irq_domain_xlate - decode an IRQ specifier for banked chips
> > + * @domain: IRQ domain
> > + * @np: device tree node
> > + * @spec: IRQ specifier
> > + * @size: number of cells in IRQ specifier
> > + * @hwirq: return location for the hardware IRQ number
> > + * @type: return location for the IRQ type
> > + *
> > + * Translates the IRQ specifier found in device tree into a hardware IRQ
> > + * number and an interrupt type.
> > + *
> > + * Returns:
> > + * 0 on success or a negative error code on failure.
> > + */
> > +int gpio_banked_irq_domain_xlate(struct irq_domain *domain,
> > +				 struct device_node *np,
> > +				 const u32 *spec, unsigned int size,
> > +				 unsigned long *hwirq,
> > +				 unsigned int *type)
> > +{
> > +	struct gpio_chip *gc = domain->host_data;
> > +	unsigned int bank, line, i, offset = 0;
> > +
> > +	if (size < 2)
> > +		return -EINVAL;
> > +
> > +	bank = (spec[0] >> gc->of_gpio_bank_mask) & gc->of_gpio_bank_shift;
> > +	line = (spec[0] >> gc->of_gpio_line_mask) & gc->of_gpio_line_shift;
> > +
> > +	if (bank >= gc->num_banks) {
> > +		dev_err(gc->parent, "invalid bank number: %u\n", bank);
> > +		return -EINVAL;
> > +	}
> > +
> > +	if (line >= gc->banks[bank]->num_lines) {
> > +		dev_err(gc->parent, "invalid line number: %u\n", line);
> > +		return -EINVAL;
> > +	}
> > +
> > +	for (i = 0; i < bank; i++)
> > +		offset += gc->banks[i]->num_lines;
> 
> Just to clarify, why is above iteration required?

This is used to handle the generic case where not all banks have the
same number of lines. In order to avoid having to separately deal with
non-existing lines, drivers are supposed to register only the exact
number of lines they support.

However, the binding may be written such that the (bank, line) pair is
encoded in one cell. To make that easier to construct and parse, simple
OR'ing is used, perhaps like this:

	index = (((bank) << 3) | (line))

However, if not all banks have 8 lines, this leaves blanks in the number
space when working your way back.

So the above iteration maps the sparse number space of the specifier to
the dense number space of per-chip lines.

> > +	*type = spec[1] & IRQ_TYPE_SENSE_MASK;
> > +	*hwirq = offset + line;
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(gpio_banked_irq_domain_xlate);
> > +
> > +/**
> > + * of_gpio_banked_xlate - translate GPIO specifier to a GPIO number and flags
> > + * @gc: GPIO chip
> > + * @gpiospec: GPIO specifier
> > + * @flags: return location for flags parsed from the GPIO specifier
> > + *
> > + * This translation function takes into account multiple banks that can make
> > + * up a single controller. Each bank can contain one or more pins. A single
> > + * cell in the specifier is used to represent a (bank, pin) pair, with each
> > + * encoded in different fields. The &gpio_chip.of_gpio_bank_shift and
> > + * &gpio_chip.of_gpio_bank_mask fields, and &gpio_chip.of_gpio_line_shift and
> > + * &gpio_chip.of_gpio_line_mask are used to specify the encoding.
> > + *
> > + * Returns:
> > + * The chip-relative index of the pin given by the GPIO specifier.
> > + */
> > +int of_gpio_banked_xlate(struct gpio_chip *gc,
> > +			 const struct of_phandle_args *gpiospec, u32 *flags)
> > +{
> > +	unsigned int offset = 0, bank, line, i;
> > +	const u32 *spec = gpiospec->args;
> > +
> > +	if (WARN_ON(gc->of_gpio_n_cells < 2))
> > +		return -EINVAL;
> > +
> > +	if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
> > +		return -EINVAL;
> > +
> > +	bank = (spec[0] >> gc->of_gpio_bank_shift) & gc->of_gpio_bank_mask;
> > +	line = (spec[0] >> gc->of_gpio_line_shift) & gc->of_gpio_line_mask;
> > +
> > +	if (bank >= gc->num_banks) {
> > +		dev_err(gc->parent, "invalid bank number: %u\n", bank);
> > +		return -EINVAL;
> > +	}
> > +
> > +	if (line >= gc->banks[bank]->num_lines) {
> > +		dev_err(gc->parent, "invalid line number: %u\n", line);
> > +		return -EINVAL;
> > +	}
> > +
> > +	for (i = 0; i < bank; i++)
> > +		offset += gc->banks[i]->num_lines;
> > +
> > +	if (flags)
> > +		*flags = spec[1];
> > +
> > +	return offset + line;
> > +}
> > +EXPORT_SYMBOL(of_gpio_banked_xlate);
> 
> Adding above two functions means adding new GPIO bindings (may be optional,
> but common).

No. This function is used to parse bindings that use an encoding of
(bank, line) pairs in one cell. Tegra and Tegra186 are two such
examples, though they seem to be the only ones doing this.

> 
> > +
> >   /**
> >    * of_mm_gpiochip_add_data - Add memory mapped GPIO chip (bank)
> >    * @np:		device node of the GPIO chip
> > diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> > index c15fb858848a..b3bd19b793d3 100644
> > --- a/drivers/gpio/gpiolib.c
> > +++ b/drivers/gpio/gpiolib.c
> > @@ -1765,6 +1765,57 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
> >   	gpiochip->to_irq = gpiochip_to_irq;
> >   	gpiochip->irq.default_type = type;
> >   
> > +	if (gpiochip->num_banks > 0 && !gpiochip->irq.map) {
> > +		struct gpio_irq_chip *irq = &gpiochip->irq;
> > +		unsigned int i, j, offset = 0;
> > +
> > +		if (!irq->parents) {
> > +			chip_err(gpiochip, "no parent interrupts defined\n");
> > +			return -EINVAL;
> > +		}
> > +
> > +		irq->map = devm_kcalloc(gpiochip->parent, gpiochip->ngpio,
> > +					sizeof(*irq->map), GFP_KERNEL);
> > +		if (!irq->map)
> > +			return -ENOMEM;
> > +
> > +		for (i = 0; i < gpiochip->num_banks; i++) {
> > +			struct gpio_bank *bank = gpiochip->banks[i];
> > +			unsigned int parent = bank->parent_irq;
> 
> 
> 
> > +
> > +			for (j = 0; j < bank->num_lines; j++) {
> > +				if (parent >= irq->num_parents) {
> > +					chip_err(gpiochip,
> > +						 "invalid parent interrupt: %u\n",
> > +						 parent);
> > +					return -EINVAL;
> > +				}
> > +
> > +				irq->map[offset + j] = irq->parents[parent];
> > +			}
> > +
> > +			offset += bank->num_lines;
> 
> Most of gpio drivers, you've listed in [1], have only one parent
> (waste of memory). There should be way not to store it permanently.

I'm sure we can find a way to special-case this for optimization. The
condition above could be extended to include

	gpiochip->irq.num_parents > 1

And a similar special case added to gpiochip_to_irq() to set the single
parent if no map is available.

> > +		}
> > +	}
> > +
> > +	if (gpiochip->num_banks > 0) {
> > +		unsigned int i;
> > +
> > +		for (i = 0; i < gpiochip->num_banks; i++) {
> > +			struct gpio_bank *bank = gpiochip->banks[i];
> > +			unsigned int num_lines = bank->num_lines;
> > +
> > +			bank->pending = devm_kcalloc(gpiochip->parent,
> > +						     BITS_TO_LONGS(num_lines),
> > +						     sizeof(unsigned long),
> > +						     GFP_KERNEL);
> > +			if (!bank->pending)
> > +				return -ENOMEM;
> > +
> > +			bank->chip = gpiochip;
> > +		}
> > +	}
> > +
> >   	if (gpiochip->irq.domain_ops)
> >   		ops = gpiochip->irq.domain_ops;
> >   	else
> > @@ -1973,6 +2024,53 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
> >   }
> >   EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
> >   
> > +/**
> > + * gpio_irq_chip_banked_chained_handler - interrupt handler for banked IRQ chips
> > + * @desc: IRQ descriptor
> > + *
> > + * Drivers can use this interrupt handler for banked GPIO controllers. This
> > + * implementation iterates over all banks and handles pending interrupts of
> > + * the pins associated with the bank.
> > + *
> > + * This function uses driver specific parts, split out into the
> > + * &gpio_chip.update_bank() callback, to retrieves the interrupt pending
> > + * state for each of the GPIOs exposed by the given bank.
> > + */
> > +void gpio_irq_chip_banked_chained_handler(struct irq_desc *desc)
> > +{
> > +	struct gpio_chip *gpio = irq_desc_get_handler_data(desc);
> 
> As per Patch 1 - there are no restriction to use parent_handler_data with
> this standard handler - in this case parent_handler_data might not be struct gpio_chip.

Well, that would have to be considered a driver bug. I can add a comment
to the kerneldoc about this if you have any concerns.

> > +	struct irq_chip *irq = irq_desc_get_chip(desc);
> > +	unsigned int parent = irq_desc_get_irq(desc);
> > +	struct gpio_irq_chip *chip = &gpio->irq;
> > +	unsigned int i, offset = 0;
> > +
> > +	chained_irq_enter(irq, desc);
> > +
> > +	for (i = 0; i < gpio->num_banks; i++) {
> > +		struct gpio_bank *bank = gpio->banks[i];
> > +		unsigned int line, virq;
> > +
> > +		if (parent != chip->parents[bank->parent_irq])
> > +			goto skip;
> 
> You've used this handler in gpio-tegra.c. 
> So for compatible = "nvidia,tegra20-gpio":
> - there are will be 7 parent irqs/banks.
> - gpiochip will be used as chained_handler data.
> 
> So, how will it work:
> - for bank0 it will take 1 iteration to get correct bank structure
> - but for bank7 - 7 iteration always (in hot path?)

Yes, that's correct. This could potentially be optimized by passing in
the right bank as handler data. I think the above code is fairly simple
and straightforward, and this is quite little overhead, so I'm not sure
it's very useful to optimize at this point.

> > +
> > +		chip->update_bank(bank);
> 
> Half of gpio drivers, you've listed in [1] required access to common
> Interrupt status registers before proceeding to banks.

I'm sure we can add some additional callback(s) to account for those
cases.

> > +
> > +		for_each_set_bit(line, bank->pending, bank->num_lines) {
> > +			virq = irq_find_mapping(chip->domain, offset + line);
> > +			if (WARN_ON(virq == 0))
> > +				continue;
> 
> drivers might require to do additional action before/after generic_handle_irq()
> (intel_mid_irq_handler())

That could be done from within ->update_bank(). Or it could be done in
an additional callback if necessary. Alternatively they may just not be
able to use this particular implementation and just provide their own
instead. This isn't meant to be a universal solution for every case, but
rather provide a meaningful helper that can be used when appropriate to
reduce boilerplate.

> > +
> > +			generic_handle_irq(virq);
> > +		}
> > +
> > +skip:
> > +		offset += bank->num_lines;
> > +	}
> > +
> > +	chained_irq_exit(irq, desc);
> > +}
> > +EXPORT_SYMBOL_GPL(gpio_irq_chip_banked_chained_handler);
> 
> chained IRQ handler is not RT friendly (no control from User space)

I don't understand this comment. What are you suggesting?

Thierry

> > +
> >   #else /* CONFIG_GPIOLIB_IRQCHIP */
> >   
> >   static inline int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
> > diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
> > index c453e0716228..3caa08b3d2b6 100644
> 
> [...]
> 
> >   
> >   /**
> > 
> 
> 
> 
> [1] https://www.spinics.net/lists/linux-tegra/msg31105.html
> 
> -- 
> regards,
> -grygorii

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

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

* Re: [PATCH v2 00/16] gpio: Tight IRQ chip integration and banked infrastructure
  2017-10-09 21:56           ` Grygorii Strashko
@ 2017-10-10 11:27               ` Thierry Reding
  -1 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-10-10 11:27 UTC (permalink / raw)
  To: Grygorii Strashko
  Cc: Linus Walleij, Jonathan Hunter,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

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

On Mon, Oct 09, 2017 at 04:56:57PM -0500, Grygorii Strashko wrote:
> 
> 
> On 10/06/2017 06:07 AM, Thierry Reding wrote:
> > On Thu, Sep 28, 2017 at 09:22:17AM -0500, Grygorii Strashko wrote:
> >>
> >>
> >> On 09/28/2017 04:56 AM, Thierry Reding wrote:
> >>> From: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> >>>
> >>> Hi Linus,
> >>>
> >>> here's the latest series of patches that implement the tighter IRQ chip
> >>> integration as well as the banked GPIO infrastructure that we had
> >>> discussed a couple of weeks/months back.
> >>>
> >>> The first couple of patches are mostly preparatory work in order to
> >>> consolidate all IRQ chip related fields in a new structure and create
> >>> the base functionality for adding IRQ chips.
> >>>
> >>> After that, I've added the Tegra186 GPIO support patch that makes use of
> >>> the new tight integration.
> >>>
> >>> To round things off the new banked GPIO infrastructure is added (along
> >>> with some more preparatory work), followed by the conversion of the two
> >>> Tegra GPIO drivers to the new infrastructure.
> >>
> >> Hm. So you've ignored my comments [1].
> >>
> >> Sry, but I do not agree with this series.
> >> - no prof that it can be re-used by other drivers than tegra
> >>   (at least I do not see reasons to re-use it for any TI drivers)
> > 
> > I had done some research based on Linus' feedback from an earlier series
> > and identified the following potential candidates[0] that could move to
> > this new infrastructure:
> > 
> 
> below based on code check:
> 
> > 	- gpio-intel-mid.c
> 
> one irq per all gpios in controller
> 
> > 	- gpio-merrifield.c
> 
> one irq per all gpios in controller
> 
> > 	- gpio-pca953x.c
> one irq per all gpios in controller
> 
> > 	- gpio-stmpe.c
> one irq per all gpios in controller
> > 	- gpio-tc3589x.c
> one irq per all gpios in controller
> > 	- gpio-ws16c48.c
> 
> one irq per all gpios in controller

I explained in another subthread how we could cater for this particular
use-case.

> > Note that this is based on code inspection rather than DT inspection,
> > because that's fundamentally flawed. If you look at this from a DT
> > perspective you're going to be tempted to change the DT bindings, but
> > you can't do that because of backwards compatiblity. This new framework
> > also doesn't address the issues at that level, but rather tries to be
> > some common code that is otherwise duplicated in one way or another in
> > various drivers and therefore hard to maintain. This is what Linus had
> > originally requested, and that's what the series does.
> 
> I've looked at this again, and again. I've looked on drivers listed above.
> Sry, I do not see how this change can improve/simplify above drivers :(
> May be it will clean up my doubts, if it will be possible to convert more
> drivers?

I'm reluctant to spend more work on this and get Tegra186 GPIO support
delayed indefinitely until every other driver has been converted. The
Tegra186 GPIO driver is now more than a year old and I've got a few
dozen patches that depend on GPIO functionality that we currently can't
merge because this unification work has been going on for more than 6
months. This has been a very frustrating experience overall.

I think this series is in good enough shape for now. It improves the
situation in general. I also don't see anything in here that couldn't be
further improved should the need arise.

If this really isn't useful at all, can we please at least get patches
1-11 merged? T hey are independent of the banked infrastructure work in
the last couple of patches.

> >> - no split
> > 
> > What does this mean? The series is nicely split into separate patches,
> > so each one individually is easy to review. I've also gone through quite
> > some trouble to make sure everything builds fine after each patch, so
> > it's possible to apply individual bits of the series. For example we
> > could opt to apply everything up to the banked GPIO support if that's
> > still contentious.
> 
> i've commented it in [1]. copy paste here
> 
> >>
> So, can it be split? I think, patches which reorganize gpio irqchip specific fields placement 
> and move them in gpio_irq_chip can be considered separately if they will not introduce
> functional changes. Also, omap changes can be considered separately.
> (Pay attention that new fields introduced in patch 1). 
> >>
> 
> This will reduce size of your series and concentrate review attention on actual functional changes.
> 
> 
> [1] https://lkml.org/lkml/2017/9/15/442

I could of course split the series into multiple parts, but then it
becomes difficult to represent dependencies. The changes you mention are
already split into separate commits and I even made sure that they keep
bisectibility. I've sent them together primarily to keep them in the
order that they need to be applied in to simplify things.

I don't see how splitting up the series any further is going to simplify
review. If you want to only review the banked infrastructure change, can
you not just focus on that patch and ignore the first ten since they are
not actually functional changes?

> 
> > 
> >> - all GPIO IRQs mapped statically
> > 
> > This series predates your work on the dynamic IRQ mapping, so I hadn't
> > picked up those changes. This should be easily solved by the attached
> > patch, though.
> > 
> >> - irq->map[offset + j] = irq->parents[parent]; holds IRQs for all pins
> >>    which is waste of memory
> > 
> > It's the only way to generically do this. Also I don't think this wastes
> > that much memory. We have one unsigned int per pin, which even for very
> > large GPIO controllers is unlikely to exceed one 4 KiB page.
> 
> for system with <128M of memory even 4k is a win.

I suspect that such systems won't have GPIOs where this infrastructure
would be used, or where the number of GPIOs would be problematic.

Also, this is supposed to be generic infrastructure and that usually
comes at some price. I don't know how to do this without the mapping,
but I'm certainly open to suggestions.

> >> - DT binding changes not documented and no DT examples
> > 
> > That's because this is completely orthogonal to DT bindings. We can't
> > make any changes to the bindings because of ABI stability.
> > 
> >> - below is ugly ;)
> >> +	bank = (spec[0] >> gc->of_gpio_bank_mask) & gc->of_gpio_bank_shift;
> >> +	pin = (spec[0] >> gc->of_gpio_pin_mask) & gc->of_gpio_pin_shift;
> > 
> > If by ugly you mean wrong, then yes, it's actually the wrong way around.
> > It should be:
> > 
> > 	bank = (spec[0] >> gc->of_gpio_bank_shift) & gc->of_gpio_bank_mask;
> > 	line = (spec[0] >> gc->of_gpio_line_shift) & gc->of_gpio_line_mask;
> 
>  
> Wrong yep. And No. What I do not like is encoding bank & line in the same field.

This is not about liking or disliking the encoding. The encoding is
already defined in the bindings for Tegra and Tegra186, so this isn't up
for discussion.

> It creates some not clear DT standard bindings requirements as for me, comparing to the
> current well known GPIO bindings 
>  gpios = <&[controller] [line number in controller] [flags]>;
> line number in controller ::= [0..max lines]

Yes, that's because this is specifically for banked controllers. It
seems to me like most other bindings for banked controllers simply use a
linear mapping, in which case the simple example above would work.

Tegra seems somewhat of an exception because the DT bindings use the
(bank, line) pair encoding to reflect the names given to the lines in
technical reference manuals. I like this because it makes the DTS files
very easy to read and relate to schematics.

> Actually, as per gpio.txt:
> "Note that gpio-specifier length is controller dependent.  In the
> above example, &gpio1 uses 2 cells to specify a gpio, while &gpio2
> only uses one.", 
> so, if this going to be part of gpiolib it should be
>  described in bindings/gpio/gpio.txt (or some other documents), as
>  above note will not be exactly correct and new "banked" gpio controllers
> will be expected to use thin new binding.

Yeah, that makes sense. I'll work on a patch that updates the binding
documentation to include this particular encoding. Again, this is not
intended to replace existing bindings because they may not be
compatible. However, bindings for new banked controllers may be able
to reuse this if it suits their needs.

Also, note that the rest of the banked infrastructure can be used
independently of the ->xlate() callback. Drivers are free to use the
of_gpio_simple_xlate() with the rest of the banked infrastructure to
simplify the driver code.

Thierry

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

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

* Re: [PATCH v2 00/16] gpio: Tight IRQ chip integration and banked infrastructure
@ 2017-10-10 11:27               ` Thierry Reding
  0 siblings, 0 replies; 56+ messages in thread
From: Thierry Reding @ 2017-10-10 11:27 UTC (permalink / raw)
  To: Grygorii Strashko
  Cc: Linus Walleij, Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

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

On Mon, Oct 09, 2017 at 04:56:57PM -0500, Grygorii Strashko wrote:
> 
> 
> On 10/06/2017 06:07 AM, Thierry Reding wrote:
> > On Thu, Sep 28, 2017 at 09:22:17AM -0500, Grygorii Strashko wrote:
> >>
> >>
> >> On 09/28/2017 04:56 AM, Thierry Reding wrote:
> >>> From: Thierry Reding <treding@nvidia.com>
> >>>
> >>> Hi Linus,
> >>>
> >>> here's the latest series of patches that implement the tighter IRQ chip
> >>> integration as well as the banked GPIO infrastructure that we had
> >>> discussed a couple of weeks/months back.
> >>>
> >>> The first couple of patches are mostly preparatory work in order to
> >>> consolidate all IRQ chip related fields in a new structure and create
> >>> the base functionality for adding IRQ chips.
> >>>
> >>> After that, I've added the Tegra186 GPIO support patch that makes use of
> >>> the new tight integration.
> >>>
> >>> To round things off the new banked GPIO infrastructure is added (along
> >>> with some more preparatory work), followed by the conversion of the two
> >>> Tegra GPIO drivers to the new infrastructure.
> >>
> >> Hm. So you've ignored my comments [1].
> >>
> >> Sry, but I do not agree with this series.
> >> - no prof that it can be re-used by other drivers than tegra
> >>   (at least I do not see reasons to re-use it for any TI drivers)
> > 
> > I had done some research based on Linus' feedback from an earlier series
> > and identified the following potential candidates[0] that could move to
> > this new infrastructure:
> > 
> 
> below based on code check:
> 
> > 	- gpio-intel-mid.c
> 
> one irq per all gpios in controller
> 
> > 	- gpio-merrifield.c
> 
> one irq per all gpios in controller
> 
> > 	- gpio-pca953x.c
> one irq per all gpios in controller
> 
> > 	- gpio-stmpe.c
> one irq per all gpios in controller
> > 	- gpio-tc3589x.c
> one irq per all gpios in controller
> > 	- gpio-ws16c48.c
> 
> one irq per all gpios in controller

I explained in another subthread how we could cater for this particular
use-case.

> > Note that this is based on code inspection rather than DT inspection,
> > because that's fundamentally flawed. If you look at this from a DT
> > perspective you're going to be tempted to change the DT bindings, but
> > you can't do that because of backwards compatiblity. This new framework
> > also doesn't address the issues at that level, but rather tries to be
> > some common code that is otherwise duplicated in one way or another in
> > various drivers and therefore hard to maintain. This is what Linus had
> > originally requested, and that's what the series does.
> 
> I've looked at this again, and again. I've looked on drivers listed above.
> Sry, I do not see how this change can improve/simplify above drivers :(
> May be it will clean up my doubts, if it will be possible to convert more
> drivers?

I'm reluctant to spend more work on this and get Tegra186 GPIO support
delayed indefinitely until every other driver has been converted. The
Tegra186 GPIO driver is now more than a year old and I've got a few
dozen patches that depend on GPIO functionality that we currently can't
merge because this unification work has been going on for more than 6
months. This has been a very frustrating experience overall.

I think this series is in good enough shape for now. It improves the
situation in general. I also don't see anything in here that couldn't be
further improved should the need arise.

If this really isn't useful at all, can we please at least get patches
1-11 merged? T hey are independent of the banked infrastructure work in
the last couple of patches.

> >> - no split
> > 
> > What does this mean? The series is nicely split into separate patches,
> > so each one individually is easy to review. I've also gone through quite
> > some trouble to make sure everything builds fine after each patch, so
> > it's possible to apply individual bits of the series. For example we
> > could opt to apply everything up to the banked GPIO support if that's
> > still contentious.
> 
> i've commented it in [1]. copy paste here
> 
> >>
> So, can it be split? I think, patches which reorganize gpio irqchip specific fields placement 
> and move them in gpio_irq_chip can be considered separately if they will not introduce
> functional changes. Also, omap changes can be considered separately.
> (Pay attention that new fields introduced in patch 1). 
> >>
> 
> This will reduce size of your series and concentrate review attention on actual functional changes.
> 
> 
> [1] https://lkml.org/lkml/2017/9/15/442

I could of course split the series into multiple parts, but then it
becomes difficult to represent dependencies. The changes you mention are
already split into separate commits and I even made sure that they keep
bisectibility. I've sent them together primarily to keep them in the
order that they need to be applied in to simplify things.

I don't see how splitting up the series any further is going to simplify
review. If you want to only review the banked infrastructure change, can
you not just focus on that patch and ignore the first ten since they are
not actually functional changes?

> 
> > 
> >> - all GPIO IRQs mapped statically
> > 
> > This series predates your work on the dynamic IRQ mapping, so I hadn't
> > picked up those changes. This should be easily solved by the attached
> > patch, though.
> > 
> >> - irq->map[offset + j] = irq->parents[parent]; holds IRQs for all pins
> >>    which is waste of memory
> > 
> > It's the only way to generically do this. Also I don't think this wastes
> > that much memory. We have one unsigned int per pin, which even for very
> > large GPIO controllers is unlikely to exceed one 4 KiB page.
> 
> for system with <128M of memory even 4k is a win.

I suspect that such systems won't have GPIOs where this infrastructure
would be used, or where the number of GPIOs would be problematic.

Also, this is supposed to be generic infrastructure and that usually
comes at some price. I don't know how to do this without the mapping,
but I'm certainly open to suggestions.

> >> - DT binding changes not documented and no DT examples
> > 
> > That's because this is completely orthogonal to DT bindings. We can't
> > make any changes to the bindings because of ABI stability.
> > 
> >> - below is ugly ;)
> >> +	bank = (spec[0] >> gc->of_gpio_bank_mask) & gc->of_gpio_bank_shift;
> >> +	pin = (spec[0] >> gc->of_gpio_pin_mask) & gc->of_gpio_pin_shift;
> > 
> > If by ugly you mean wrong, then yes, it's actually the wrong way around.
> > It should be:
> > 
> > 	bank = (spec[0] >> gc->of_gpio_bank_shift) & gc->of_gpio_bank_mask;
> > 	line = (spec[0] >> gc->of_gpio_line_shift) & gc->of_gpio_line_mask;
> 
>  
> Wrong yep. And No. What I do not like is encoding bank & line in the same field.

This is not about liking or disliking the encoding. The encoding is
already defined in the bindings for Tegra and Tegra186, so this isn't up
for discussion.

> It creates some not clear DT standard bindings requirements as for me, comparing to the
> current well known GPIO bindings 
>  gpios = <&[controller] [line number in controller] [flags]>;
> line number in controller ::= [0..max lines]

Yes, that's because this is specifically for banked controllers. It
seems to me like most other bindings for banked controllers simply use a
linear mapping, in which case the simple example above would work.

Tegra seems somewhat of an exception because the DT bindings use the
(bank, line) pair encoding to reflect the names given to the lines in
technical reference manuals. I like this because it makes the DTS files
very easy to read and relate to schematics.

> Actually, as per gpio.txt:
> "Note that gpio-specifier length is controller dependent.  In the
> above example, &gpio1 uses 2 cells to specify a gpio, while &gpio2
> only uses one.", 
> so, if this going to be part of gpiolib it should be
>  described in bindings/gpio/gpio.txt (or some other documents), as
>  above note will not be exactly correct and new "banked" gpio controllers
> will be expected to use thin new binding.

Yeah, that makes sense. I'll work on a patch that updates the binding
documentation to include this particular encoding. Again, this is not
intended to replace existing bindings because they may not be
compatible. However, bindings for new banked controllers may be able
to reuse this if it suits their needs.

Also, note that the rest of the banked infrastructure can be used
independently of the ->xlate() callback. Drivers are free to use the
of_gpio_simple_xlate() with the rest of the banked infrastructure to
simplify the driver code.

Thierry

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

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

* Re: [PATCH v2 15/16] gpio: tegra: Use banked GPIO infrastructure
  2017-10-10 10:27         ` Thierry Reding
@ 2017-10-10 19:31             ` Grygorii Strashko
  0 siblings, 0 replies; 56+ messages in thread
From: Grygorii Strashko @ 2017-10-10 19:31 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Linus Walleij, Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel



On 10/10/2017 05:27 AM, Thierry Reding wrote:
> On Mon, Oct 09, 2017 at 04:22:29PM -0500, Grygorii Strashko wrote:
>>
>>
>> On 09/28/2017 04:56 AM, Thierry Reding wrote:
>>> From: Thierry Reding <treding@nvidia.com>
>>>
>>> Convert the Tegra GPIO driver to use the banked GPIO infrastructure,
>>> which simplifies some parts of the driver.
>>>
>>> Signed-off-by: Thierry Reding <treding@nvidia.com>
>>> ---
>>>    drivers/gpio/Kconfig      |   1 +
>>>    drivers/gpio/gpio-tegra.c | 203 ++++++++++++++++++++++------------------------
>>>    2 files changed, 98 insertions(+), 106 deletions(-)
>>>
>>> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
>>> index db3e446ad9b3..458157d6d491 100644
>>> --- a/drivers/gpio/Kconfig
>>> +++ b/drivers/gpio/Kconfig
>>> @@ -439,6 +439,7 @@ config GPIO_TEGRA
>>>    	default ARCH_TEGRA
>>>    	depends on ARCH_TEGRA || COMPILE_TEST
>>
>> ...
>>
>>> @@ -616,76 +617,66 @@ static int tegra_gpio_probe(struct platform_device *pdev)
>>>    	tgi->ic.irq_set_wake		= tegra_gpio_irq_set_wake;
>>>    #endif
>>>    
>>> +	irq = &tgi->gc.irq;
>>> +	irq->chip = &tgi->ic;
>>> +	irq->handler = handle_simple_irq;
>>> +	irq->lock_key = &tegra_gpio_lock_class;
>>
>> As per current gpiolib design lockdep lock_class_key is assigned
>> automatically and hidden from gpiolib users.
>> Why do you need to do the same manually?
> 
> Can you elaborate? I don't see the lock class key getting set anywhere.
> gpiolib does set if for interrupts, but only if the drivers assigned it
> before adding the chip.
> 

include/linux/gpio/driver.h

#ifdef CONFIG_LOCKDEP

/*
 * Lockdep requires that each irqchip instance be created with a
 * unique key so as to avoid unnecessary warnings. This upfront
 * boilerplate static inlines provides such a key for each
 * unique instance.
 */
static inline int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
				       struct irq_chip *irqchip,
				       unsigned int first_irq,
				       irq_flow_handler_t handler,
				       unsigned int type)
{
	static struct lock_class_key key;
^^^

	return gpiochip_irqchip_add_key(gpiochip, irqchip, first_irq,
					handler, type, false, &key);
}
 

-- 
regards,
-grygorii

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

* Re: [PATCH v2 15/16] gpio: tegra: Use banked GPIO infrastructure
@ 2017-10-10 19:31             ` Grygorii Strashko
  0 siblings, 0 replies; 56+ messages in thread
From: Grygorii Strashko @ 2017-10-10 19:31 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Linus Walleij, Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel



On 10/10/2017 05:27 AM, Thierry Reding wrote:
> On Mon, Oct 09, 2017 at 04:22:29PM -0500, Grygorii Strashko wrote:
>>
>>
>> On 09/28/2017 04:56 AM, Thierry Reding wrote:
>>> From: Thierry Reding <treding@nvidia.com>
>>>
>>> Convert the Tegra GPIO driver to use the banked GPIO infrastructure,
>>> which simplifies some parts of the driver.
>>>
>>> Signed-off-by: Thierry Reding <treding@nvidia.com>
>>> ---
>>>    drivers/gpio/Kconfig      |   1 +
>>>    drivers/gpio/gpio-tegra.c | 203 ++++++++++++++++++++++------------------------
>>>    2 files changed, 98 insertions(+), 106 deletions(-)
>>>
>>> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
>>> index db3e446ad9b3..458157d6d491 100644
>>> --- a/drivers/gpio/Kconfig
>>> +++ b/drivers/gpio/Kconfig
>>> @@ -439,6 +439,7 @@ config GPIO_TEGRA
>>>    	default ARCH_TEGRA
>>>    	depends on ARCH_TEGRA || COMPILE_TEST
>>
>> ...
>>
>>> @@ -616,76 +617,66 @@ static int tegra_gpio_probe(struct platform_device *pdev)
>>>    	tgi->ic.irq_set_wake		= tegra_gpio_irq_set_wake;
>>>    #endif
>>>    
>>> +	irq = &tgi->gc.irq;
>>> +	irq->chip = &tgi->ic;
>>> +	irq->handler = handle_simple_irq;
>>> +	irq->lock_key = &tegra_gpio_lock_class;
>>
>> As per current gpiolib design lockdep lock_class_key is assigned
>> automatically and hidden from gpiolib users.
>> Why do you need to do the same manually?
> 
> Can you elaborate? I don't see the lock class key getting set anywhere.
> gpiolib does set if for interrupts, but only if the drivers assigned it
> before adding the chip.
> 

include/linux/gpio/driver.h

#ifdef CONFIG_LOCKDEP

/*
 * Lockdep requires that each irqchip instance be created with a
 * unique key so as to avoid unnecessary warnings. This upfront
 * boilerplate static inlines provides such a key for each
 * unique instance.
 */
static inline int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
				       struct irq_chip *irqchip,
				       unsigned int first_irq,
				       irq_flow_handler_t handler,
				       unsigned int type)
{
	static struct lock_class_key key;
^^^

	return gpiochip_irqchip_add_key(gpiochip, irqchip, first_irq,
					handler, type, false, &key);
}
 

-- 
regards,
-grygorii

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

* Re: [PATCH v2 14/16] gpio: Add support for banked GPIO controllers
  2017-10-10 11:00             ` Thierry Reding
@ 2017-10-10 22:12               ` Grygorii Strashko
  -1 siblings, 0 replies; 56+ messages in thread
From: Grygorii Strashko @ 2017-10-10 22:12 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Linus Walleij, Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel



On 10/10/2017 06:00 AM, Thierry Reding wrote:
> On Mon, Oct 09, 2017 at 04:52:21PM -0500, Grygorii Strashko wrote:
>>
>>
>> On 09/28/2017 04:56 AM, Thierry Reding wrote:
>>> From: Thierry Reding <treding@nvidia.com>
>>>
>>> Some GPIO controllers are subdivided into multiple logical blocks called
>>> banks (or ports). This is often caused by the design assigning separate
>>> resources, such as register regions or interrupts, to each bank, or some
>>> set of banks.
>>>
>>> This commit adds support for describing controllers that have such a
>>> banked design and provides common code for dealing with them.
>>>
>>> Signed-off-by: Thierry Reding <treding@nvidia.com>
>>> ---
>>>    drivers/gpio/gpiolib-of.c   | 101 +++++++++++++++++++++++++++++++++++++++++
>>>    drivers/gpio/gpiolib.c      |  98 ++++++++++++++++++++++++++++++++++++++++
>>>    include/linux/gpio/driver.h | 108 ++++++++++++++++++++++++++++++++++++++++++++
>>>    include/linux/of_gpio.h     |  10 ++++
>>>    4 files changed, 317 insertions(+)
>>>
>>> diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
>>> index bfcd20699ec8..9baabe00966d 100644
>>> --- a/drivers/gpio/gpiolib-of.c
>>> +++ b/drivers/gpio/gpiolib-of.c
>>> @@ -309,6 +309,107 @@ int of_gpio_simple_xlate(struct gpio_chip *gc,
>>>    }
>>>    EXPORT_SYMBOL(of_gpio_simple_xlate);
>>>    
>>> +/**
>>> + * gpio_banked_irq_domain_xlate - decode an IRQ specifier for banked chips
>>> + * @domain: IRQ domain
>>> + * @np: device tree node
>>> + * @spec: IRQ specifier
>>> + * @size: number of cells in IRQ specifier
>>> + * @hwirq: return location for the hardware IRQ number
>>> + * @type: return location for the IRQ type
>>> + *
>>> + * Translates the IRQ specifier found in device tree into a hardware IRQ
>>> + * number and an interrupt type.
>>> + *
>>> + * Returns:
>>> + * 0 on success or a negative error code on failure.
>>> + */
>>> +int gpio_banked_irq_domain_xlate(struct irq_domain *domain,
>>> +				 struct device_node *np,
>>> +				 const u32 *spec, unsigned int size,
>>> +				 unsigned long *hwirq,
>>> +				 unsigned int *type)
>>> +{
>>> +	struct gpio_chip *gc = domain->host_data;
>>> +	unsigned int bank, line, i, offset = 0;
>>> +
>>> +	if (size < 2)
>>> +		return -EINVAL;
>>> +
>>> +	bank = (spec[0] >> gc->of_gpio_bank_mask) & gc->of_gpio_bank_shift;
>>> +	line = (spec[0] >> gc->of_gpio_line_mask) & gc->of_gpio_line_shift;
>>> +
>>> +	if (bank >= gc->num_banks) {
>>> +		dev_err(gc->parent, "invalid bank number: %u\n", bank);
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	if (line >= gc->banks[bank]->num_lines) {
>>> +		dev_err(gc->parent, "invalid line number: %u\n", line);
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	for (i = 0; i < bank; i++)
>>> +		offset += gc->banks[i]->num_lines;
>>
>> Just to clarify, why is above iteration required?
> 
> This is used to handle the generic case where not all banks have the
> same number of lines. In order to avoid having to separately deal with
> non-existing lines, drivers are supposed to register only the exact
> number of lines they support.
> 
> However, the binding may be written such that the (bank, line) pair is
> encoded in one cell. To make that easier to construct and parse, simple
> OR'ing is used, perhaps like this:
> 
> 	index = (((bank) << 3) | (line))
> 
> However, if not all banks have 8 lines, this leaves blanks in the number
> space when working your way back.
> 
> So the above iteration maps the sparse number space of the specifier to
> the dense number space of per-chip lines.

Wouldn't it be reasonable to save GPIO offset in struct gpio_bank - it's
one time configuration.

> 
>>> +	*type = spec[1] & IRQ_TYPE_SENSE_MASK;
>>> +	*hwirq = offset + line;
>>> +
>>> +	return 0;
>>> +}
>>> +EXPORT_SYMBOL_GPL(gpio_banked_irq_domain_xlate);
>>> +
>>> +/**
>>> + * of_gpio_banked_xlate - translate GPIO specifier to a GPIO number and flags
>>> + * @gc: GPIO chip
>>> + * @gpiospec: GPIO specifier
>>> + * @flags: return location for flags parsed from the GPIO specifier
>>> + *
>>> + * This translation function takes into account multiple banks that can make
>>> + * up a single controller. Each bank can contain one or more pins. A single
>>> + * cell in the specifier is used to represent a (bank, pin) pair, with each
>>> + * encoded in different fields. The &gpio_chip.of_gpio_bank_shift and
>>> + * &gpio_chip.of_gpio_bank_mask fields, and &gpio_chip.of_gpio_line_shift and
>>> + * &gpio_chip.of_gpio_line_mask are used to specify the encoding.
>>> + *
>>> + * Returns:
>>> + * The chip-relative index of the pin given by the GPIO specifier.
>>> + */
>>> +int of_gpio_banked_xlate(struct gpio_chip *gc,
>>> +			 const struct of_phandle_args *gpiospec, u32 *flags)
>>> +{
>>> +	unsigned int offset = 0, bank, line, i;
>>> +	const u32 *spec = gpiospec->args;
>>> +
>>> +	if (WARN_ON(gc->of_gpio_n_cells < 2))
>>> +		return -EINVAL;
>>> +
>>> +	if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
>>> +		return -EINVAL;
>>> +
>>> +	bank = (spec[0] >> gc->of_gpio_bank_shift) & gc->of_gpio_bank_mask;
>>> +	line = (spec[0] >> gc->of_gpio_line_shift) & gc->of_gpio_line_mask;
>>> +
>>> +	if (bank >= gc->num_banks) {
>>> +		dev_err(gc->parent, "invalid bank number: %u\n", bank);
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	if (line >= gc->banks[bank]->num_lines) {
>>> +		dev_err(gc->parent, "invalid line number: %u\n", line);
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	for (i = 0; i < bank; i++)
>>> +		offset += gc->banks[i]->num_lines;
>>> +
>>> +	if (flags)
>>> +		*flags = spec[1];
>>> +
>>> +	return offset + line;
>>> +}
>>> +EXPORT_SYMBOL(of_gpio_banked_xlate);
>>
>> Adding above two functions means adding new GPIO bindings (may be optional,
>> but common).
> 
> No. This function is used to parse bindings that use an encoding of
> (bank, line) pairs in one cell. Tegra and Tegra186 are two such
> examples, though they seem to be the only ones doing this.

They are only one such examples ;)

Again two cells <bank/port> <pin> mach more user friendly as for me.


> 
>>
>>> +
>>>    /**
>>>     * of_mm_gpiochip_add_data - Add memory mapped GPIO chip (bank)
>>>     * @np:		device node of the GPIO chip
>>> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
>>> index c15fb858848a..b3bd19b793d3 100644
>>> --- a/drivers/gpio/gpiolib.c
>>> +++ b/drivers/gpio/gpiolib.c
>>> @@ -1765,6 +1765,57 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
>>>    	gpiochip->to_irq = gpiochip_to_irq;
>>>    	gpiochip->irq.default_type = type;
>>>    
>>> +	if (gpiochip->num_banks > 0 && !gpiochip->irq.map) {
>>> +		struct gpio_irq_chip *irq = &gpiochip->irq;
>>> +		unsigned int i, j, offset = 0;
>>> +
>>> +		if (!irq->parents) {
>>> +			chip_err(gpiochip, "no parent interrupts defined\n");
>>> +			return -EINVAL;
>>> +		}
>>> +
>>> +		irq->map = devm_kcalloc(gpiochip->parent, gpiochip->ngpio,
>>> +					sizeof(*irq->map), GFP_KERNEL);
>>> +		if (!irq->map)
>>> +			return -ENOMEM;
>>> +
>>> +		for (i = 0; i < gpiochip->num_banks; i++) {
>>> +			struct gpio_bank *bank = gpiochip->banks[i];
>>> +			unsigned int parent = bank->parent_irq;
>>
>>
>>
>>> +
>>> +			for (j = 0; j < bank->num_lines; j++) {
>>> +				if (parent >= irq->num_parents) {
>>> +					chip_err(gpiochip,
>>> +						 "invalid parent interrupt: %u\n",
>>> +						 parent);
>>> +					return -EINVAL;
>>> +				}
>>> +
>>> +				irq->map[offset + j] = irq->parents[parent];
>>> +			}
>>> +
>>> +			offset += bank->num_lines;
>>
>> Most of gpio drivers, you've listed in [1], have only one parent
>> (waste of memory). There should be way not to store it permanently.
> 
> I'm sure we can find a way to special-case this for optimization. The
> condition above could be extended to include
> 
> 	gpiochip->irq.num_parents > 1
> 
> And a similar special case added to gpiochip_to_irq() to set the single
> parent if no map is available.


> 
>>> +		}
>>> +	}
>>> +
>>> +	if (gpiochip->num_banks > 0) {
>>> +		unsigned int i;
>>> +
>>> +		for (i = 0; i < gpiochip->num_banks; i++) {
>>> +			struct gpio_bank *bank = gpiochip->banks[i];
>>> +			unsigned int num_lines = bank->num_lines;
>>> +
>>> +			bank->pending = devm_kcalloc(gpiochip->parent,
>>> +						     BITS_TO_LONGS(num_lines),
>>> +						     sizeof(unsigned long),
>>> +						     GFP_KERNEL);
>>> +			if (!bank->pending)
>>> +				return -ENOMEM;
>>> +
>>> +			bank->chip = gpiochip;
>>> +		}
>>> +	}
>>> +
>>>    	if (gpiochip->irq.domain_ops)
>>>    		ops = gpiochip->irq.domain_ops;
>>>    	else
>>> @@ -1973,6 +2024,53 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
>>>    }
>>>    EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
>>>    
>>> +/**
>>> + * gpio_irq_chip_banked_chained_handler - interrupt handler for banked IRQ chips
>>> + * @desc: IRQ descriptor
>>> + *
>>> + * Drivers can use this interrupt handler for banked GPIO controllers. This
>>> + * implementation iterates over all banks and handles pending interrupts of
>>> + * the pins associated with the bank.
>>> + *
>>> + * This function uses driver specific parts, split out into the
>>> + * &gpio_chip.update_bank() callback, to retrieves the interrupt pending
>>> + * state for each of the GPIOs exposed by the given bank.
>>> + */
>>> +void gpio_irq_chip_banked_chained_handler(struct irq_desc *desc)
>>> +{
>>> +	struct gpio_chip *gpio = irq_desc_get_handler_data(desc);
>>
>> As per Patch 1 - there are no restriction to use parent_handler_data with
>> this standard handler - in this case parent_handler_data might not be struct gpio_chip.
> 
> Well, that would have to be considered a driver bug. I can add a comment
> to the kerneldoc about this if you have any concerns.

It would be good to have Documentation/gpio/driver.txt updated actually.

> 
>>> +	struct irq_chip *irq = irq_desc_get_chip(desc);
>>> +	unsigned int parent = irq_desc_get_irq(desc);
>>> +	struct gpio_irq_chip *chip = &gpio->irq;
>>> +	unsigned int i, offset = 0;
>>> +
>>> +	chained_irq_enter(irq, desc);
>>> +
>>> +	for (i = 0; i < gpio->num_banks; i++) {
>>> +		struct gpio_bank *bank = gpio->banks[i];
>>> +		unsigned int line, virq;
>>> +
>>> +		if (parent != chip->parents[bank->parent_irq])
>>> +			goto skip;
>>
>> You've used this handler in gpio-tegra.c.
>> So for compatible = "nvidia,tegra20-gpio":
>> - there are will be 7 parent irqs/banks.
>> - gpiochip will be used as chained_handler data.
>>
>> So, how will it work:
>> - for bank0 it will take 1 iteration to get correct bank structure
>> - but for bank7 - 7 iteration always (in hot path?)
> 
> Yes, that's correct. This could potentially be optimized by passing in
> the right bank as handler data. I think the above code is fairly simple
> and straightforward, and this is quite little overhead, so I'm not sure
> it's very useful to optimize at this point.

I'm not sure about this handler at all. HW IRQ handler is usually very
HW specific and well optimized, so as for me it should not be generic.
And it any way can be used for sleepable controllers. 
And for Edge IRQs handling it might be reasonable to read IRQ status and handle IRQs 
in IRQ handler in cycle.
...


> 
>>> +
>>> +		chip->update_bank(bank);
>>
>> Half of gpio drivers, you've listed in [1] required access to common
>> Interrupt status registers before proceeding to banks.
> 
> I'm sure we can add some additional callback(s) to account for those
> cases.

How many? ;)

> 
>>> +
>>> +		for_each_set_bit(line, bank->pending, bank->num_lines) {
>>> +			virq = irq_find_mapping(chip->domain, offset + line);
>>> +			if (WARN_ON(virq == 0))
>>> +				continue;
>>
>> drivers might require to do additional action before/after generic_handle_irq()
>> (intel_mid_irq_handler())
> 
> That could be done from within ->update_bank(). Or it could be done in
> an additional callback if necessary. Alternatively they may just not be
> able to use this particular implementation and just provide their own
> instead. This isn't meant to be a universal solution for every case, but
> rather provide a meaningful helper that can be used when appropriate to
> reduce boilerplate.

My opinion - It's better not to introduce generic IRQ handler at all as there
are too many variations in IRQ registers processing.

> 
>>> +
>>> +			generic_handle_irq(virq);
>>> +		}
>>> +
>>> +skip:
>>> +		offset += bank->num_lines;
>>> +	}
>>> +
>>> +	chained_irq_exit(irq, desc);
>>> +}
>>> +EXPORT_SYMBOL_GPL(gpio_irq_chip_banked_chained_handler);
>>
>> chained IRQ handler is not RT friendly (no control from User space)
> 
> I don't understand this comment. What are you suggesting?

Documentation/gpio/driver.txt Real-Time compliance for GPIO IRQ chips


-- 
regards,
-grygorii

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

* Re: [PATCH v2 14/16] gpio: Add support for banked GPIO controllers
@ 2017-10-10 22:12               ` Grygorii Strashko
  0 siblings, 0 replies; 56+ messages in thread
From: Grygorii Strashko @ 2017-10-10 22:12 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Linus Walleij, Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel



On 10/10/2017 06:00 AM, Thierry Reding wrote:
> On Mon, Oct 09, 2017 at 04:52:21PM -0500, Grygorii Strashko wrote:
>>
>>
>> On 09/28/2017 04:56 AM, Thierry Reding wrote:
>>> From: Thierry Reding <treding@nvidia.com>
>>>
>>> Some GPIO controllers are subdivided into multiple logical blocks called
>>> banks (or ports). This is often caused by the design assigning separate
>>> resources, such as register regions or interrupts, to each bank, or some
>>> set of banks.
>>>
>>> This commit adds support for describing controllers that have such a
>>> banked design and provides common code for dealing with them.
>>>
>>> Signed-off-by: Thierry Reding <treding@nvidia.com>
>>> ---
>>>    drivers/gpio/gpiolib-of.c   | 101 +++++++++++++++++++++++++++++++++++++++++
>>>    drivers/gpio/gpiolib.c      |  98 ++++++++++++++++++++++++++++++++++++++++
>>>    include/linux/gpio/driver.h | 108 ++++++++++++++++++++++++++++++++++++++++++++
>>>    include/linux/of_gpio.h     |  10 ++++
>>>    4 files changed, 317 insertions(+)
>>>
>>> diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
>>> index bfcd20699ec8..9baabe00966d 100644
>>> --- a/drivers/gpio/gpiolib-of.c
>>> +++ b/drivers/gpio/gpiolib-of.c
>>> @@ -309,6 +309,107 @@ int of_gpio_simple_xlate(struct gpio_chip *gc,
>>>    }
>>>    EXPORT_SYMBOL(of_gpio_simple_xlate);
>>>    
>>> +/**
>>> + * gpio_banked_irq_domain_xlate - decode an IRQ specifier for banked chips
>>> + * @domain: IRQ domain
>>> + * @np: device tree node
>>> + * @spec: IRQ specifier
>>> + * @size: number of cells in IRQ specifier
>>> + * @hwirq: return location for the hardware IRQ number
>>> + * @type: return location for the IRQ type
>>> + *
>>> + * Translates the IRQ specifier found in device tree into a hardware IRQ
>>> + * number and an interrupt type.
>>> + *
>>> + * Returns:
>>> + * 0 on success or a negative error code on failure.
>>> + */
>>> +int gpio_banked_irq_domain_xlate(struct irq_domain *domain,
>>> +				 struct device_node *np,
>>> +				 const u32 *spec, unsigned int size,
>>> +				 unsigned long *hwirq,
>>> +				 unsigned int *type)
>>> +{
>>> +	struct gpio_chip *gc = domain->host_data;
>>> +	unsigned int bank, line, i, offset = 0;
>>> +
>>> +	if (size < 2)
>>> +		return -EINVAL;
>>> +
>>> +	bank = (spec[0] >> gc->of_gpio_bank_mask) & gc->of_gpio_bank_shift;
>>> +	line = (spec[0] >> gc->of_gpio_line_mask) & gc->of_gpio_line_shift;
>>> +
>>> +	if (bank >= gc->num_banks) {
>>> +		dev_err(gc->parent, "invalid bank number: %u\n", bank);
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	if (line >= gc->banks[bank]->num_lines) {
>>> +		dev_err(gc->parent, "invalid line number: %u\n", line);
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	for (i = 0; i < bank; i++)
>>> +		offset += gc->banks[i]->num_lines;
>>
>> Just to clarify, why is above iteration required?
> 
> This is used to handle the generic case where not all banks have the
> same number of lines. In order to avoid having to separately deal with
> non-existing lines, drivers are supposed to register only the exact
> number of lines they support.
> 
> However, the binding may be written such that the (bank, line) pair is
> encoded in one cell. To make that easier to construct and parse, simple
> OR'ing is used, perhaps like this:
> 
> 	index = (((bank) << 3) | (line))
> 
> However, if not all banks have 8 lines, this leaves blanks in the number
> space when working your way back.
> 
> So the above iteration maps the sparse number space of the specifier to
> the dense number space of per-chip lines.

Wouldn't it be reasonable to save GPIO offset in struct gpio_bank - it's
one time configuration.

> 
>>> +	*type = spec[1] & IRQ_TYPE_SENSE_MASK;
>>> +	*hwirq = offset + line;
>>> +
>>> +	return 0;
>>> +}
>>> +EXPORT_SYMBOL_GPL(gpio_banked_irq_domain_xlate);
>>> +
>>> +/**
>>> + * of_gpio_banked_xlate - translate GPIO specifier to a GPIO number and flags
>>> + * @gc: GPIO chip
>>> + * @gpiospec: GPIO specifier
>>> + * @flags: return location for flags parsed from the GPIO specifier
>>> + *
>>> + * This translation function takes into account multiple banks that can make
>>> + * up a single controller. Each bank can contain one or more pins. A single
>>> + * cell in the specifier is used to represent a (bank, pin) pair, with each
>>> + * encoded in different fields. The &gpio_chip.of_gpio_bank_shift and
>>> + * &gpio_chip.of_gpio_bank_mask fields, and &gpio_chip.of_gpio_line_shift and
>>> + * &gpio_chip.of_gpio_line_mask are used to specify the encoding.
>>> + *
>>> + * Returns:
>>> + * The chip-relative index of the pin given by the GPIO specifier.
>>> + */
>>> +int of_gpio_banked_xlate(struct gpio_chip *gc,
>>> +			 const struct of_phandle_args *gpiospec, u32 *flags)
>>> +{
>>> +	unsigned int offset = 0, bank, line, i;
>>> +	const u32 *spec = gpiospec->args;
>>> +
>>> +	if (WARN_ON(gc->of_gpio_n_cells < 2))
>>> +		return -EINVAL;
>>> +
>>> +	if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
>>> +		return -EINVAL;
>>> +
>>> +	bank = (spec[0] >> gc->of_gpio_bank_shift) & gc->of_gpio_bank_mask;
>>> +	line = (spec[0] >> gc->of_gpio_line_shift) & gc->of_gpio_line_mask;
>>> +
>>> +	if (bank >= gc->num_banks) {
>>> +		dev_err(gc->parent, "invalid bank number: %u\n", bank);
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	if (line >= gc->banks[bank]->num_lines) {
>>> +		dev_err(gc->parent, "invalid line number: %u\n", line);
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	for (i = 0; i < bank; i++)
>>> +		offset += gc->banks[i]->num_lines;
>>> +
>>> +	if (flags)
>>> +		*flags = spec[1];
>>> +
>>> +	return offset + line;
>>> +}
>>> +EXPORT_SYMBOL(of_gpio_banked_xlate);
>>
>> Adding above two functions means adding new GPIO bindings (may be optional,
>> but common).
> 
> No. This function is used to parse bindings that use an encoding of
> (bank, line) pairs in one cell. Tegra and Tegra186 are two such
> examples, though they seem to be the only ones doing this.

They are only one such examples ;)

Again two cells <bank/port> <pin> mach more user friendly as for me.


> 
>>
>>> +
>>>    /**
>>>     * of_mm_gpiochip_add_data - Add memory mapped GPIO chip (bank)
>>>     * @np:		device node of the GPIO chip
>>> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
>>> index c15fb858848a..b3bd19b793d3 100644
>>> --- a/drivers/gpio/gpiolib.c
>>> +++ b/drivers/gpio/gpiolib.c
>>> @@ -1765,6 +1765,57 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
>>>    	gpiochip->to_irq = gpiochip_to_irq;
>>>    	gpiochip->irq.default_type = type;
>>>    
>>> +	if (gpiochip->num_banks > 0 && !gpiochip->irq.map) {
>>> +		struct gpio_irq_chip *irq = &gpiochip->irq;
>>> +		unsigned int i, j, offset = 0;
>>> +
>>> +		if (!irq->parents) {
>>> +			chip_err(gpiochip, "no parent interrupts defined\n");
>>> +			return -EINVAL;
>>> +		}
>>> +
>>> +		irq->map = devm_kcalloc(gpiochip->parent, gpiochip->ngpio,
>>> +					sizeof(*irq->map), GFP_KERNEL);
>>> +		if (!irq->map)
>>> +			return -ENOMEM;
>>> +
>>> +		for (i = 0; i < gpiochip->num_banks; i++) {
>>> +			struct gpio_bank *bank = gpiochip->banks[i];
>>> +			unsigned int parent = bank->parent_irq;
>>
>>
>>
>>> +
>>> +			for (j = 0; j < bank->num_lines; j++) {
>>> +				if (parent >= irq->num_parents) {
>>> +					chip_err(gpiochip,
>>> +						 "invalid parent interrupt: %u\n",
>>> +						 parent);
>>> +					return -EINVAL;
>>> +				}
>>> +
>>> +				irq->map[offset + j] = irq->parents[parent];
>>> +			}
>>> +
>>> +			offset += bank->num_lines;
>>
>> Most of gpio drivers, you've listed in [1], have only one parent
>> (waste of memory). There should be way not to store it permanently.
> 
> I'm sure we can find a way to special-case this for optimization. The
> condition above could be extended to include
> 
> 	gpiochip->irq.num_parents > 1
> 
> And a similar special case added to gpiochip_to_irq() to set the single
> parent if no map is available.


> 
>>> +		}
>>> +	}
>>> +
>>> +	if (gpiochip->num_banks > 0) {
>>> +		unsigned int i;
>>> +
>>> +		for (i = 0; i < gpiochip->num_banks; i++) {
>>> +			struct gpio_bank *bank = gpiochip->banks[i];
>>> +			unsigned int num_lines = bank->num_lines;
>>> +
>>> +			bank->pending = devm_kcalloc(gpiochip->parent,
>>> +						     BITS_TO_LONGS(num_lines),
>>> +						     sizeof(unsigned long),
>>> +						     GFP_KERNEL);
>>> +			if (!bank->pending)
>>> +				return -ENOMEM;
>>> +
>>> +			bank->chip = gpiochip;
>>> +		}
>>> +	}
>>> +
>>>    	if (gpiochip->irq.domain_ops)
>>>    		ops = gpiochip->irq.domain_ops;
>>>    	else
>>> @@ -1973,6 +2024,53 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
>>>    }
>>>    EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
>>>    
>>> +/**
>>> + * gpio_irq_chip_banked_chained_handler - interrupt handler for banked IRQ chips
>>> + * @desc: IRQ descriptor
>>> + *
>>> + * Drivers can use this interrupt handler for banked GPIO controllers. This
>>> + * implementation iterates over all banks and handles pending interrupts of
>>> + * the pins associated with the bank.
>>> + *
>>> + * This function uses driver specific parts, split out into the
>>> + * &gpio_chip.update_bank() callback, to retrieves the interrupt pending
>>> + * state for each of the GPIOs exposed by the given bank.
>>> + */
>>> +void gpio_irq_chip_banked_chained_handler(struct irq_desc *desc)
>>> +{
>>> +	struct gpio_chip *gpio = irq_desc_get_handler_data(desc);
>>
>> As per Patch 1 - there are no restriction to use parent_handler_data with
>> this standard handler - in this case parent_handler_data might not be struct gpio_chip.
> 
> Well, that would have to be considered a driver bug. I can add a comment
> to the kerneldoc about this if you have any concerns.

It would be good to have Documentation/gpio/driver.txt updated actually.

> 
>>> +	struct irq_chip *irq = irq_desc_get_chip(desc);
>>> +	unsigned int parent = irq_desc_get_irq(desc);
>>> +	struct gpio_irq_chip *chip = &gpio->irq;
>>> +	unsigned int i, offset = 0;
>>> +
>>> +	chained_irq_enter(irq, desc);
>>> +
>>> +	for (i = 0; i < gpio->num_banks; i++) {
>>> +		struct gpio_bank *bank = gpio->banks[i];
>>> +		unsigned int line, virq;
>>> +
>>> +		if (parent != chip->parents[bank->parent_irq])
>>> +			goto skip;
>>
>> You've used this handler in gpio-tegra.c.
>> So for compatible = "nvidia,tegra20-gpio":
>> - there are will be 7 parent irqs/banks.
>> - gpiochip will be used as chained_handler data.
>>
>> So, how will it work:
>> - for bank0 it will take 1 iteration to get correct bank structure
>> - but for bank7 - 7 iteration always (in hot path?)
> 
> Yes, that's correct. This could potentially be optimized by passing in
> the right bank as handler data. I think the above code is fairly simple
> and straightforward, and this is quite little overhead, so I'm not sure
> it's very useful to optimize at this point.

I'm not sure about this handler at all. HW IRQ handler is usually very
HW specific and well optimized, so as for me it should not be generic.
And it any way can be used for sleepable controllers. 
And for Edge IRQs handling it might be reasonable to read IRQ status and handle IRQs 
in IRQ handler in cycle.
...


> 
>>> +
>>> +		chip->update_bank(bank);
>>
>> Half of gpio drivers, you've listed in [1] required access to common
>> Interrupt status registers before proceeding to banks.
> 
> I'm sure we can add some additional callback(s) to account for those
> cases.

How many? ;)

> 
>>> +
>>> +		for_each_set_bit(line, bank->pending, bank->num_lines) {
>>> +			virq = irq_find_mapping(chip->domain, offset + line);
>>> +			if (WARN_ON(virq == 0))
>>> +				continue;
>>
>> drivers might require to do additional action before/after generic_handle_irq()
>> (intel_mid_irq_handler())
> 
> That could be done from within ->update_bank(). Or it could be done in
> an additional callback if necessary. Alternatively they may just not be
> able to use this particular implementation and just provide their own
> instead. This isn't meant to be a universal solution for every case, but
> rather provide a meaningful helper that can be used when appropriate to
> reduce boilerplate.

My opinion - It's better not to introduce generic IRQ handler at all as there
are too many variations in IRQ registers processing.

> 
>>> +
>>> +			generic_handle_irq(virq);
>>> +		}
>>> +
>>> +skip:
>>> +		offset += bank->num_lines;
>>> +	}
>>> +
>>> +	chained_irq_exit(irq, desc);
>>> +}
>>> +EXPORT_SYMBOL_GPL(gpio_irq_chip_banked_chained_handler);
>>
>> chained IRQ handler is not RT friendly (no control from User space)
> 
> I don't understand this comment. What are you suggesting?

Documentation/gpio/driver.txt Real-Time compliance for GPIO IRQ chips


-- 
regards,
-grygorii

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

* Re: [PATCH v2 01/16] gpio: Implement tighter IRQ chip integration
  2017-09-28  9:56 ` [PATCH v2 01/16] gpio: Implement tighter IRQ chip integration Thierry Reding
@ 2017-10-10 22:56       ` Grygorii Strashko
  0 siblings, 0 replies; 56+ messages in thread
From: Grygorii Strashko @ 2017-10-10 22:56 UTC (permalink / raw)
  To: Thierry Reding, Linus Walleij
  Cc: Jonathan Hunter, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA



On 09/28/2017 04:56 AM, Thierry Reding wrote:
> From: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> 
> 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.

few more comments.
> 
> Signed-off-by: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> ---
>   drivers/gpio/gpiolib.c      | 146 +++++++++++++++++++++++++++++++++++++++++++-
>   include/linux/gpio/driver.h |  64 +++++++++++++++++++
>   2 files changed, 207 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> index eb80dac4e26a..b34d9cbd5809 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);
> @@ -1260,6 +1261,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;
> +

lock_key - it better if drivers will not need to define it.

>   	status = of_gpiochip_add(chip);
>   	if (status)
>   		goto err_remove_chip;
> @@ -1626,8 +1631,8 @@ 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;
>   
> @@ -1655,8 +1660,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;
>   
> @@ -1665,6 +1671,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,
> @@ -1705,6 +1712,124 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
>   	return irq_create_mapping(chip->irqdomain, 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->irqchip;
> +	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

above can be retrieved from gpio_chip->gpiodev

> +
> +	/*
> +	 * 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->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_base,
> +						    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;

GPIO driver might not specify parent_handler, but it doesn't mean it's irq_nested,
as driver may use request_irq()

> +	}
> +
> +	/*
> +	 * 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
> @@ -1722,6 +1847,16 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
>   		irq_set_handler_data(gpiochip->irq_chained_parent, NULL);
>   	}
>   
> +	if (gpiochip->irqchip) {
> +		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++) {
> @@ -1842,6 +1977,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 c97f8325e8bf..6100b171817e 100644
> --- a/include/linux/gpio/driver.h
> +++ b/include/linux/gpio/driver.h
> @@ -19,6 +19,58 @@ struct module;
>   
>   #ifdef CONFIG_GPIOLIB
>   
> +#ifdef CONFIG_GPIOLIB_IRQCHIP
> +/**
> + * struct gpio_irq_chip - GPIO interrupt controller
> + */
> +struct gpio_irq_chip {
> +	/**
> +	 * @domain_ops:
> +	 *
> +	 * Table of interrupt domain operations for this IRQ chip.
> +	 */
> +	const struct irq_domain_ops *domain_ops;
> +
> +	/**
> +	 * @parent_handler:
> +	 *
> +	 * The interrupt handler for the GPIO chip's parent interrupts, may be
> +	 * NULL if the parent interrupts are nested rather than cascaded.
> +	 */
> +	irq_flow_handler_t parent_handler;
> +
> +	/**
> +	 * @parent_handler_data:
> +	 *
> +	 * Data associated, and passed to, the handler for the parent
> +	 * interrupt.
> +	 */
> +	void *parent_handler_data;
> +
> +	/**
> +	 * @num_parents:
> +	 *
> +	 * The number of interrupt parents of a GPIO chip.
> +	 */
> +	unsigned int num_parents;
> +
> +	/**
> +	 * @parents:
> +	 *
> +	 * A list of interrupt parents of a GPIO chip. This is owned by the
> +	 * driver, so the core will only reference this list, not modify it.
> +	 */
> +	unsigned int *parents;
> +
> +	/**
> +	 * @map:
> +	 *
> +	 * A list of interrupt parents for each line of a GPIO chip.
> +	 */
> +	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 +225,14 @@ struct gpio_chip {
>   	bool			irq_need_valid_mask;
>   	unsigned long		*irq_valid_mask;
>   	struct lock_class_key	*lock_key;
> +
> +	/**
> +	 * @irq:
> +	 *
> +	 * Integrates interrupt chip functionality with the GPIO chip. Can be
> +	 * used to handle IRQs for most practical cases.
> +	 */
> +	struct gpio_irq_chip irq;
>   #endif
>   
>   #if defined(CONFIG_OF_GPIO)
> @@ -264,6 +324,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,
> 

-- 
regards,
-grygorii

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

* Re: [PATCH v2 01/16] gpio: Implement tighter IRQ chip integration
@ 2017-10-10 22:56       ` Grygorii Strashko
  0 siblings, 0 replies; 56+ messages in thread
From: Grygorii Strashko @ 2017-10-10 22:56 UTC (permalink / raw)
  To: Thierry Reding, Linus Walleij
  Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel



On 09/28/2017 04:56 AM, Thierry Reding wrote:
> 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.

few more comments.
> 
> Signed-off-by: Thierry Reding <treding@nvidia.com>
> ---
>   drivers/gpio/gpiolib.c      | 146 +++++++++++++++++++++++++++++++++++++++++++-
>   include/linux/gpio/driver.h |  64 +++++++++++++++++++
>   2 files changed, 207 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> index eb80dac4e26a..b34d9cbd5809 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);
> @@ -1260,6 +1261,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;
> +

lock_key - it better if drivers will not need to define it.

>   	status = of_gpiochip_add(chip);
>   	if (status)
>   		goto err_remove_chip;
> @@ -1626,8 +1631,8 @@ 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;
>   
> @@ -1655,8 +1660,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;
>   
> @@ -1665,6 +1671,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,
> @@ -1705,6 +1712,124 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
>   	return irq_create_mapping(chip->irqdomain, 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->irqchip;
> +	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

above can be retrieved from gpio_chip->gpiodev

> +
> +	/*
> +	 * 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->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_base,
> +						    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;

GPIO driver might not specify parent_handler, but it doesn't mean it's irq_nested,
as driver may use request_irq()

> +	}
> +
> +	/*
> +	 * 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
> @@ -1722,6 +1847,16 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
>   		irq_set_handler_data(gpiochip->irq_chained_parent, NULL);
>   	}
>   
> +	if (gpiochip->irqchip) {
> +		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++) {
> @@ -1842,6 +1977,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 c97f8325e8bf..6100b171817e 100644
> --- a/include/linux/gpio/driver.h
> +++ b/include/linux/gpio/driver.h
> @@ -19,6 +19,58 @@ struct module;
>   
>   #ifdef CONFIG_GPIOLIB
>   
> +#ifdef CONFIG_GPIOLIB_IRQCHIP
> +/**
> + * struct gpio_irq_chip - GPIO interrupt controller
> + */
> +struct gpio_irq_chip {
> +	/**
> +	 * @domain_ops:
> +	 *
> +	 * Table of interrupt domain operations for this IRQ chip.
> +	 */
> +	const struct irq_domain_ops *domain_ops;
> +
> +	/**
> +	 * @parent_handler:
> +	 *
> +	 * The interrupt handler for the GPIO chip's parent interrupts, may be
> +	 * NULL if the parent interrupts are nested rather than cascaded.
> +	 */
> +	irq_flow_handler_t parent_handler;
> +
> +	/**
> +	 * @parent_handler_data:
> +	 *
> +	 * Data associated, and passed to, the handler for the parent
> +	 * interrupt.
> +	 */
> +	void *parent_handler_data;
> +
> +	/**
> +	 * @num_parents:
> +	 *
> +	 * The number of interrupt parents of a GPIO chip.
> +	 */
> +	unsigned int num_parents;
> +
> +	/**
> +	 * @parents:
> +	 *
> +	 * A list of interrupt parents of a GPIO chip. This is owned by the
> +	 * driver, so the core will only reference this list, not modify it.
> +	 */
> +	unsigned int *parents;
> +
> +	/**
> +	 * @map:
> +	 *
> +	 * A list of interrupt parents for each line of a GPIO chip.
> +	 */
> +	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 +225,14 @@ struct gpio_chip {
>   	bool			irq_need_valid_mask;
>   	unsigned long		*irq_valid_mask;
>   	struct lock_class_key	*lock_key;
> +
> +	/**
> +	 * @irq:
> +	 *
> +	 * Integrates interrupt chip functionality with the GPIO chip. Can be
> +	 * used to handle IRQs for most practical cases.
> +	 */
> +	struct gpio_irq_chip irq;
>   #endif
>   
>   #if defined(CONFIG_OF_GPIO)
> @@ -264,6 +324,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,
> 

-- 
regards,
-grygorii

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

* Re: [PATCH v2 00/16] gpio: Tight IRQ chip integration and banked infrastructure
  2017-10-10 11:27               ` Thierry Reding
@ 2017-10-10 22:56                 ` Grygorii Strashko
  -1 siblings, 0 replies; 56+ messages in thread
From: Grygorii Strashko @ 2017-10-10 22:56 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Linus Walleij, Jonathan Hunter,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA



On 10/10/2017 06:27 AM, Thierry Reding wrote:
> On Mon, Oct 09, 2017 at 04:56:57PM -0500, Grygorii Strashko wrote:
>>
>>
>> On 10/06/2017 06:07 AM, Thierry Reding wrote:
>>> On Thu, Sep 28, 2017 at 09:22:17AM -0500, Grygorii Strashko wrote:
>>>>
>>>>
>>>> On 09/28/2017 04:56 AM, Thierry Reding wrote:
>>>>> From: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
>>>>>
>>>>> Hi Linus,
>>>>>
>>>>> here's the latest series of patches that implement the tighter IRQ chip
>>>>> integration as well as the banked GPIO infrastructure that we had
>>>>> discussed a couple of weeks/months back.
>>>>>
>>>>> The first couple of patches are mostly preparatory work in order to
>>>>> consolidate all IRQ chip related fields in a new structure and create
>>>>> the base functionality for adding IRQ chips.
>>>>>
>>>>> After that, I've added the Tegra186 GPIO support patch that makes use of
>>>>> the new tight integration.
>>>>>
>>>>> To round things off the new banked GPIO infrastructure is added (along
>>>>> with some more preparatory work), followed by the conversion of the two
>>>>> Tegra GPIO drivers to the new infrastructure.
>>>>
>>>> Hm. So you've ignored my comments [1].
>>>>
>>>> Sry, but I do not agree with this series.
>>>> - no prof that it can be re-used by other drivers than tegra
>>>>    (at least I do not see reasons to re-use it for any TI drivers)
>>>
>>> I had done some research based on Linus' feedback from an earlier series
>>> and identified the following potential candidates[0] that could move to
>>> this new infrastructure:
>>>
>>
>> below based on code check:
>>
>>> 	- gpio-intel-mid.c
>>
>> one irq per all gpios in controller
>>
>>> 	- gpio-merrifield.c
>>
>> one irq per all gpios in controller
>>
>>> 	- gpio-pca953x.c
>> one irq per all gpios in controller
>>
>>> 	- gpio-stmpe.c
>> one irq per all gpios in controller
>>> 	- gpio-tc3589x.c
>> one irq per all gpios in controller
>>> 	- gpio-ws16c48.c
>>
>> one irq per all gpios in controller
> 
> I explained in another subthread how we could cater for this particular
> use-case.
> 
>>> Note that this is based on code inspection rather than DT inspection,
>>> because that's fundamentally flawed. If you look at this from a DT
>>> perspective you're going to be tempted to change the DT bindings, but
>>> you can't do that because of backwards compatiblity. This new framework
>>> also doesn't address the issues at that level, but rather tries to be
>>> some common code that is otherwise duplicated in one way or another in
>>> various drivers and therefore hard to maintain. This is what Linus had
>>> originally requested, and that's what the series does.
>>
>> I've looked at this again, and again. I've looked on drivers listed above.
>> Sry, I do not see how this change can improve/simplify above drivers :(
>> May be it will clean up my doubts, if it will be possible to convert more
>> drivers?
> 
> I'm reluctant to spend more work on this and get Tegra186 GPIO support
> delayed indefinitely until every other driver has been converted. The
> Tegra186 GPIO driver is now more than a year old and I've got a few
> dozen patches that depend on GPIO functionality that we currently can't
> merge because this unification work has been going on for more than 6
> months. This has been a very frustrating experience overall.
> 
> I think this series is in good enough shape for now. It improves the
> situation in general. I also don't see anything in here that couldn't be
> further improved should the need arise.
> 
> If this really isn't useful at all, can we please at least get patches
> 1-11 merged? T hey are independent of the banked infrastructure work in
> the last couple of patches.

I agree with patches 10 in general (with comments applied) and, honestly.
Do not see reasons why 11 can't go (but it any way up to Linus). 
That why I've proposed split.

> 
>>>> - no split
>>>
>>> What does this mean? The series is nicely split into separate patches,
>>> so each one individually is easy to review. I've also gone through quite
>>> some trouble to make sure everything builds fine after each patch, so
>>> it's possible to apply individual bits of the series. For example we
>>> could opt to apply everything up to the banked GPIO support if that's
>>> still contentious.
>>
>> i've commented it in [1]. copy paste here
>>
>>>>
>> So, can it be split? I think, patches which reorganize gpio irqchip specific fields placement
>> and move them in gpio_irq_chip can be considered separately if they will not introduce
>> functional changes. Also, omap changes can be considered separately.
>> (Pay attention that new fields introduced in patch 1).
>>>>
>>
>> This will reduce size of your series and concentrate review attention on actual functional changes.
>>
>>
>> [1] https://lkml.org/lkml/2017/9/15/442
> 
> I could of course split the series into multiple parts, but then it
> becomes difficult to represent dependencies. The changes you mention are
> already split into separate commits and I even made sure that they keep
> bisectibility. I've sent them together primarily to keep them in the
> order that they need to be applied in to simplify things.
> 
> I don't see how splitting up the series any further is going to simplify
> review. If you want to only review the banked infrastructure change, can
> you not just focus on that patch and ignore the first ten since they are
> not actually functional changes?

Patch 1 need to be updated as for me. while 2 - 10 are very simple.
It will allow to get rid 10 patches from your series if
- first introduce struct gpio_irq_chip
- second move all current IRQ specific field in it
- last add gpiochip_add_irqchip() and num_parents, parents, map

this will allow to update drivers and drop gpiochip_irqchip_add() by filling
gpio_irq_chip structure.

> 
>>
>>>
>>>> - all GPIO IRQs mapped statically
>>>
>>> This series predates your work on the dynamic IRQ mapping, so I hadn't
>>> picked up those changes. This should be easily solved by the attached
>>> patch, though.
>>>
>>>> - irq->map[offset + j] = irq->parents[parent]; holds IRQs for all pins
>>>>     which is waste of memory
>>>
>>> It's the only way to generically do this. Also I don't think this wastes
>>> that much memory. We have one unsigned int per pin, which even for very
>>> large GPIO controllers is unlikely to exceed one 4 KiB page.
>>
>> for system with <128M of memory even 4k is a win.
> 
> I suspect that such systems won't have GPIOs where this infrastructure
> would be used, or where the number of GPIOs would be problematic.
> 
> Also, this is supposed to be generic infrastructure and that usually
> comes at some price. I don't know how to do this without the mapping,
> but I'm certainly open to suggestions.
> 
>>>> - DT binding changes not documented and no DT examples
>>>
>>> That's because this is completely orthogonal to DT bindings. We can't
>>> make any changes to the bindings because of ABI stability.
>>>
>>>> - below is ugly ;)
>>>> +	bank = (spec[0] >> gc->of_gpio_bank_mask) & gc->of_gpio_bank_shift;
>>>> +	pin = (spec[0] >> gc->of_gpio_pin_mask) & gc->of_gpio_pin_shift;
>>>
>>> If by ugly you mean wrong, then yes, it's actually the wrong way around.
>>> It should be:
>>>
>>> 	bank = (spec[0] >> gc->of_gpio_bank_shift) & gc->of_gpio_bank_mask;
>>> 	line = (spec[0] >> gc->of_gpio_line_shift) & gc->of_gpio_line_mask;
>>
>>   
>> Wrong yep. And No. What I do not like is encoding bank & line in the same field.
> 
> This is not about liking or disliking the encoding. The encoding is
> already defined in the bindings for Tegra and Tegra186, so this isn't up
> for discussion.
> 
>> It creates some not clear DT standard bindings requirements as for me, comparing to the
>> current well known GPIO bindings
>>   gpios = <&[controller] [line number in controller] [flags]>;
>> line number in controller ::= [0..max lines]
> 
> Yes, that's because this is specifically for banked controllers. It
> seems to me like most other bindings for banked controllers simply use a
> linear mapping, in which case the simple example above would work.
> 
> Tegra seems somewhat of an exception because the DT bindings use the
> (bank, line) pair encoding to reflect the names given to the lines in
> technical reference manuals. I like this because it makes the DTS files
> very easy to read and relate to schematics.

I did some googling and saw tegra binding accepted already. 
Juts curious why not to use two cells <bank/port> <pin>
it as for me much more readable and no masks/shifts 

> 
>> Actually, as per gpio.txt:
>> "Note that gpio-specifier length is controller dependent.  In the
>> above example, &gpio1 uses 2 cells to specify a gpio, while &gpio2
>> only uses one.",
>> so, if this going to be part of gpiolib it should be
>>   described in bindings/gpio/gpio.txt (or some other documents), as
>>   above note will not be exactly correct and new "banked" gpio controllers
>> will be expected to use thin new binding.
> 
> Yeah, that makes sense. I'll work on a patch that updates the binding
> documentation to include this particular encoding. Again, this is not
> intended to replace existing bindings because they may not be
> compatible. However, bindings for new banked controllers may be able
> to reuse this if it suits their needs.
> 
> Also, note that the rest of the banked infrastructure can be used
> independently of the ->xlate() callback. Drivers are free to use the
> of_gpio_simple_xlate() with the rest of the banked infrastructure to
> simplify the driver code.

-- 
regards,
-grygorii

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

* Re: [PATCH v2 00/16] gpio: Tight IRQ chip integration and banked infrastructure
@ 2017-10-10 22:56                 ` Grygorii Strashko
  0 siblings, 0 replies; 56+ messages in thread
From: Grygorii Strashko @ 2017-10-10 22:56 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Linus Walleij, Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel



On 10/10/2017 06:27 AM, Thierry Reding wrote:
> On Mon, Oct 09, 2017 at 04:56:57PM -0500, Grygorii Strashko wrote:
>>
>>
>> On 10/06/2017 06:07 AM, Thierry Reding wrote:
>>> On Thu, Sep 28, 2017 at 09:22:17AM -0500, Grygorii Strashko wrote:
>>>>
>>>>
>>>> On 09/28/2017 04:56 AM, Thierry Reding wrote:
>>>>> From: Thierry Reding <treding@nvidia.com>
>>>>>
>>>>> Hi Linus,
>>>>>
>>>>> here's the latest series of patches that implement the tighter IRQ chip
>>>>> integration as well as the banked GPIO infrastructure that we had
>>>>> discussed a couple of weeks/months back.
>>>>>
>>>>> The first couple of patches are mostly preparatory work in order to
>>>>> consolidate all IRQ chip related fields in a new structure and create
>>>>> the base functionality for adding IRQ chips.
>>>>>
>>>>> After that, I've added the Tegra186 GPIO support patch that makes use of
>>>>> the new tight integration.
>>>>>
>>>>> To round things off the new banked GPIO infrastructure is added (along
>>>>> with some more preparatory work), followed by the conversion of the two
>>>>> Tegra GPIO drivers to the new infrastructure.
>>>>
>>>> Hm. So you've ignored my comments [1].
>>>>
>>>> Sry, but I do not agree with this series.
>>>> - no prof that it can be re-used by other drivers than tegra
>>>>    (at least I do not see reasons to re-use it for any TI drivers)
>>>
>>> I had done some research based on Linus' feedback from an earlier series
>>> and identified the following potential candidates[0] that could move to
>>> this new infrastructure:
>>>
>>
>> below based on code check:
>>
>>> 	- gpio-intel-mid.c
>>
>> one irq per all gpios in controller
>>
>>> 	- gpio-merrifield.c
>>
>> one irq per all gpios in controller
>>
>>> 	- gpio-pca953x.c
>> one irq per all gpios in controller
>>
>>> 	- gpio-stmpe.c
>> one irq per all gpios in controller
>>> 	- gpio-tc3589x.c
>> one irq per all gpios in controller
>>> 	- gpio-ws16c48.c
>>
>> one irq per all gpios in controller
> 
> I explained in another subthread how we could cater for this particular
> use-case.
> 
>>> Note that this is based on code inspection rather than DT inspection,
>>> because that's fundamentally flawed. If you look at this from a DT
>>> perspective you're going to be tempted to change the DT bindings, but
>>> you can't do that because of backwards compatiblity. This new framework
>>> also doesn't address the issues at that level, but rather tries to be
>>> some common code that is otherwise duplicated in one way or another in
>>> various drivers and therefore hard to maintain. This is what Linus had
>>> originally requested, and that's what the series does.
>>
>> I've looked at this again, and again. I've looked on drivers listed above.
>> Sry, I do not see how this change can improve/simplify above drivers :(
>> May be it will clean up my doubts, if it will be possible to convert more
>> drivers?
> 
> I'm reluctant to spend more work on this and get Tegra186 GPIO support
> delayed indefinitely until every other driver has been converted. The
> Tegra186 GPIO driver is now more than a year old and I've got a few
> dozen patches that depend on GPIO functionality that we currently can't
> merge because this unification work has been going on for more than 6
> months. This has been a very frustrating experience overall.
> 
> I think this series is in good enough shape for now. It improves the
> situation in general. I also don't see anything in here that couldn't be
> further improved should the need arise.
> 
> If this really isn't useful at all, can we please at least get patches
> 1-11 merged? T hey are independent of the banked infrastructure work in
> the last couple of patches.

I agree with patches 10 in general (with comments applied) and, honestly.
Do not see reasons why 11 can't go (but it any way up to Linus). 
That why I've proposed split.

> 
>>>> - no split
>>>
>>> What does this mean? The series is nicely split into separate patches,
>>> so each one individually is easy to review. I've also gone through quite
>>> some trouble to make sure everything builds fine after each patch, so
>>> it's possible to apply individual bits of the series. For example we
>>> could opt to apply everything up to the banked GPIO support if that's
>>> still contentious.
>>
>> i've commented it in [1]. copy paste here
>>
>>>>
>> So, can it be split? I think, patches which reorganize gpio irqchip specific fields placement
>> and move them in gpio_irq_chip can be considered separately if they will not introduce
>> functional changes. Also, omap changes can be considered separately.
>> (Pay attention that new fields introduced in patch 1).
>>>>
>>
>> This will reduce size of your series and concentrate review attention on actual functional changes.
>>
>>
>> [1] https://lkml.org/lkml/2017/9/15/442
> 
> I could of course split the series into multiple parts, but then it
> becomes difficult to represent dependencies. The changes you mention are
> already split into separate commits and I even made sure that they keep
> bisectibility. I've sent them together primarily to keep them in the
> order that they need to be applied in to simplify things.
> 
> I don't see how splitting up the series any further is going to simplify
> review. If you want to only review the banked infrastructure change, can
> you not just focus on that patch and ignore the first ten since they are
> not actually functional changes?

Patch 1 need to be updated as for me. while 2 - 10 are very simple.
It will allow to get rid 10 patches from your series if
- first introduce struct gpio_irq_chip
- second move all current IRQ specific field in it
- last add gpiochip_add_irqchip() and num_parents, parents, map

this will allow to update drivers and drop gpiochip_irqchip_add() by filling
gpio_irq_chip structure.

> 
>>
>>>
>>>> - all GPIO IRQs mapped statically
>>>
>>> This series predates your work on the dynamic IRQ mapping, so I hadn't
>>> picked up those changes. This should be easily solved by the attached
>>> patch, though.
>>>
>>>> - irq->map[offset + j] = irq->parents[parent]; holds IRQs for all pins
>>>>     which is waste of memory
>>>
>>> It's the only way to generically do this. Also I don't think this wastes
>>> that much memory. We have one unsigned int per pin, which even for very
>>> large GPIO controllers is unlikely to exceed one 4 KiB page.
>>
>> for system with <128M of memory even 4k is a win.
> 
> I suspect that such systems won't have GPIOs where this infrastructure
> would be used, or where the number of GPIOs would be problematic.
> 
> Also, this is supposed to be generic infrastructure and that usually
> comes at some price. I don't know how to do this without the mapping,
> but I'm certainly open to suggestions.
> 
>>>> - DT binding changes not documented and no DT examples
>>>
>>> That's because this is completely orthogonal to DT bindings. We can't
>>> make any changes to the bindings because of ABI stability.
>>>
>>>> - below is ugly ;)
>>>> +	bank = (spec[0] >> gc->of_gpio_bank_mask) & gc->of_gpio_bank_shift;
>>>> +	pin = (spec[0] >> gc->of_gpio_pin_mask) & gc->of_gpio_pin_shift;
>>>
>>> If by ugly you mean wrong, then yes, it's actually the wrong way around.
>>> It should be:
>>>
>>> 	bank = (spec[0] >> gc->of_gpio_bank_shift) & gc->of_gpio_bank_mask;
>>> 	line = (spec[0] >> gc->of_gpio_line_shift) & gc->of_gpio_line_mask;
>>
>>   
>> Wrong yep. And No. What I do not like is encoding bank & line in the same field.
> 
> This is not about liking or disliking the encoding. The encoding is
> already defined in the bindings for Tegra and Tegra186, so this isn't up
> for discussion.
> 
>> It creates some not clear DT standard bindings requirements as for me, comparing to the
>> current well known GPIO bindings
>>   gpios = <&[controller] [line number in controller] [flags]>;
>> line number in controller ::= [0..max lines]
> 
> Yes, that's because this is specifically for banked controllers. It
> seems to me like most other bindings for banked controllers simply use a
> linear mapping, in which case the simple example above would work.
> 
> Tegra seems somewhat of an exception because the DT bindings use the
> (bank, line) pair encoding to reflect the names given to the lines in
> technical reference manuals. I like this because it makes the DTS files
> very easy to read and relate to schematics.

I did some googling and saw tegra binding accepted already. 
Juts curious why not to use two cells <bank/port> <pin>
it as for me much more readable and no masks/shifts 

> 
>> Actually, as per gpio.txt:
>> "Note that gpio-specifier length is controller dependent.  In the
>> above example, &gpio1 uses 2 cells to specify a gpio, while &gpio2
>> only uses one.",
>> so, if this going to be part of gpiolib it should be
>>   described in bindings/gpio/gpio.txt (or some other documents), as
>>   above note will not be exactly correct and new "banked" gpio controllers
>> will be expected to use thin new binding.
> 
> Yeah, that makes sense. I'll work on a patch that updates the binding
> documentation to include this particular encoding. Again, this is not
> intended to replace existing bindings because they may not be
> compatible. However, bindings for new banked controllers may be able
> to reuse this if it suits their needs.
> 
> Also, note that the rest of the banked infrastructure can be used
> independently of the ->xlate() callback. Drivers are free to use the
> of_gpio_simple_xlate() with the rest of the banked infrastructure to
> simplify the driver code.

-- 
regards,
-grygorii

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

end of thread, other threads:[~2017-10-10 22:57 UTC | newest]

Thread overview: 56+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-09-28  9:56 [PATCH v2 00/16] gpio: Tight IRQ chip integration and banked infrastructure Thierry Reding
2017-09-28  9:56 ` Thierry Reding
2017-09-28  9:56 ` [PATCH v2 01/16] gpio: Implement tighter IRQ chip integration Thierry Reding
     [not found]   ` <20170928095628.21966-2-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2017-09-28 14:22     ` Grygorii Strashko
2017-09-28 14:22       ` Grygorii Strashko
2017-10-10 22:56     ` Grygorii Strashko
2017-10-10 22:56       ` Grygorii Strashko
2017-09-28  9:56 ` [PATCH v2 03/16] gpio: Move irqdomain into struct gpio_irq_chip Thierry Reding
2017-09-28  9:56 ` [PATCH v2 04/16] gpio: Move irq_base to " Thierry Reding
2017-09-28  9:56 ` [PATCH v2 05/16] gpio: Move irq_handler " Thierry Reding
2017-09-28  9:56 ` [PATCH v2 06/16] gpio: Move irq_default_type " Thierry Reding
2017-09-28  9:56 ` [PATCH v2 08/16] gpio: Move irq_nested into " Thierry Reding
2017-09-28  9:56 ` [PATCH v2 10/16] gpio: Move lock_key " Thierry Reding
2017-09-28  9:56 ` [PATCH v2 11/16] gpio: Add Tegra186 support Thierry Reding
2017-09-28  9:56 ` [PATCH v2 12/16] gpio: omap: Fix checkpatch warnings Thierry Reding
2017-09-28  9:56 ` [PATCH v2 13/16] gpio: omap: Rename struct gpio_bank to struct omap_gpio_bank Thierry Reding
     [not found] ` <20170928095628.21966-1-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2017-09-28  9:56   ` [PATCH v2 02/16] gpio: Move irqchip into struct gpio_irq_chip Thierry Reding
2017-09-28  9:56     ` Thierry Reding
2017-09-28  9:56   ` [PATCH v2 07/16] gpio: Move irq_chained_parent to " Thierry Reding
2017-09-28  9:56     ` Thierry Reding
2017-09-28  9:56   ` [PATCH v2 09/16] gpio: Move irq_valid_mask into " Thierry Reding
2017-09-28  9:56     ` Thierry Reding
2017-09-28  9:56   ` [PATCH v2 14/16] gpio: Add support for banked GPIO controllers Thierry Reding
2017-09-28  9:56     ` Thierry Reding
     [not found]     ` <20170928095628.21966-15-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2017-10-09 21:52       ` Grygorii Strashko
2017-10-09 21:52         ` Grygorii Strashko
     [not found]         ` <ff3b45ec-2af0-5f34-aae8-bb54e892a64a-l0cyMroinI0@public.gmane.org>
2017-10-10 11:00           ` Thierry Reding
2017-10-10 11:00             ` Thierry Reding
2017-10-10 22:12             ` Grygorii Strashko
2017-10-10 22:12               ` Grygorii Strashko
2017-09-28  9:56   ` [PATCH v2 15/16] gpio: tegra: Use banked GPIO infrastructure Thierry Reding
2017-09-28  9:56     ` Thierry Reding
     [not found]     ` <20170928095628.21966-16-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2017-10-09 21:22       ` Grygorii Strashko
2017-10-09 21:22         ` Grygorii Strashko
2017-10-10 10:27         ` Thierry Reding
2017-10-10 19:31           ` Grygorii Strashko
2017-10-10 19:31             ` Grygorii Strashko
2017-09-28 14:22   ` [PATCH v2 00/16] gpio: Tight IRQ chip integration and banked infrastructure Grygorii Strashko
2017-09-28 14:22     ` Grygorii Strashko
2017-10-02  7:55     ` Linus Walleij
     [not found]       ` <CACRpkdagAxotP=VZr1NUvmNmHgACfr4x2aHkh=nyyEhUWWgzPw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2017-10-03 18:26         ` Grygorii Strashko
2017-10-03 18:26           ` Grygorii Strashko
2017-10-05 11:19           ` Linus Walleij
2017-10-05 11:14         ` Linus Walleij
2017-10-05 11:14           ` Linus Walleij
     [not found]     ` <44cf41e3-834e-ddb3-4c9e-8ab00e0866cb-l0cyMroinI0@public.gmane.org>
2017-10-06 11:07       ` Thierry Reding
2017-10-06 11:07         ` Thierry Reding
2017-10-06 11:11         ` Thierry Reding
2017-10-06 11:11           ` Thierry Reding
2017-10-09 21:56         ` Grygorii Strashko
2017-10-09 21:56           ` Grygorii Strashko
     [not found]           ` <2c1abc4e-828e-8cd6-cce7-73050f5322fb-l0cyMroinI0@public.gmane.org>
2017-10-10 11:27             ` Thierry Reding
2017-10-10 11:27               ` Thierry Reding
2017-10-10 22:56               ` Grygorii Strashko
2017-10-10 22:56                 ` Grygorii Strashko
2017-09-28  9:56 ` [PATCH v2 16/16] gpio: tegra186: Use banked GPIO infrastructure Thierry Reding

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.