All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RfC v3 0/7] pintrl: meson: add support for GPIO IRQs
@ 2017-05-17 20:02 ` Heiner Kallweit
  0 siblings, 0 replies; 22+ messages in thread
From: Heiner Kallweit @ 2017-05-17 20:02 UTC (permalink / raw)
  To: Jerome Brunet, Mark Rutland, Marc Zyngier, Linus Walleij,
	Kevin Hilman, Thomas Gleixner, Rob Herring
  Cc: devicetree, linux-amlogic, linux-gpio, thierry.reding, Thierry Reding

This patch series is partially based on a series Jerome Brunet
submitted about half a year ago. Due to open questions this series never
made it to mainline, see https://patchwork.kernel.org/patch/9384431/

This new attempt uses GPIOLIB_IRQCHIP resulting in less needed code.
Included is also support for using two parent IRQs in case
of IRQ_TYPE_EDGE_BOTH, like in the vendor driver.

The series was successfully tested on a Odroid-C2, e.g. with removing
polling for SD card insertion/removal from the mmc driver.

Known open issues:
- location of the irqchip driver and its DT binding documentation

Changes in v2:
- separate the GPIO IRQ controller from the pinctrl driver
- minor improvements to the GPIO IRQ controller

Changes in v3:
- replace the request_irq based allocation of parent irq's with
  chained irq handling, this also fixes the spurious interrupts issue
  and allows to remove the workaround code.
  Last but not least the parent irq's are no longer visible in
  /proc/interrupts.
- minor improvements to the GPIO IRQ controller

Heiner Kallweit (7):
  pinctrl: meson: add interrupts to pinctrl data
  pinctrl: meson: document GPIO IRQ DT binding
  pinctrl: meson: add DT node for GPIO IRQ on Meson GX
  pinctrl: meson: add DT node for GPIO IRQ on Meson 8 / 8b
  pinctrl: meson: improve meson_get_bank and export it
  pinctrl: meson: add support for GPIO interrupts
  pinctrl: meson: add interrupt controller to GPIO DT nodes

 .../bindings/gpio/amlogic,meson-gpio-interrupt.txt |  30 ++
 .../devicetree/bindings/pinctrl/meson,pinctrl.txt  |   4 +
 arch/arm/boot/dts/meson8.dtsi                      |  15 +
 arch/arm/boot/dts/meson8b.dtsi                     |  15 +
 arch/arm64/boot/dts/amlogic/meson-gx.dtsi          |  13 +
 arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi        |   4 +
 arch/arm64/boot/dts/amlogic/meson-gxl.dtsi         |   4 +
 drivers/pinctrl/Kconfig                            |   1 +
 drivers/pinctrl/meson/Makefile                     |   2 +-
 drivers/pinctrl/meson/pinctrl-meson-gxbb.c         |  22 +-
 drivers/pinctrl/meson/pinctrl-meson-gxl.c          |  20 +-
 drivers/pinctrl/meson/pinctrl-meson-irq.c          | 320 +++++++++++++++++++++
 drivers/pinctrl/meson/pinctrl-meson.c              |  62 ++--
 drivers/pinctrl/meson/pinctrl-meson.h              |  19 +-
 drivers/pinctrl/meson/pinctrl-meson8.c             |  20 +-
 drivers/pinctrl/meson/pinctrl-meson8b.c            |  32 ++-
 16 files changed, 502 insertions(+), 81 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/gpio/amlogic,meson-gpio-interrupt.txt
 create mode 100644 drivers/pinctrl/meson/pinctrl-meson-irq.c

-- 
2.13.0


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

* [PATCH RfC v3 0/7] pintrl: meson: add support for GPIO IRQs
@ 2017-05-17 20:02 ` Heiner Kallweit
  0 siblings, 0 replies; 22+ messages in thread
From: Heiner Kallweit @ 2017-05-17 20:02 UTC (permalink / raw)
  To: linus-amlogic

This patch series is partially based on a series Jerome Brunet
submitted about half a year ago. Due to open questions this series never
made it to mainline, see https://patchwork.kernel.org/patch/9384431/

This new attempt uses GPIOLIB_IRQCHIP resulting in less needed code.
Included is also support for using two parent IRQs in case
of IRQ_TYPE_EDGE_BOTH, like in the vendor driver.

The series was successfully tested on a Odroid-C2, e.g. with removing
polling for SD card insertion/removal from the mmc driver.

Known open issues:
- location of the irqchip driver and its DT binding documentation

Changes in v2:
- separate the GPIO IRQ controller from the pinctrl driver
- minor improvements to the GPIO IRQ controller

Changes in v3:
- replace the request_irq based allocation of parent irq's with
  chained irq handling, this also fixes the spurious interrupts issue
  and allows to remove the workaround code.
  Last but not least the parent irq's are no longer visible in
  /proc/interrupts.
- minor improvements to the GPIO IRQ controller

Heiner Kallweit (7):
  pinctrl: meson: add interrupts to pinctrl data
  pinctrl: meson: document GPIO IRQ DT binding
  pinctrl: meson: add DT node for GPIO IRQ on Meson GX
  pinctrl: meson: add DT node for GPIO IRQ on Meson 8 / 8b
  pinctrl: meson: improve meson_get_bank and export it
  pinctrl: meson: add support for GPIO interrupts
  pinctrl: meson: add interrupt controller to GPIO DT nodes

 .../bindings/gpio/amlogic,meson-gpio-interrupt.txt |  30 ++
 .../devicetree/bindings/pinctrl/meson,pinctrl.txt  |   4 +
 arch/arm/boot/dts/meson8.dtsi                      |  15 +
 arch/arm/boot/dts/meson8b.dtsi                     |  15 +
 arch/arm64/boot/dts/amlogic/meson-gx.dtsi          |  13 +
 arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi        |   4 +
 arch/arm64/boot/dts/amlogic/meson-gxl.dtsi         |   4 +
 drivers/pinctrl/Kconfig                            |   1 +
 drivers/pinctrl/meson/Makefile                     |   2 +-
 drivers/pinctrl/meson/pinctrl-meson-gxbb.c         |  22 +-
 drivers/pinctrl/meson/pinctrl-meson-gxl.c          |  20 +-
 drivers/pinctrl/meson/pinctrl-meson-irq.c          | 320 +++++++++++++++++++++
 drivers/pinctrl/meson/pinctrl-meson.c              |  62 ++--
 drivers/pinctrl/meson/pinctrl-meson.h              |  19 +-
 drivers/pinctrl/meson/pinctrl-meson8.c             |  20 +-
 drivers/pinctrl/meson/pinctrl-meson8b.c            |  32 ++-
 16 files changed, 502 insertions(+), 81 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/gpio/amlogic,meson-gpio-interrupt.txt
 create mode 100644 drivers/pinctrl/meson/pinctrl-meson-irq.c

-- 
2.13.0

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

* [PATCH RfC v3 1/7] pinctrl: meson: add interrupts to pinctrl data
  2017-05-17 20:02 ` Heiner Kallweit
@ 2017-05-17 20:16   ` Heiner Kallweit
  -1 siblings, 0 replies; 22+ messages in thread
From: Heiner Kallweit @ 2017-05-17 20:16 UTC (permalink / raw)
  To: Jerome Brunet, Mark Rutland, Marc Zyngier, Linus Walleij,
	Kevin Hilman, Thomas Gleixner, Rob Herring
  Cc: devicetree, linux-amlogic, linux-gpio, thierry.reding, Thierry Reding

From: Jerome Brunet <jbrunet@baylibre.com>
Add GPIO interrupt information to pinctrl data. Added to the original
version from Jerome was data for Meson GXL.

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
---
v2:
- no changes
v3:
- no changes
---
 drivers/pinctrl/meson/pinctrl-meson-gxbb.c | 22 ++++++++++----------
 drivers/pinctrl/meson/pinctrl-meson-gxl.c  | 20 +++++++++----------
 drivers/pinctrl/meson/pinctrl-meson.h      | 15 +++++++++-----
 drivers/pinctrl/meson/pinctrl-meson8.c     | 20 +++++++++----------
 drivers/pinctrl/meson/pinctrl-meson8b.c    | 32 ++++++++++++++++++++----------
 5 files changed, 63 insertions(+), 46 deletions(-)

diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
index 9b00be15..e54dbeaa 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
@@ -782,20 +782,20 @@ static struct meson_pmx_func meson_gxbb_aobus_functions[] = {
 };
 
 static struct meson_bank meson_gxbb_periphs_banks[] = {
-	/*   name    first                      last                    pullen  pull    dir     out     in  */
-	BANK("X",    PIN(GPIOX_0, EE_OFF),	PIN(GPIOX_22, EE_OFF),  4,  0,  4,  0,  12, 0,  13, 0,  14, 0),
-	BANK("Y",    PIN(GPIOY_0, EE_OFF),	PIN(GPIOY_16, EE_OFF),  1,  0,  1,  0,  3,  0,  4,  0,  5,  0),
-	BANK("DV",   PIN(GPIODV_0, EE_OFF),	PIN(GPIODV_29, EE_OFF), 0,  0,  0,  0,  0,  0,  1,  0,  2,  0),
-	BANK("H",    PIN(GPIOH_0, EE_OFF),	PIN(GPIOH_3, EE_OFF),   1, 20,  1, 20,  3, 20,  4, 20,  5, 20),
-	BANK("Z",    PIN(GPIOZ_0, EE_OFF),	PIN(GPIOZ_15, EE_OFF),  3,  0,  3,  0,  9,  0,  10, 0, 11,  0),
-	BANK("CARD", PIN(CARD_0, EE_OFF),	PIN(CARD_6, EE_OFF),    2, 20,  2, 20,  6, 20,  7, 20,  8, 20),
-	BANK("BOOT", PIN(BOOT_0, EE_OFF),	PIN(BOOT_17, EE_OFF),   2,  0,  2,  0,  6,  0,  7,  0,  8,  0),
-	BANK("CLK",  PIN(GPIOCLK_0, EE_OFF),	PIN(GPIOCLK_3, EE_OFF), 3, 28,  3, 28,  9, 28, 10, 28, 11, 28),
+	/*   name    first                      last                    irq       pullen  pull    dir     out     in  */
+	BANK("X",    PIN(GPIOX_0, EE_OFF),	PIN(GPIOX_22, EE_OFF),  106, 128, 4,  0,  4,  0,  12, 0,  13, 0,  14, 0),
+	BANK("Y",    PIN(GPIOY_0, EE_OFF),	PIN(GPIOY_16, EE_OFF),   89, 105, 1,  0,  1,  0,  3,  0,  4,  0,  5,  0),
+	BANK("DV",   PIN(GPIODV_0, EE_OFF),	PIN(GPIODV_29, EE_OFF),  59,  88, 0,  0,  0,  0,  0,  0,  1,  0,  2,  0),
+	BANK("H",    PIN(GPIOH_0, EE_OFF),	PIN(GPIOH_3, EE_OFF),    30,  33, 1, 20,  1, 20,  3, 20,  4, 20,  5, 20),
+	BANK("Z",    PIN(GPIOZ_0, EE_OFF),	PIN(GPIOZ_15, EE_OFF),   14,  29, 3,  0,  3,  0,  9,  0,  10, 0, 11,  0),
+	BANK("CARD", PIN(CARD_0, EE_OFF),	PIN(CARD_6, EE_OFF),     52,  58, 2, 20,  2, 20,  6, 20,  7, 20,  8, 20),
+	BANK("BOOT", PIN(BOOT_0, EE_OFF),	PIN(BOOT_17, EE_OFF),    34,  51, 2,  0,  2,  0,  6,  0,  7,  0,  8,  0),
+	BANK("CLK",  PIN(GPIOCLK_0, EE_OFF),	PIN(GPIOCLK_3, EE_OFF), 129, 132, 3, 28,  3, 28,  9, 28, 10, 28, 11, 28),
 };
 
 static struct meson_bank meson_gxbb_aobus_banks[] = {
-	/*   name    first              last               pullen  pull    dir     out     in  */
-	BANK("AO",   PIN(GPIOAO_0, 0),  PIN(GPIOAO_13, 0), 0,  0,  0, 16,  0,  0,  0, 16,  1,  0),
+	/*   name    first              last               irq    pullen  pull    dir     out     in  */
+	BANK("AO",   PIN(GPIOAO_0, 0),  PIN(GPIOAO_13, 0), 0, 13, 0,  0,  0, 16,  0,  0,  0, 16,  1,  0),
 };
 
 struct meson_pinctrl_data meson_gxbb_periphs_pinctrl_data = {
diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxl.c b/drivers/pinctrl/meson/pinctrl-meson-gxl.c
index 998210ea..bcd8da10 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-gxl.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxl.c
@@ -729,19 +729,19 @@ static struct meson_pmx_func meson_gxl_aobus_functions[] = {
 };
 
 static struct meson_bank meson_gxl_periphs_banks[] = {
-	/*   name    first                      last                    pullen  pull    dir     out     in  */
-	BANK("X",    PIN(GPIOX_0, EE_OFF),	PIN(GPIOX_18, EE_OFF),  4,  0,  4,  0,  12, 0,  13, 0,  14, 0),
-	BANK("DV",   PIN(GPIODV_0, EE_OFF),	PIN(GPIODV_29, EE_OFF), 0,  0,  0,  0,  0,  0,  1,  0,  2,  0),
-	BANK("H",    PIN(GPIOH_0, EE_OFF),	PIN(GPIOH_9, EE_OFF),   1, 20,  1, 20,  3, 20,  4, 20,  5, 20),
-	BANK("Z",    PIN(GPIOZ_0, EE_OFF),	PIN(GPIOZ_15, EE_OFF),  3,  0,  3,  0,  9,  0,  10, 0, 11,  0),
-	BANK("CARD", PIN(CARD_0, EE_OFF),	PIN(CARD_6, EE_OFF),    2, 20,  2, 20,  6, 20,  7, 20,  8, 20),
-	BANK("BOOT", PIN(BOOT_0, EE_OFF),	PIN(BOOT_15, EE_OFF),   2,  0,  2,  0,  6,  0,  7,  0,  8,  0),
-	BANK("CLK",  PIN(GPIOCLK_0, EE_OFF),	PIN(GPIOCLK_1, EE_OFF), 3, 28,  3, 28,  9, 28, 10, 28, 11, 28),
+	/*   name    first                      last                    irq	  pullen  pull    dir     out     in  */
+	BANK("X",    PIN(GPIOX_0, EE_OFF),	PIN(GPIOX_18, EE_OFF),   89, 107, 4,  0,  4,  0,  12, 0,  13, 0,  14, 0),
+	BANK("DV",   PIN(GPIODV_0, EE_OFF),	PIN(GPIODV_29, EE_OFF),  83,  88, 0,  0,  0,  0,  0,  0,  1,  0,  2,  0),
+	BANK("H",    PIN(GPIOH_0, EE_OFF),	PIN(GPIOH_9, EE_OFF),    26,  35, 1, 20,  1, 20,  3, 20,  4, 20,  5, 20),
+	BANK("Z",    PIN(GPIOZ_0, EE_OFF),	PIN(GPIOZ_15, EE_OFF),   10,  25, 3,  0,  3,  0,  9,  0,  10, 0, 11,  0),
+	BANK("CARD", PIN(CARD_0, EE_OFF),	PIN(CARD_6, EE_OFF),     52,  58, 2, 20,  2, 20,  6, 20,  7, 20,  8, 20),
+	BANK("BOOT", PIN(BOOT_0, EE_OFF),	PIN(BOOT_15, EE_OFF),    36,  51, 2,  0,  2,  0,  6,  0,  7,  0,  8,  0),
+	BANK("CLK",  PIN(GPIOCLK_0, EE_OFF),	PIN(GPIOCLK_1, EE_OFF), 108, 109, 3, 28,  3, 28,  9, 28, 10, 28, 11, 28),
 };
 
 static struct meson_bank meson_gxl_aobus_banks[] = {
-	/*   name    first              last              pullen  pull    dir     out     in  */
-	BANK("AO",   PIN(GPIOAO_0, 0),  PIN(GPIOAO_9, 0), 0,  0,  0, 16,  0,  0,  0, 16,  1,  0),
+	/*   name    first              last              irq	pullen  pull    dir     out     in  */
+	BANK("AO",   PIN(GPIOAO_0, 0),  PIN(GPIOAO_9, 0), 0, 9, 0,  0,  0, 16,  0,  0,  0, 16,  1,  0),
 };
 
 struct meson_pinctrl_data meson_gxl_periphs_pinctrl_data = {
diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h
index 1aa871d5..890f296f 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.h
+++ b/drivers/pinctrl/meson/pinctrl-meson.h
@@ -81,6 +81,7 @@ enum meson_reg_type {
  * @name:	bank name
  * @first:	first pin of the bank
  * @last:	last pin of the bank
+ * @irq:	hwirq base number of the bank
  * @regs:	array of register descriptors
  *
  * A bank represents a set of pins controlled by a contiguous set of
@@ -92,6 +93,8 @@ struct meson_bank {
 	const char *name;
 	unsigned int first;
 	unsigned int last;
+	int irq_first;
+	int irq_last;
 	struct meson_reg_desc regs[NUM_REG];
 };
 
@@ -147,12 +150,14 @@ struct meson_pinctrl {
 		.num_groups = ARRAY_SIZE(fn ## _groups),		\
 	}
 
-#define BANK(n, f, l, per, peb, pr, pb, dr, db, or, ob, ir, ib)		\
+#define BANK(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib)	\
 	{								\
-		.name	= n,						\
-		.first	= f,						\
-		.last	= l,						\
-		.regs	= {						\
+		.name		= n,					\
+		.first		= f,					\
+		.last		= l,					\
+		.irq_first	= fi,					\
+		.irq_last	= li,					\
+		.regs = {						\
 			[REG_PULLEN]	= { per, peb },			\
 			[REG_PULL]	= { pr, pb },			\
 			[REG_DIR]	= { dr, db },			\
diff --git a/drivers/pinctrl/meson/pinctrl-meson8.c b/drivers/pinctrl/meson/pinctrl-meson8.c
index 07f1cb21..32449820 100644
--- a/drivers/pinctrl/meson/pinctrl-meson8.c
+++ b/drivers/pinctrl/meson/pinctrl-meson8.c
@@ -916,19 +916,19 @@ static struct meson_pmx_func meson8_aobus_functions[] = {
 };
 
 static struct meson_bank meson8_cbus_banks[] = {
-	/*   name    first             last                 pullen  pull    dir     out     in  */
-	BANK("X",    PIN(GPIOX_0, 0),  PIN(GPIOX_21, 0),    4,  0,  4,  0,  0,  0,  1,  0,  2,  0),
-	BANK("Y",    PIN(GPIOY_0, 0),  PIN(GPIOY_16, 0),    3,  0,  3,  0,  3,  0,  4,  0,  5,  0),
-	BANK("DV",   PIN(GPIODV_0, 0), PIN(GPIODV_29, 0),   0,  0,  0,  0,  7,  0,  8,  0,  9,  0),
-	BANK("H",    PIN(GPIOH_0, 0),  PIN(GPIOH_9, 0),     1, 16,  1, 16,  9, 19, 10, 19, 11, 19),
-	BANK("Z",    PIN(GPIOZ_0, 0),  PIN(GPIOZ_14, 0),    1,  0,  1,  0,  3, 17,  4, 17,  5, 17),
-	BANK("CARD", PIN(CARD_0, 0),   PIN(CARD_6, 0),      2, 20,  2, 20,  0, 22,  1, 22,  2, 22),
-	BANK("BOOT", PIN(BOOT_0, 0),   PIN(BOOT_18, 0),     2,  0,  2,  0,  9,  0, 10,  0, 11,  0),
+	/*   name    first             last                 irq       pullen  pull    dir     out     in  */
+	BANK("X",    PIN(GPIOX_0, 0),  PIN(GPIOX_21, 0),    112, 133, 4,  0,  4,  0,  0,  0,  1,  0,  2,  0),
+	BANK("Y",    PIN(GPIOY_0, 0),  PIN(GPIOY_16, 0),    95,  111, 3,  0,  3,  0,  3,  0,  4,  0,  5,  0),
+	BANK("DV",   PIN(GPIODV_0, 0), PIN(GPIODV_29, 0),   65,   94, 0,  0,  0,  0,  7,  0,  8,  0,  9,  0),
+	BANK("H",    PIN(GPIOH_0, 0),  PIN(GPIOH_9, 0),     29,   38, 1, 16,  1, 16,  9, 19, 10, 19, 11, 19),
+	BANK("Z",    PIN(GPIOZ_0, 0),  PIN(GPIOZ_14, 0),    14,   28, 1,  0,  1,  0,  3, 17,  4, 17,  5, 17),
+	BANK("CARD", PIN(CARD_0, 0),   PIN(CARD_6, 0),      58,   64, 2, 20,  2, 20,  0, 22,  1, 22,  2, 22),
+	BANK("BOOT", PIN(BOOT_0, 0),   PIN(BOOT_18, 0),     39,   57, 2,  0,  2,  0,  9,  0, 10,  0, 11,  0),
 };
 
 static struct meson_bank meson8_aobus_banks[] = {
-	/*   name    first                  last                      pullen  pull    dir     out     in  */
-	BANK("AO",   PIN(GPIOAO_0, AO_OFF), PIN(GPIO_TEST_N, AO_OFF), 0,  0,  0, 16,  0,  0,  0, 16,  1,  0),
+	/*   name    first                  last                      irq    pullen  pull    dir     out     in  */
+	BANK("AO",   PIN(GPIOAO_0, AO_OFF), PIN(GPIO_TEST_N, AO_OFF), 0, 13, 0,  0,  0, 16,  0,  0,  0, 16,  1,  0),
 };
 
 struct meson_pinctrl_data meson8_cbus_pinctrl_data = {
diff --git a/drivers/pinctrl/meson/pinctrl-meson8b.c b/drivers/pinctrl/meson/pinctrl-meson8b.c
index bf747eb1..71f216b5 100644
--- a/drivers/pinctrl/meson/pinctrl-meson8b.c
+++ b/drivers/pinctrl/meson/pinctrl-meson8b.c
@@ -124,6 +124,12 @@ static const struct pinctrl_pin_desc meson8b_aobus_pins[] = {
 	MESON_PIN(GPIOAO_11, AO_OFF),
 	MESON_PIN(GPIOAO_12, AO_OFF),
 	MESON_PIN(GPIOAO_13, AO_OFF),
+
+	/*
+	 * The following 2 pins are not mentionned in the public datasheet
+	 * According to this datasheet, they can't be used with the gpio
+	 * interrupt controller
+	 */
 	MESON_PIN(GPIO_BSD_EN, AO_OFF),
 	MESON_PIN(GPIO_TEST_N, AO_OFF),
 };
@@ -881,19 +887,25 @@ static struct meson_pmx_func meson8b_aobus_functions[] = {
 };
 
 static struct meson_bank meson8b_cbus_banks[] = {
-	/*   name    first                      last                   pullen  pull    dir     out     in  */
-	BANK("X",    PIN(GPIOX_0, 0),		PIN(GPIOX_21, 0),      4,  0,  4,  0,  0,  0,  1,  0,  2,  0),
-	BANK("Y",    PIN(GPIOY_0, 0),		PIN(GPIOY_14, 0),      3,  0,  3,  0,  3,  0,  4,  0,  5,  0),
-	BANK("DV",   PIN(GPIODV_9, 0),		PIN(GPIODV_29, 0),     0,  0,  0,  0,  7,  0,  8,  0,  9,  0),
-	BANK("H",    PIN(GPIOH_0, 0),		PIN(GPIOH_9, 0),       1, 16,  1, 16,  9, 19, 10, 19, 11, 19),
-	BANK("CARD", PIN(CARD_0, 0),		PIN(CARD_6, 0),        2, 20,  2, 20,  0, 22,  1, 22,  2, 22),
-	BANK("BOOT", PIN(BOOT_0, 0),		PIN(BOOT_18, 0),       2,  0,  2,  0,  9,  0, 10,  0, 11,  0),
-	BANK("DIF",  PIN(DIF_0_P, 0),		PIN(DIF_4_N, 0),       5,  8,  5,  8, 12, 12, 13, 12, 14, 12),
+	/*   name    first                      last                irq      pullen  pull    dir     out     in  */
+	BANK("X",    PIN(GPIOX_0, 0),		PIN(GPIOX_21, 0),   97, 118, 4,  0,  4,  0,  0,  0,  1,  0,  2,  0),
+	BANK("Y",    PIN(GPIOY_0, 0),		PIN(GPIOY_14, 0),   80,  96, 3,  0,  3,  0,  3,  0,  4,  0,  5,  0),
+	BANK("DV",   PIN(GPIODV_9, 0),		PIN(GPIODV_29, 0),  59,  79, 0,  0,  0,  0,  7,  0,  8,  0,  9,  0),
+	BANK("H",    PIN(GPIOH_0, 0),		PIN(GPIOH_9, 0),    14,  23, 1, 16,  1, 16,  9, 19, 10, 19, 11, 19),
+	BANK("CARD", PIN(CARD_0, 0),		PIN(CARD_6, 0),     43,  49, 2, 20,  2, 20,  0, 22,  1, 22,  2, 22),
+	BANK("BOOT", PIN(BOOT_0, 0),		PIN(BOOT_18, 0),    24,  42, 2,  0,  2,  0,  9,  0, 10,  0, 11,  0),
+
+	/*
+	 * The following bank is not mentionned in the public datasheet
+	 * There is no information whether it can be used with the gpio
+	 * interrupt controller
+	 */
+	BANK("DIF",  PIN(DIF_0_P, 0),		PIN(DIF_4_N, 0),    -1,  -1, 5,  8,  5,  8, 12, 12, 13, 12, 14, 12),
 };
 
 static struct meson_bank meson8b_aobus_banks[] = {
-	/*   name    first                  last                      pullen  pull    dir     out     in  */
-	BANK("AO",   PIN(GPIOAO_0, AO_OFF), PIN(GPIO_TEST_N, AO_OFF), 0,  0,  0, 16,  0,  0,  0, 16,  1,  0),
+	/*   name    first                  last                      irq    pullen  pull    dir     out     in  */
+	BANK("AO",   PIN(GPIOAO_0, AO_OFF), PIN(GPIO_TEST_N, AO_OFF), 0, 13, 0,  0,  0, 16,  0,  0,  0, 16,  1,  0),
 };
 
 struct meson_pinctrl_data meson8b_cbus_pinctrl_data = {
-- 
2.13.0



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

* [PATCH RfC v3 1/7] pinctrl: meson: add interrupts to pinctrl data
@ 2017-05-17 20:16   ` Heiner Kallweit
  0 siblings, 0 replies; 22+ messages in thread
From: Heiner Kallweit @ 2017-05-17 20:16 UTC (permalink / raw)
  To: linus-amlogic

From: Jerome Brunet <jbrunet@baylibre.com>
Add GPIO interrupt information to pinctrl data. Added to the original
version from Jerome was data for Meson GXL.

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
---
v2:
- no changes
v3:
- no changes
---
 drivers/pinctrl/meson/pinctrl-meson-gxbb.c | 22 ++++++++++----------
 drivers/pinctrl/meson/pinctrl-meson-gxl.c  | 20 +++++++++----------
 drivers/pinctrl/meson/pinctrl-meson.h      | 15 +++++++++-----
 drivers/pinctrl/meson/pinctrl-meson8.c     | 20 +++++++++----------
 drivers/pinctrl/meson/pinctrl-meson8b.c    | 32 ++++++++++++++++++++----------
 5 files changed, 63 insertions(+), 46 deletions(-)

diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
index 9b00be15..e54dbeaa 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
@@ -782,20 +782,20 @@ static struct meson_pmx_func meson_gxbb_aobus_functions[] = {
 };
 
 static struct meson_bank meson_gxbb_periphs_banks[] = {
-	/*   name    first                      last                    pullen  pull    dir     out     in  */
-	BANK("X",    PIN(GPIOX_0, EE_OFF),	PIN(GPIOX_22, EE_OFF),  4,  0,  4,  0,  12, 0,  13, 0,  14, 0),
-	BANK("Y",    PIN(GPIOY_0, EE_OFF),	PIN(GPIOY_16, EE_OFF),  1,  0,  1,  0,  3,  0,  4,  0,  5,  0),
-	BANK("DV",   PIN(GPIODV_0, EE_OFF),	PIN(GPIODV_29, EE_OFF), 0,  0,  0,  0,  0,  0,  1,  0,  2,  0),
-	BANK("H",    PIN(GPIOH_0, EE_OFF),	PIN(GPIOH_3, EE_OFF),   1, 20,  1, 20,  3, 20,  4, 20,  5, 20),
-	BANK("Z",    PIN(GPIOZ_0, EE_OFF),	PIN(GPIOZ_15, EE_OFF),  3,  0,  3,  0,  9,  0,  10, 0, 11,  0),
-	BANK("CARD", PIN(CARD_0, EE_OFF),	PIN(CARD_6, EE_OFF),    2, 20,  2, 20,  6, 20,  7, 20,  8, 20),
-	BANK("BOOT", PIN(BOOT_0, EE_OFF),	PIN(BOOT_17, EE_OFF),   2,  0,  2,  0,  6,  0,  7,  0,  8,  0),
-	BANK("CLK",  PIN(GPIOCLK_0, EE_OFF),	PIN(GPIOCLK_3, EE_OFF), 3, 28,  3, 28,  9, 28, 10, 28, 11, 28),
+	/*   name    first                      last                    irq       pullen  pull    dir     out     in  */
+	BANK("X",    PIN(GPIOX_0, EE_OFF),	PIN(GPIOX_22, EE_OFF),  106, 128, 4,  0,  4,  0,  12, 0,  13, 0,  14, 0),
+	BANK("Y",    PIN(GPIOY_0, EE_OFF),	PIN(GPIOY_16, EE_OFF),   89, 105, 1,  0,  1,  0,  3,  0,  4,  0,  5,  0),
+	BANK("DV",   PIN(GPIODV_0, EE_OFF),	PIN(GPIODV_29, EE_OFF),  59,  88, 0,  0,  0,  0,  0,  0,  1,  0,  2,  0),
+	BANK("H",    PIN(GPIOH_0, EE_OFF),	PIN(GPIOH_3, EE_OFF),    30,  33, 1, 20,  1, 20,  3, 20,  4, 20,  5, 20),
+	BANK("Z",    PIN(GPIOZ_0, EE_OFF),	PIN(GPIOZ_15, EE_OFF),   14,  29, 3,  0,  3,  0,  9,  0,  10, 0, 11,  0),
+	BANK("CARD", PIN(CARD_0, EE_OFF),	PIN(CARD_6, EE_OFF),     52,  58, 2, 20,  2, 20,  6, 20,  7, 20,  8, 20),
+	BANK("BOOT", PIN(BOOT_0, EE_OFF),	PIN(BOOT_17, EE_OFF),    34,  51, 2,  0,  2,  0,  6,  0,  7,  0,  8,  0),
+	BANK("CLK",  PIN(GPIOCLK_0, EE_OFF),	PIN(GPIOCLK_3, EE_OFF), 129, 132, 3, 28,  3, 28,  9, 28, 10, 28, 11, 28),
 };
 
 static struct meson_bank meson_gxbb_aobus_banks[] = {
-	/*   name    first              last               pullen  pull    dir     out     in  */
-	BANK("AO",   PIN(GPIOAO_0, 0),  PIN(GPIOAO_13, 0), 0,  0,  0, 16,  0,  0,  0, 16,  1,  0),
+	/*   name    first              last               irq    pullen  pull    dir     out     in  */
+	BANK("AO",   PIN(GPIOAO_0, 0),  PIN(GPIOAO_13, 0), 0, 13, 0,  0,  0, 16,  0,  0,  0, 16,  1,  0),
 };
 
 struct meson_pinctrl_data meson_gxbb_periphs_pinctrl_data = {
diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxl.c b/drivers/pinctrl/meson/pinctrl-meson-gxl.c
index 998210ea..bcd8da10 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-gxl.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxl.c
@@ -729,19 +729,19 @@ static struct meson_pmx_func meson_gxl_aobus_functions[] = {
 };
 
 static struct meson_bank meson_gxl_periphs_banks[] = {
-	/*   name    first                      last                    pullen  pull    dir     out     in  */
-	BANK("X",    PIN(GPIOX_0, EE_OFF),	PIN(GPIOX_18, EE_OFF),  4,  0,  4,  0,  12, 0,  13, 0,  14, 0),
-	BANK("DV",   PIN(GPIODV_0, EE_OFF),	PIN(GPIODV_29, EE_OFF), 0,  0,  0,  0,  0,  0,  1,  0,  2,  0),
-	BANK("H",    PIN(GPIOH_0, EE_OFF),	PIN(GPIOH_9, EE_OFF),   1, 20,  1, 20,  3, 20,  4, 20,  5, 20),
-	BANK("Z",    PIN(GPIOZ_0, EE_OFF),	PIN(GPIOZ_15, EE_OFF),  3,  0,  3,  0,  9,  0,  10, 0, 11,  0),
-	BANK("CARD", PIN(CARD_0, EE_OFF),	PIN(CARD_6, EE_OFF),    2, 20,  2, 20,  6, 20,  7, 20,  8, 20),
-	BANK("BOOT", PIN(BOOT_0, EE_OFF),	PIN(BOOT_15, EE_OFF),   2,  0,  2,  0,  6,  0,  7,  0,  8,  0),
-	BANK("CLK",  PIN(GPIOCLK_0, EE_OFF),	PIN(GPIOCLK_1, EE_OFF), 3, 28,  3, 28,  9, 28, 10, 28, 11, 28),
+	/*   name    first                      last                    irq	  pullen  pull    dir     out     in  */
+	BANK("X",    PIN(GPIOX_0, EE_OFF),	PIN(GPIOX_18, EE_OFF),   89, 107, 4,  0,  4,  0,  12, 0,  13, 0,  14, 0),
+	BANK("DV",   PIN(GPIODV_0, EE_OFF),	PIN(GPIODV_29, EE_OFF),  83,  88, 0,  0,  0,  0,  0,  0,  1,  0,  2,  0),
+	BANK("H",    PIN(GPIOH_0, EE_OFF),	PIN(GPIOH_9, EE_OFF),    26,  35, 1, 20,  1, 20,  3, 20,  4, 20,  5, 20),
+	BANK("Z",    PIN(GPIOZ_0, EE_OFF),	PIN(GPIOZ_15, EE_OFF),   10,  25, 3,  0,  3,  0,  9,  0,  10, 0, 11,  0),
+	BANK("CARD", PIN(CARD_0, EE_OFF),	PIN(CARD_6, EE_OFF),     52,  58, 2, 20,  2, 20,  6, 20,  7, 20,  8, 20),
+	BANK("BOOT", PIN(BOOT_0, EE_OFF),	PIN(BOOT_15, EE_OFF),    36,  51, 2,  0,  2,  0,  6,  0,  7,  0,  8,  0),
+	BANK("CLK",  PIN(GPIOCLK_0, EE_OFF),	PIN(GPIOCLK_1, EE_OFF), 108, 109, 3, 28,  3, 28,  9, 28, 10, 28, 11, 28),
 };
 
 static struct meson_bank meson_gxl_aobus_banks[] = {
-	/*   name    first              last              pullen  pull    dir     out     in  */
-	BANK("AO",   PIN(GPIOAO_0, 0),  PIN(GPIOAO_9, 0), 0,  0,  0, 16,  0,  0,  0, 16,  1,  0),
+	/*   name    first              last              irq	pullen  pull    dir     out     in  */
+	BANK("AO",   PIN(GPIOAO_0, 0),  PIN(GPIOAO_9, 0), 0, 9, 0,  0,  0, 16,  0,  0,  0, 16,  1,  0),
 };
 
 struct meson_pinctrl_data meson_gxl_periphs_pinctrl_data = {
diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h
index 1aa871d5..890f296f 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.h
+++ b/drivers/pinctrl/meson/pinctrl-meson.h
@@ -81,6 +81,7 @@ enum meson_reg_type {
  * @name:	bank name
  * @first:	first pin of the bank
  * @last:	last pin of the bank
+ * @irq:	hwirq base number of the bank
  * @regs:	array of register descriptors
  *
  * A bank represents a set of pins controlled by a contiguous set of
@@ -92,6 +93,8 @@ struct meson_bank {
 	const char *name;
 	unsigned int first;
 	unsigned int last;
+	int irq_first;
+	int irq_last;
 	struct meson_reg_desc regs[NUM_REG];
 };
 
@@ -147,12 +150,14 @@ struct meson_pinctrl {
 		.num_groups = ARRAY_SIZE(fn ## _groups),		\
 	}
 
-#define BANK(n, f, l, per, peb, pr, pb, dr, db, or, ob, ir, ib)		\
+#define BANK(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib)	\
 	{								\
-		.name	= n,						\
-		.first	= f,						\
-		.last	= l,						\
-		.regs	= {						\
+		.name		= n,					\
+		.first		= f,					\
+		.last		= l,					\
+		.irq_first	= fi,					\
+		.irq_last	= li,					\
+		.regs = {						\
 			[REG_PULLEN]	= { per, peb },			\
 			[REG_PULL]	= { pr, pb },			\
 			[REG_DIR]	= { dr, db },			\
diff --git a/drivers/pinctrl/meson/pinctrl-meson8.c b/drivers/pinctrl/meson/pinctrl-meson8.c
index 07f1cb21..32449820 100644
--- a/drivers/pinctrl/meson/pinctrl-meson8.c
+++ b/drivers/pinctrl/meson/pinctrl-meson8.c
@@ -916,19 +916,19 @@ static struct meson_pmx_func meson8_aobus_functions[] = {
 };
 
 static struct meson_bank meson8_cbus_banks[] = {
-	/*   name    first             last                 pullen  pull    dir     out     in  */
-	BANK("X",    PIN(GPIOX_0, 0),  PIN(GPIOX_21, 0),    4,  0,  4,  0,  0,  0,  1,  0,  2,  0),
-	BANK("Y",    PIN(GPIOY_0, 0),  PIN(GPIOY_16, 0),    3,  0,  3,  0,  3,  0,  4,  0,  5,  0),
-	BANK("DV",   PIN(GPIODV_0, 0), PIN(GPIODV_29, 0),   0,  0,  0,  0,  7,  0,  8,  0,  9,  0),
-	BANK("H",    PIN(GPIOH_0, 0),  PIN(GPIOH_9, 0),     1, 16,  1, 16,  9, 19, 10, 19, 11, 19),
-	BANK("Z",    PIN(GPIOZ_0, 0),  PIN(GPIOZ_14, 0),    1,  0,  1,  0,  3, 17,  4, 17,  5, 17),
-	BANK("CARD", PIN(CARD_0, 0),   PIN(CARD_6, 0),      2, 20,  2, 20,  0, 22,  1, 22,  2, 22),
-	BANK("BOOT", PIN(BOOT_0, 0),   PIN(BOOT_18, 0),     2,  0,  2,  0,  9,  0, 10,  0, 11,  0),
+	/*   name    first             last                 irq       pullen  pull    dir     out     in  */
+	BANK("X",    PIN(GPIOX_0, 0),  PIN(GPIOX_21, 0),    112, 133, 4,  0,  4,  0,  0,  0,  1,  0,  2,  0),
+	BANK("Y",    PIN(GPIOY_0, 0),  PIN(GPIOY_16, 0),    95,  111, 3,  0,  3,  0,  3,  0,  4,  0,  5,  0),
+	BANK("DV",   PIN(GPIODV_0, 0), PIN(GPIODV_29, 0),   65,   94, 0,  0,  0,  0,  7,  0,  8,  0,  9,  0),
+	BANK("H",    PIN(GPIOH_0, 0),  PIN(GPIOH_9, 0),     29,   38, 1, 16,  1, 16,  9, 19, 10, 19, 11, 19),
+	BANK("Z",    PIN(GPIOZ_0, 0),  PIN(GPIOZ_14, 0),    14,   28, 1,  0,  1,  0,  3, 17,  4, 17,  5, 17),
+	BANK("CARD", PIN(CARD_0, 0),   PIN(CARD_6, 0),      58,   64, 2, 20,  2, 20,  0, 22,  1, 22,  2, 22),
+	BANK("BOOT", PIN(BOOT_0, 0),   PIN(BOOT_18, 0),     39,   57, 2,  0,  2,  0,  9,  0, 10,  0, 11,  0),
 };
 
 static struct meson_bank meson8_aobus_banks[] = {
-	/*   name    first                  last                      pullen  pull    dir     out     in  */
-	BANK("AO",   PIN(GPIOAO_0, AO_OFF), PIN(GPIO_TEST_N, AO_OFF), 0,  0,  0, 16,  0,  0,  0, 16,  1,  0),
+	/*   name    first                  last                      irq    pullen  pull    dir     out     in  */
+	BANK("AO",   PIN(GPIOAO_0, AO_OFF), PIN(GPIO_TEST_N, AO_OFF), 0, 13, 0,  0,  0, 16,  0,  0,  0, 16,  1,  0),
 };
 
 struct meson_pinctrl_data meson8_cbus_pinctrl_data = {
diff --git a/drivers/pinctrl/meson/pinctrl-meson8b.c b/drivers/pinctrl/meson/pinctrl-meson8b.c
index bf747eb1..71f216b5 100644
--- a/drivers/pinctrl/meson/pinctrl-meson8b.c
+++ b/drivers/pinctrl/meson/pinctrl-meson8b.c
@@ -124,6 +124,12 @@ static const struct pinctrl_pin_desc meson8b_aobus_pins[] = {
 	MESON_PIN(GPIOAO_11, AO_OFF),
 	MESON_PIN(GPIOAO_12, AO_OFF),
 	MESON_PIN(GPIOAO_13, AO_OFF),
+
+	/*
+	 * The following 2 pins are not mentionned in the public datasheet
+	 * According to this datasheet, they can't be used with the gpio
+	 * interrupt controller
+	 */
 	MESON_PIN(GPIO_BSD_EN, AO_OFF),
 	MESON_PIN(GPIO_TEST_N, AO_OFF),
 };
@@ -881,19 +887,25 @@ static struct meson_pmx_func meson8b_aobus_functions[] = {
 };
 
 static struct meson_bank meson8b_cbus_banks[] = {
-	/*   name    first                      last                   pullen  pull    dir     out     in  */
-	BANK("X",    PIN(GPIOX_0, 0),		PIN(GPIOX_21, 0),      4,  0,  4,  0,  0,  0,  1,  0,  2,  0),
-	BANK("Y",    PIN(GPIOY_0, 0),		PIN(GPIOY_14, 0),      3,  0,  3,  0,  3,  0,  4,  0,  5,  0),
-	BANK("DV",   PIN(GPIODV_9, 0),		PIN(GPIODV_29, 0),     0,  0,  0,  0,  7,  0,  8,  0,  9,  0),
-	BANK("H",    PIN(GPIOH_0, 0),		PIN(GPIOH_9, 0),       1, 16,  1, 16,  9, 19, 10, 19, 11, 19),
-	BANK("CARD", PIN(CARD_0, 0),		PIN(CARD_6, 0),        2, 20,  2, 20,  0, 22,  1, 22,  2, 22),
-	BANK("BOOT", PIN(BOOT_0, 0),		PIN(BOOT_18, 0),       2,  0,  2,  0,  9,  0, 10,  0, 11,  0),
-	BANK("DIF",  PIN(DIF_0_P, 0),		PIN(DIF_4_N, 0),       5,  8,  5,  8, 12, 12, 13, 12, 14, 12),
+	/*   name    first                      last                irq      pullen  pull    dir     out     in  */
+	BANK("X",    PIN(GPIOX_0, 0),		PIN(GPIOX_21, 0),   97, 118, 4,  0,  4,  0,  0,  0,  1,  0,  2,  0),
+	BANK("Y",    PIN(GPIOY_0, 0),		PIN(GPIOY_14, 0),   80,  96, 3,  0,  3,  0,  3,  0,  4,  0,  5,  0),
+	BANK("DV",   PIN(GPIODV_9, 0),		PIN(GPIODV_29, 0),  59,  79, 0,  0,  0,  0,  7,  0,  8,  0,  9,  0),
+	BANK("H",    PIN(GPIOH_0, 0),		PIN(GPIOH_9, 0),    14,  23, 1, 16,  1, 16,  9, 19, 10, 19, 11, 19),
+	BANK("CARD", PIN(CARD_0, 0),		PIN(CARD_6, 0),     43,  49, 2, 20,  2, 20,  0, 22,  1, 22,  2, 22),
+	BANK("BOOT", PIN(BOOT_0, 0),		PIN(BOOT_18, 0),    24,  42, 2,  0,  2,  0,  9,  0, 10,  0, 11,  0),
+
+	/*
+	 * The following bank is not mentionned in the public datasheet
+	 * There is no information whether it can be used with the gpio
+	 * interrupt controller
+	 */
+	BANK("DIF",  PIN(DIF_0_P, 0),		PIN(DIF_4_N, 0),    -1,  -1, 5,  8,  5,  8, 12, 12, 13, 12, 14, 12),
 };
 
 static struct meson_bank meson8b_aobus_banks[] = {
-	/*   name    first                  last                      pullen  pull    dir     out     in  */
-	BANK("AO",   PIN(GPIOAO_0, AO_OFF), PIN(GPIO_TEST_N, AO_OFF), 0,  0,  0, 16,  0,  0,  0, 16,  1,  0),
+	/*   name    first                  last                      irq    pullen  pull    dir     out     in  */
+	BANK("AO",   PIN(GPIOAO_0, AO_OFF), PIN(GPIO_TEST_N, AO_OFF), 0, 13, 0,  0,  0, 16,  0,  0,  0, 16,  1,  0),
 };
 
 struct meson_pinctrl_data meson8b_cbus_pinctrl_data = {
-- 
2.13.0

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

* [PATCH RfC v3 2/7] pinctrl: meson: document GPIO IRQ driver DT binding
  2017-05-17 20:02 ` Heiner Kallweit
@ 2017-05-17 20:16     ` Heiner Kallweit
  -1 siblings, 0 replies; 22+ messages in thread
From: Heiner Kallweit @ 2017-05-17 20:16 UTC (permalink / raw)
  To: Jerome Brunet, Mark Rutland, Marc Zyngier, Linus Walleij,
	Kevin Hilman, Thomas Gleixner, Rob Herring
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w, Thierry Reding

Document the DT binding for GPIO IRQ support on Amlogic Meson SoC's.

This documentation is intentionally not placed under
interrupt-controllers as GPIO IRQ support on these SoC's acts more
like an interrupt multiplexer.

Signed-off-by: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
v2:
- remove syscon
v3:
- no changes
---
 .../bindings/gpio/amlogic,meson-gpio-interrupt.txt | 30 ++++++++++++++++++++++
 1 file changed, 30 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/gpio/amlogic,meson-gpio-interrupt.txt

diff --git a/Documentation/devicetree/bindings/gpio/amlogic,meson-gpio-interrupt.txt b/Documentation/devicetree/bindings/gpio/amlogic,meson-gpio-interrupt.txt
new file mode 100644
index 00000000..ba7d3015
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/amlogic,meson-gpio-interrupt.txt
@@ -0,0 +1,30 @@
+Amlogic meson GPIO interrupt controller
+
+Meson SoCs contains an interrupt controller which is able watch the SoC pads
+and generate an interrupt on edges or level. The controller is essentially a
+256 pads to 8 GIC interrupt multiplexer, with a filter block to select edge
+or level and polarity. We don't expose all 256 mux inputs because the
+documentation shows that upper part is not mapped to any pad. The actual number
+of interrupt exposed depends on the SoC.
+
+Required properties:
+
+- compatible : should be "amlogic,meson-gpio-interrupt".
+- reg : Specifies base physical address and size of the registers.
+- interrupts : list of GIC interrupts which can be used with the
+	       GPIO IRQ multiplexer
+
+Example:
+
+gpio_irq@9880 {
+	compatible = "amlogic,meson-gpio-interrupt";
+	reg = <0x0 0x09880 0x0 0x10>;
+	interrupts = <GIC_SPI 64 IRQ_TYPE_NONE>,
+		     <GIC_SPI 65 IRQ_TYPE_NONE>,
+		     <GIC_SPI 66 IRQ_TYPE_NONE>,
+		     <GIC_SPI 67 IRQ_TYPE_NONE>,
+		     <GIC_SPI 68 IRQ_TYPE_NONE>,
+		     <GIC_SPI 69 IRQ_TYPE_NONE>,
+		     <GIC_SPI 70 IRQ_TYPE_NONE>,
+		     <GIC_SPI 71 IRQ_TYPE_NONE>;
+	};
-- 
2.13.0


--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH RfC v3 2/7] pinctrl: meson: document GPIO IRQ driver DT binding
@ 2017-05-17 20:16     ` Heiner Kallweit
  0 siblings, 0 replies; 22+ messages in thread
From: Heiner Kallweit @ 2017-05-17 20:16 UTC (permalink / raw)
  To: linus-amlogic

Document the DT binding for GPIO IRQ support on Amlogic Meson SoC's.

This documentation is intentionally not placed under
interrupt-controllers as GPIO IRQ support on these SoC's acts more
like an interrupt multiplexer.

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
---
v2:
- remove syscon
v3:
- no changes
---
 .../bindings/gpio/amlogic,meson-gpio-interrupt.txt | 30 ++++++++++++++++++++++
 1 file changed, 30 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/gpio/amlogic,meson-gpio-interrupt.txt

diff --git a/Documentation/devicetree/bindings/gpio/amlogic,meson-gpio-interrupt.txt b/Documentation/devicetree/bindings/gpio/amlogic,meson-gpio-interrupt.txt
new file mode 100644
index 00000000..ba7d3015
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/amlogic,meson-gpio-interrupt.txt
@@ -0,0 +1,30 @@
+Amlogic meson GPIO interrupt controller
+
+Meson SoCs contains an interrupt controller which is able watch the SoC pads
+and generate an interrupt on edges or level. The controller is essentially a
+256 pads to 8 GIC interrupt multiplexer, with a filter block to select edge
+or level and polarity. We don't expose all 256 mux inputs because the
+documentation shows that upper part is not mapped to any pad. The actual number
+of interrupt exposed depends on the SoC.
+
+Required properties:
+
+- compatible : should be "amlogic,meson-gpio-interrupt".
+- reg : Specifies base physical address and size of the registers.
+- interrupts : list of GIC interrupts which can be used with the
+	       GPIO IRQ multiplexer
+
+Example:
+
+gpio_irq at 9880 {
+	compatible = "amlogic,meson-gpio-interrupt";
+	reg = <0x0 0x09880 0x0 0x10>;
+	interrupts = <GIC_SPI 64 IRQ_TYPE_NONE>,
+		     <GIC_SPI 65 IRQ_TYPE_NONE>,
+		     <GIC_SPI 66 IRQ_TYPE_NONE>,
+		     <GIC_SPI 67 IRQ_TYPE_NONE>,
+		     <GIC_SPI 68 IRQ_TYPE_NONE>,
+		     <GIC_SPI 69 IRQ_TYPE_NONE>,
+		     <GIC_SPI 70 IRQ_TYPE_NONE>,
+		     <GIC_SPI 71 IRQ_TYPE_NONE>;
+	};
-- 
2.13.0

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

* [PATCH RfC v3 3/7] pinctrl: meson: add DT node for GPIO IRQ on Meson GX
  2017-05-17 20:02 ` Heiner Kallweit
@ 2017-05-17 20:16   ` Heiner Kallweit
  -1 siblings, 0 replies; 22+ messages in thread
From: Heiner Kallweit @ 2017-05-17 20:16 UTC (permalink / raw)
  To: Jerome Brunet, Mark Rutland, Marc Zyngier, Linus Walleij,
	Kevin Hilman, Thomas Gleixner, Rob Herring
  Cc: devicetree, linux-amlogic, linux-gpio, thierry.reding, Thierry Reding

Add the DT node for GPIO IRQ support on AMlogic Meson GX.

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
---
v2:
- remove syscon
v3:
- no changes
---
 arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
index 436b8750..44422b85 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
@@ -312,6 +312,19 @@
 				status = "disabled";
 			};
 
+			gpio_irq@9880 {
+				compatible = "amlogic,meson-gpio-interrupt";
+				reg = <0x0 0x09880 0x0 0x10>;
+				interrupts = <GIC_SPI 64 IRQ_TYPE_NONE>,
+					     <GIC_SPI 65 IRQ_TYPE_NONE>,
+					     <GIC_SPI 66 IRQ_TYPE_NONE>,
+					     <GIC_SPI 67 IRQ_TYPE_NONE>,
+					     <GIC_SPI 68 IRQ_TYPE_NONE>,
+					     <GIC_SPI 69 IRQ_TYPE_NONE>,
+					     <GIC_SPI 70 IRQ_TYPE_NONE>,
+					     <GIC_SPI 71 IRQ_TYPE_NONE>;
+			};
+
 			watchdog@98d0 {
 				compatible = "amlogic,meson-gx-wdt", "amlogic,meson-gxbb-wdt";
 				reg = <0x0 0x098d0 0x0 0x10>;
-- 
2.13.0



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

* [PATCH RfC v3 3/7] pinctrl: meson: add DT node for GPIO IRQ on Meson GX
@ 2017-05-17 20:16   ` Heiner Kallweit
  0 siblings, 0 replies; 22+ messages in thread
From: Heiner Kallweit @ 2017-05-17 20:16 UTC (permalink / raw)
  To: linus-amlogic

Add the DT node for GPIO IRQ support on AMlogic Meson GX.

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
---
v2:
- remove syscon
v3:
- no changes
---
 arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
index 436b8750..44422b85 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
@@ -312,6 +312,19 @@
 				status = "disabled";
 			};
 
+			gpio_irq at 9880 {
+				compatible = "amlogic,meson-gpio-interrupt";
+				reg = <0x0 0x09880 0x0 0x10>;
+				interrupts = <GIC_SPI 64 IRQ_TYPE_NONE>,
+					     <GIC_SPI 65 IRQ_TYPE_NONE>,
+					     <GIC_SPI 66 IRQ_TYPE_NONE>,
+					     <GIC_SPI 67 IRQ_TYPE_NONE>,
+					     <GIC_SPI 68 IRQ_TYPE_NONE>,
+					     <GIC_SPI 69 IRQ_TYPE_NONE>,
+					     <GIC_SPI 70 IRQ_TYPE_NONE>,
+					     <GIC_SPI 71 IRQ_TYPE_NONE>;
+			};
+
 			watchdog at 98d0 {
 				compatible = "amlogic,meson-gx-wdt", "amlogic,meson-gxbb-wdt";
 				reg = <0x0 0x098d0 0x0 0x10>;
-- 
2.13.0

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

* [PATCH RfC v3 4/7] pinctrl: meson: add DT node for GPIO IRQ on Meson 8 / 8b
  2017-05-17 20:02 ` Heiner Kallweit
@ 2017-05-17 20:16   ` Heiner Kallweit
  -1 siblings, 0 replies; 22+ messages in thread
From: Heiner Kallweit @ 2017-05-17 20:16 UTC (permalink / raw)
  To: Jerome Brunet, Mark Rutland, Marc Zyngier, Linus Walleij,
	Kevin Hilman, Thomas Gleixner, Rob Herring
  Cc: devicetree, linux-amlogic, linux-gpio, thierry.reding, Thierry Reding

Add the DT node for GPIO IRQ support on AMlogic Meson 8 and 8b.

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
---
v2:
- remove syscon
v3:
- no changes
---
 arch/arm/boot/dts/meson8.dtsi  | 13 +++++++++++++
 arch/arm/boot/dts/meson8b.dtsi | 13 +++++++++++++
 2 files changed, 26 insertions(+)

diff --git a/arch/arm/boot/dts/meson8.dtsi b/arch/arm/boot/dts/meson8.dtsi
index ebc763ea..1962e16e 100644
--- a/arch/arm/boot/dts/meson8.dtsi
+++ b/arch/arm/boot/dts/meson8.dtsi
@@ -91,6 +91,19 @@
 		clock-frequency = <141666666>;
 	};
 
+	gpio_irq@c1109880 {
+		compatible = "amlogic,meson-gpio-interrupt";
+		reg = <0xc1109880 0x10>;
+		interrupts = <GIC_SPI 64 IRQ_TYPE_NONE>,
+			     <GIC_SPI 65 IRQ_TYPE_NONE>,
+			     <GIC_SPI 66 IRQ_TYPE_NONE>,
+			     <GIC_SPI 67 IRQ_TYPE_NONE>,
+			     <GIC_SPI 68 IRQ_TYPE_NONE>,
+			     <GIC_SPI 69 IRQ_TYPE_NONE>,
+			     <GIC_SPI 70 IRQ_TYPE_NONE>,
+			     <GIC_SPI 71 IRQ_TYPE_NONE>;
+	};
+
 	pinctrl_cbus: pinctrl@c1109880 {
 		compatible = "amlogic,meson8-cbus-pinctrl";
 		reg = <0xc1109880 0x10>;
diff --git a/arch/arm/boot/dts/meson8b.dtsi b/arch/arm/boot/dts/meson8b.dtsi
index 828aa49c..e48017be 100644
--- a/arch/arm/boot/dts/meson8b.dtsi
+++ b/arch/arm/boot/dts/meson8b.dtsi
@@ -183,6 +183,19 @@
 			status = "disabled";
 		};
 
+		gpio_irq@c1109880 {
+			compatible = "amlogic,meson-gpio-interrupt";
+			reg = <0xc1109880 0x10>;
+			interrupts = <GIC_SPI 64 IRQ_TYPE_NONE>,
+				     <GIC_SPI 65 IRQ_TYPE_NONE>,
+				     <GIC_SPI 66 IRQ_TYPE_NONE>,
+				     <GIC_SPI 67 IRQ_TYPE_NONE>,
+				     <GIC_SPI 68 IRQ_TYPE_NONE>,
+				     <GIC_SPI 69 IRQ_TYPE_NONE>,
+				     <GIC_SPI 70 IRQ_TYPE_NONE>,
+				     <GIC_SPI 71 IRQ_TYPE_NONE>;
+		};
+
 		pinctrl_cbus: pinctrl@c1109880 {
 			compatible = "amlogic,meson8b-cbus-pinctrl";
 			reg = <0xc1109880 0x10>;
-- 
2.13.0



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

* [PATCH RfC v3 4/7] pinctrl: meson: add DT node for GPIO IRQ on Meson 8 / 8b
@ 2017-05-17 20:16   ` Heiner Kallweit
  0 siblings, 0 replies; 22+ messages in thread
From: Heiner Kallweit @ 2017-05-17 20:16 UTC (permalink / raw)
  To: linus-amlogic

Add the DT node for GPIO IRQ support on AMlogic Meson 8 and 8b.

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
---
v2:
- remove syscon
v3:
- no changes
---
 arch/arm/boot/dts/meson8.dtsi  | 13 +++++++++++++
 arch/arm/boot/dts/meson8b.dtsi | 13 +++++++++++++
 2 files changed, 26 insertions(+)

diff --git a/arch/arm/boot/dts/meson8.dtsi b/arch/arm/boot/dts/meson8.dtsi
index ebc763ea..1962e16e 100644
--- a/arch/arm/boot/dts/meson8.dtsi
+++ b/arch/arm/boot/dts/meson8.dtsi
@@ -91,6 +91,19 @@
 		clock-frequency = <141666666>;
 	};
 
+	gpio_irq at c1109880 {
+		compatible = "amlogic,meson-gpio-interrupt";
+		reg = <0xc1109880 0x10>;
+		interrupts = <GIC_SPI 64 IRQ_TYPE_NONE>,
+			     <GIC_SPI 65 IRQ_TYPE_NONE>,
+			     <GIC_SPI 66 IRQ_TYPE_NONE>,
+			     <GIC_SPI 67 IRQ_TYPE_NONE>,
+			     <GIC_SPI 68 IRQ_TYPE_NONE>,
+			     <GIC_SPI 69 IRQ_TYPE_NONE>,
+			     <GIC_SPI 70 IRQ_TYPE_NONE>,
+			     <GIC_SPI 71 IRQ_TYPE_NONE>;
+	};
+
 	pinctrl_cbus: pinctrl at c1109880 {
 		compatible = "amlogic,meson8-cbus-pinctrl";
 		reg = <0xc1109880 0x10>;
diff --git a/arch/arm/boot/dts/meson8b.dtsi b/arch/arm/boot/dts/meson8b.dtsi
index 828aa49c..e48017be 100644
--- a/arch/arm/boot/dts/meson8b.dtsi
+++ b/arch/arm/boot/dts/meson8b.dtsi
@@ -183,6 +183,19 @@
 			status = "disabled";
 		};
 
+		gpio_irq at c1109880 {
+			compatible = "amlogic,meson-gpio-interrupt";
+			reg = <0xc1109880 0x10>;
+			interrupts = <GIC_SPI 64 IRQ_TYPE_NONE>,
+				     <GIC_SPI 65 IRQ_TYPE_NONE>,
+				     <GIC_SPI 66 IRQ_TYPE_NONE>,
+				     <GIC_SPI 67 IRQ_TYPE_NONE>,
+				     <GIC_SPI 68 IRQ_TYPE_NONE>,
+				     <GIC_SPI 69 IRQ_TYPE_NONE>,
+				     <GIC_SPI 70 IRQ_TYPE_NONE>,
+				     <GIC_SPI 71 IRQ_TYPE_NONE>;
+		};
+
 		pinctrl_cbus: pinctrl at c1109880 {
 			compatible = "amlogic,meson8b-cbus-pinctrl";
 			reg = <0xc1109880 0x10>;
-- 
2.13.0

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

* [PATCH RfC v3 5/7] pinctrl: meson: improve meson_get_bank and export it
  2017-05-17 20:02 ` Heiner Kallweit
@ 2017-05-17 20:16     ` Heiner Kallweit
  -1 siblings, 0 replies; 22+ messages in thread
From: Heiner Kallweit @ 2017-05-17 20:16 UTC (permalink / raw)
  To: Jerome Brunet, Mark Rutland, Marc Zyngier, Linus Walleij,
	Kevin Hilman, Thomas Gleixner, Rob Herring
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w, Thierry Reding

Export meson_get_bank because it's needed for the GPIO IRQ controller.
To avoid potential name conflicts rename it to meson_pinctrl_get_bank.

In addition simplify it by returning the pointer directly and using
a ERR_PTR in case of an error.

Signed-off-by: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
v2:
- add this patch to the series
v3:
- no changes
---
 drivers/pinctrl/meson/pinctrl-meson.c | 59 +++++++++++++++--------------------
 drivers/pinctrl/meson/pinctrl-meson.h |  3 ++
 2 files changed, 29 insertions(+), 33 deletions(-)

diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c
index 66ed70c1..39ad9861 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.c
+++ b/drivers/pinctrl/meson/pinctrl-meson.c
@@ -63,28 +63,24 @@
 #include "pinctrl-meson.h"
 
 /**
- * meson_get_bank() - find the bank containing a given pin
+ * meson_pinctrl_get_bank() - find the bank containing a given pin
  *
  * @pc:		the pinctrl instance
  * @pin:	the pin number
- * @bank:	the found bank
  *
- * Return:	0 on success, a negative value on error
+ * Return:	the found bank or an ERR_PTR
  */
-static int meson_get_bank(struct meson_pinctrl *pc, unsigned int pin,
-			  struct meson_bank **bank)
+struct meson_bank *meson_pinctrl_get_bank(const struct meson_pinctrl *pc,
+					  unsigned int pin)
 {
+	struct meson_bank *bank = pc->data->banks;
 	int i;
 
-	for (i = 0; i < pc->data->num_banks; i++) {
-		if (pin >= pc->data->banks[i].first &&
-		    pin <= pc->data->banks[i].last) {
-			*bank = &pc->data->banks[i];
-			return 0;
-		}
-	}
+	for (i = 0; i < pc->data->num_banks; i++, bank++)
+		if (pin >= bank->first && pin <= bank->last)
+			return bank;
 
-	return -EINVAL;
+	return ERR_PTR(-EINVAL);
 }
 
 /**
@@ -261,9 +257,9 @@ static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin,
 	unsigned int reg, bit;
 	int i, ret;
 
-	ret = meson_get_bank(pc, pin, &bank);
-	if (ret)
-		return ret;
+	bank = meson_pinctrl_get_bank(pc, pin);
+	if (IS_ERR(bank))
+		return PTR_ERR(bank);
 
 	for (i = 0; i < num_configs; i++) {
 		param = pinconf_to_config_param(configs[i]);
@@ -324,9 +320,9 @@ static int meson_pinconf_get_pull(struct meson_pinctrl *pc, unsigned int pin)
 	unsigned int reg, bit, val;
 	int ret, conf;
 
-	ret = meson_get_bank(pc, pin, &bank);
-	if (ret)
-		return ret;
+	bank = meson_pinctrl_get_bank(pc, pin);
+	if (IS_ERR(bank))
+		return PTR_ERR(bank);
 
 	meson_calc_reg_and_bit(bank, pin, REG_PULLEN, &reg, &bit);
 
@@ -427,12 +423,11 @@ static int meson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
 	struct meson_pinctrl *pc = gpiochip_get_data(chip);
 	unsigned int reg, bit, pin;
 	struct meson_bank *bank;
-	int ret;
 
 	pin = pc->data->pin_base + gpio;
-	ret = meson_get_bank(pc, pin, &bank);
-	if (ret)
-		return ret;
+	bank = meson_pinctrl_get_bank(pc, pin);
+	if (IS_ERR(bank))
+		return PTR_ERR(bank);
 
 	meson_calc_reg_and_bit(bank, pin, REG_DIR, &reg, &bit);
 
@@ -448,9 +443,9 @@ static int meson_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
 	int ret;
 
 	pin = pc->data->pin_base + gpio;
-	ret = meson_get_bank(pc, pin, &bank);
-	if (ret)
-		return ret;
+	bank = meson_pinctrl_get_bank(pc, pin);
+	if (IS_ERR(bank))
+		return PTR_ERR(bank);
 
 	meson_calc_reg_and_bit(bank, pin, REG_DIR, &reg, &bit);
 	ret = regmap_update_bits(pc->reg_gpio, reg, BIT(bit), 0);
@@ -467,11 +462,10 @@ static void meson_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
 	struct meson_pinctrl *pc = gpiochip_get_data(chip);
 	unsigned int reg, bit, pin;
 	struct meson_bank *bank;
-	int ret;
 
 	pin = pc->data->pin_base + gpio;
-	ret = meson_get_bank(pc, pin, &bank);
-	if (ret)
+	bank = meson_pinctrl_get_bank(pc, pin);
+	if (IS_ERR(bank))
 		return;
 
 	meson_calc_reg_and_bit(bank, pin, REG_OUT, &reg, &bit);
@@ -484,12 +478,11 @@ static int meson_gpio_get(struct gpio_chip *chip, unsigned gpio)
 	struct meson_pinctrl *pc = gpiochip_get_data(chip);
 	unsigned int reg, bit, val, pin;
 	struct meson_bank *bank;
-	int ret;
 
 	pin = pc->data->pin_base + gpio;
-	ret = meson_get_bank(pc, pin, &bank);
-	if (ret)
-		return ret;
+	bank = meson_pinctrl_get_bank(pc, pin);
+	if (IS_ERR(bank))
+		return PTR_ERR(bank);
 
 	meson_calc_reg_and_bit(bank, pin, REG_IN, &reg, &bit);
 	regmap_read(pc->reg_gpio, reg, &val);
diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h
index 890f296f..40b56aff 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.h
+++ b/drivers/pinctrl/meson/pinctrl-meson.h
@@ -176,3 +176,6 @@ extern struct meson_pinctrl_data meson_gxbb_periphs_pinctrl_data;
 extern struct meson_pinctrl_data meson_gxbb_aobus_pinctrl_data;
 extern struct meson_pinctrl_data meson_gxl_periphs_pinctrl_data;
 extern struct meson_pinctrl_data meson_gxl_aobus_pinctrl_data;
+
+struct meson_bank *meson_pinctrl_get_bank(const struct meson_pinctrl *pc,
+					  unsigned int pin);
-- 
2.13.0


--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH RfC v3 5/7] pinctrl: meson: improve meson_get_bank and export it
@ 2017-05-17 20:16     ` Heiner Kallweit
  0 siblings, 0 replies; 22+ messages in thread
From: Heiner Kallweit @ 2017-05-17 20:16 UTC (permalink / raw)
  To: linus-amlogic

Export meson_get_bank because it's needed for the GPIO IRQ controller.
To avoid potential name conflicts rename it to meson_pinctrl_get_bank.

In addition simplify it by returning the pointer directly and using
a ERR_PTR in case of an error.

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
---
v2:
- add this patch to the series
v3:
- no changes
---
 drivers/pinctrl/meson/pinctrl-meson.c | 59 +++++++++++++++--------------------
 drivers/pinctrl/meson/pinctrl-meson.h |  3 ++
 2 files changed, 29 insertions(+), 33 deletions(-)

diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c
index 66ed70c1..39ad9861 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.c
+++ b/drivers/pinctrl/meson/pinctrl-meson.c
@@ -63,28 +63,24 @@
 #include "pinctrl-meson.h"
 
 /**
- * meson_get_bank() - find the bank containing a given pin
+ * meson_pinctrl_get_bank() - find the bank containing a given pin
  *
  * @pc:		the pinctrl instance
  * @pin:	the pin number
- * @bank:	the found bank
  *
- * Return:	0 on success, a negative value on error
+ * Return:	the found bank or an ERR_PTR
  */
-static int meson_get_bank(struct meson_pinctrl *pc, unsigned int pin,
-			  struct meson_bank **bank)
+struct meson_bank *meson_pinctrl_get_bank(const struct meson_pinctrl *pc,
+					  unsigned int pin)
 {
+	struct meson_bank *bank = pc->data->banks;
 	int i;
 
-	for (i = 0; i < pc->data->num_banks; i++) {
-		if (pin >= pc->data->banks[i].first &&
-		    pin <= pc->data->banks[i].last) {
-			*bank = &pc->data->banks[i];
-			return 0;
-		}
-	}
+	for (i = 0; i < pc->data->num_banks; i++, bank++)
+		if (pin >= bank->first && pin <= bank->last)
+			return bank;
 
-	return -EINVAL;
+	return ERR_PTR(-EINVAL);
 }
 
 /**
@@ -261,9 +257,9 @@ static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin,
 	unsigned int reg, bit;
 	int i, ret;
 
-	ret = meson_get_bank(pc, pin, &bank);
-	if (ret)
-		return ret;
+	bank = meson_pinctrl_get_bank(pc, pin);
+	if (IS_ERR(bank))
+		return PTR_ERR(bank);
 
 	for (i = 0; i < num_configs; i++) {
 		param = pinconf_to_config_param(configs[i]);
@@ -324,9 +320,9 @@ static int meson_pinconf_get_pull(struct meson_pinctrl *pc, unsigned int pin)
 	unsigned int reg, bit, val;
 	int ret, conf;
 
-	ret = meson_get_bank(pc, pin, &bank);
-	if (ret)
-		return ret;
+	bank = meson_pinctrl_get_bank(pc, pin);
+	if (IS_ERR(bank))
+		return PTR_ERR(bank);
 
 	meson_calc_reg_and_bit(bank, pin, REG_PULLEN, &reg, &bit);
 
@@ -427,12 +423,11 @@ static int meson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
 	struct meson_pinctrl *pc = gpiochip_get_data(chip);
 	unsigned int reg, bit, pin;
 	struct meson_bank *bank;
-	int ret;
 
 	pin = pc->data->pin_base + gpio;
-	ret = meson_get_bank(pc, pin, &bank);
-	if (ret)
-		return ret;
+	bank = meson_pinctrl_get_bank(pc, pin);
+	if (IS_ERR(bank))
+		return PTR_ERR(bank);
 
 	meson_calc_reg_and_bit(bank, pin, REG_DIR, &reg, &bit);
 
@@ -448,9 +443,9 @@ static int meson_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
 	int ret;
 
 	pin = pc->data->pin_base + gpio;
-	ret = meson_get_bank(pc, pin, &bank);
-	if (ret)
-		return ret;
+	bank = meson_pinctrl_get_bank(pc, pin);
+	if (IS_ERR(bank))
+		return PTR_ERR(bank);
 
 	meson_calc_reg_and_bit(bank, pin, REG_DIR, &reg, &bit);
 	ret = regmap_update_bits(pc->reg_gpio, reg, BIT(bit), 0);
@@ -467,11 +462,10 @@ static void meson_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
 	struct meson_pinctrl *pc = gpiochip_get_data(chip);
 	unsigned int reg, bit, pin;
 	struct meson_bank *bank;
-	int ret;
 
 	pin = pc->data->pin_base + gpio;
-	ret = meson_get_bank(pc, pin, &bank);
-	if (ret)
+	bank = meson_pinctrl_get_bank(pc, pin);
+	if (IS_ERR(bank))
 		return;
 
 	meson_calc_reg_and_bit(bank, pin, REG_OUT, &reg, &bit);
@@ -484,12 +478,11 @@ static int meson_gpio_get(struct gpio_chip *chip, unsigned gpio)
 	struct meson_pinctrl *pc = gpiochip_get_data(chip);
 	unsigned int reg, bit, val, pin;
 	struct meson_bank *bank;
-	int ret;
 
 	pin = pc->data->pin_base + gpio;
-	ret = meson_get_bank(pc, pin, &bank);
-	if (ret)
-		return ret;
+	bank = meson_pinctrl_get_bank(pc, pin);
+	if (IS_ERR(bank))
+		return PTR_ERR(bank);
 
 	meson_calc_reg_and_bit(bank, pin, REG_IN, &reg, &bit);
 	regmap_read(pc->reg_gpio, reg, &val);
diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h
index 890f296f..40b56aff 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.h
+++ b/drivers/pinctrl/meson/pinctrl-meson.h
@@ -176,3 +176,6 @@ extern struct meson_pinctrl_data meson_gxbb_periphs_pinctrl_data;
 extern struct meson_pinctrl_data meson_gxbb_aobus_pinctrl_data;
 extern struct meson_pinctrl_data meson_gxl_periphs_pinctrl_data;
 extern struct meson_pinctrl_data meson_gxl_aobus_pinctrl_data;
+
+struct meson_bank *meson_pinctrl_get_bank(const struct meson_pinctrl *pc,
+					  unsigned int pin);
-- 
2.13.0

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

* [PATCH RfC v3 6/7] pinctrl: meson: add support for GPIO interrupts
  2017-05-17 20:02 ` Heiner Kallweit
@ 2017-05-17 20:17   ` Heiner Kallweit
  -1 siblings, 0 replies; 22+ messages in thread
From: Heiner Kallweit @ 2017-05-17 20:17 UTC (permalink / raw)
  To: Jerome Brunet, Mark Rutland, Marc Zyngier, Linus Walleij,
	Kevin Hilman, Thomas Gleixner, Rob Herring
  Cc: devicetree, linux-amlogic, linux-gpio, thierry.reding, Thierry Reding

Add support for GPIO interrupts on Amlogic Meson SoC's.

There's a limit of 8 parent interupts which can be used in total.
Note that IRQ_TYPE_EDGE_BOTH interrupts reserve two parent IRQ's,
one for each edge.

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
---
v2:
- make the GPIO IRQ controller a separate driver
- several smaller improvements
v3:
- replace request_irq based parent irq allocation with chained irq
  handling
- this also fixes a spurious interrupt issue, therefore the related
  workaround code could be removed
- several smaller improvements
---
 drivers/pinctrl/Kconfig                   |   1 +
 drivers/pinctrl/meson/Makefile            |   2 +-
 drivers/pinctrl/meson/pinctrl-meson-irq.c | 320 ++++++++++++++++++++++++++++++
 drivers/pinctrl/meson/pinctrl-meson.c     |   3 +-
 drivers/pinctrl/meson/pinctrl-meson.h     |   1 +
 5 files changed, 325 insertions(+), 2 deletions(-)
 create mode 100644 drivers/pinctrl/meson/pinctrl-meson-irq.c

diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 37af5e30..f8f401a0 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -153,6 +153,7 @@ config PINCTRL_MESON
 	select PINCONF
 	select GENERIC_PINCONF
 	select GPIOLIB
+	select GPIOLIB_IRQCHIP
 	select OF_GPIO
 	select REGMAP_MMIO
 
diff --git a/drivers/pinctrl/meson/Makefile b/drivers/pinctrl/meson/Makefile
index 27c5b512..f711fd0a 100644
--- a/drivers/pinctrl/meson/Makefile
+++ b/drivers/pinctrl/meson/Makefile
@@ -1,3 +1,3 @@
 obj-y	+= pinctrl-meson8.o pinctrl-meson8b.o
 obj-y	+= pinctrl-meson-gxbb.o pinctrl-meson-gxl.o
-obj-y	+= pinctrl-meson.o
+obj-y	+= pinctrl-meson-irq.o pinctrl-meson.o
diff --git a/drivers/pinctrl/meson/pinctrl-meson-irq.c b/drivers/pinctrl/meson/pinctrl-meson-irq.c
new file mode 100644
index 00000000..f32c26e3
--- /dev/null
+++ b/drivers/pinctrl/meson/pinctrl-meson-irq.c
@@ -0,0 +1,320 @@
+/*
+ * Amlogic Meson GPIO IRQ driver
+ *
+ * Copyright 2017 Heiner Kallweit <hkallweit1@gmail.com>
+ * Based on a first version by Jerome Brunet <jbrunet@baylibre.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ */
+
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include "pinctrl-meson.h"
+
+#define REG_EDGE_POL		0x00
+#define REG_PIN_03_SEL		0x04
+#define REG_PIN_47_SEL		0x08
+#define REG_FILTER_SEL		0x0c
+
+#define REG_EDGE_POL_MASK(x)	(BIT(x) | BIT(16 + (x)))
+#define REG_EDGE_POL_EDGE(x)	BIT(x)
+#define REG_EDGE_POL_LOW(x)	BIT(16 + (x))
+
+#define MESON_GPIO_MAX_PARENT_IRQ_NUM	8
+
+struct meson_gpio_irq_slot {
+	int irq;
+	int owner;
+};
+
+static struct regmap *meson_gpio_irq_regmap;
+static struct meson_gpio_irq_slot
+		meson_gpio_irq_slots[MESON_GPIO_MAX_PARENT_IRQ_NUM];
+static int meson_gpio_num_irq_slots;
+static DEFINE_MUTEX(meson_gpio_irq_slot_mutex);
+
+static struct meson_pinctrl *meson_gpio_data_to_pc(struct irq_data *data)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+
+	return gpiochip_get_data(chip);
+}
+
+static int meson_gpio_to_hwirq(struct meson_bank *bank, unsigned int offset)
+{
+	int hwirq;
+
+	if (bank->irq_first < 0)
+		/* this bank cannot generate irqs */
+		return 0;
+
+	hwirq = offset - bank->first + bank->irq_first;
+
+	if (hwirq > bank->irq_last)
+		/* this pin cannot generate irqs */
+		return 0;
+
+	return hwirq;
+}
+
+static int meson_gpio_to_irq(struct meson_pinctrl *pc, unsigned int offset)
+{
+	struct meson_bank *bank;
+	int hwirq;
+
+	offset += pc->data->pin_base;
+
+	bank = meson_pinctrl_get_bank(pc, offset);
+	if (IS_ERR(bank))
+		return PTR_ERR(bank);
+
+	hwirq = meson_gpio_to_hwirq(bank, offset);
+	if (!hwirq)
+		dev_dbg(pc->dev, "no interrupt for pin %u\n", offset);
+
+	return hwirq;
+}
+
+static void meson_gpio_irq_handler(struct irq_desc *desc)
+{
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	struct irq_data *gpio_irq_data = irq_desc_get_handler_data(desc);
+
+	chained_irq_enter(chip, desc);
+
+	if (gpio_irq_data)
+		generic_handle_irq(gpio_irq_data->irq);
+
+	chained_irq_exit(chip, desc);
+}
+
+static int meson_gpio_alloc_irq_slot(struct irq_data *data, int num_slots,
+				     int *slots)
+{
+	int i, cnt = 0;
+
+	mutex_lock(&meson_gpio_irq_slot_mutex);
+
+	for (i = 0; i < meson_gpio_num_irq_slots; i++)
+		if (!meson_gpio_irq_slots[i].owner) {
+			meson_gpio_irq_slots[i].owner = data->irq;
+			slots[cnt++] = i;
+			if (cnt == num_slots)
+				break;
+		}
+
+	if (cnt < num_slots)
+		for (i = 0; i < cnt; i++)
+			meson_gpio_irq_slots[i].owner = 0;
+
+	mutex_unlock(&meson_gpio_irq_slot_mutex);
+
+	return cnt == num_slots ? 0 : -ENOSPC;
+}
+
+static void meson_gpio_free_irq_slot(struct irq_data *data)
+{
+	int i;
+
+	mutex_lock(&meson_gpio_irq_slot_mutex);
+
+	for (i = 0; i < meson_gpio_num_irq_slots; i++)
+		if (meson_gpio_irq_slots[i].owner == data->irq) {
+			irq_set_handler_data(meson_gpio_irq_slots[i].irq,
+					     NULL);
+			meson_gpio_irq_slots[i].owner = 0;
+		}
+
+	mutex_unlock(&meson_gpio_irq_slot_mutex);
+}
+
+static int meson_gpio_find_irq_slot(struct irq_data *data, int *slots)
+{
+	int i, cnt = 0;
+
+	mutex_lock(&meson_gpio_irq_slot_mutex);
+
+	for (i = 0; i < meson_gpio_num_irq_slots; i++)
+		if (meson_gpio_irq_slots[i].owner == data->irq)
+			slots[cnt++] = i;
+
+	mutex_unlock(&meson_gpio_irq_slot_mutex);
+
+	return cnt ?: -EINVAL;
+}
+
+static void meson_gpio_set_hwirq(int idx, int hwirq)
+{
+	int reg = idx > 3 ? REG_PIN_47_SEL : REG_PIN_03_SEL;
+	int shift = 8 * (idx % 4);
+
+	regmap_update_bits(meson_gpio_irq_regmap, reg, 0xff << shift,
+			   hwirq << shift);
+}
+
+static void meson_gpio_irq_set_hwirq(struct irq_data *data, int hwirq)
+{
+	struct meson_pinctrl *pc = meson_gpio_data_to_pc(data);
+	int i, cnt, slots[MESON_GPIO_MAX_PARENT_IRQ_NUM];
+
+	cnt = meson_gpio_find_irq_slot(data, slots);
+	if (cnt < 0) {
+		dev_err(pc->dev, "didn't find gpio irq slot\n");
+		return;
+	}
+
+	for (i = 0; i < cnt; i++)
+		meson_gpio_set_hwirq(slots[i], hwirq);
+}
+
+static void meson_gpio_irq_unmask(struct irq_data *data)
+{
+	struct meson_pinctrl *pc = meson_gpio_data_to_pc(data);
+	unsigned gpio = irqd_to_hwirq(data);
+	int hwirq = meson_gpio_to_irq(pc, gpio);
+
+	meson_gpio_irq_set_hwirq(data, hwirq);
+}
+
+static void meson_gpio_irq_mask(struct irq_data *data)
+{
+	meson_gpio_irq_set_hwirq(data, 0xff);
+}
+
+static void meson_gpio_irq_shutdown(struct irq_data *data)
+{
+	meson_gpio_irq_mask(data);
+	meson_gpio_free_irq_slot(data);
+}
+
+static int meson_gpio_irq_set_type(struct irq_data *data, unsigned int type)
+{
+	int i, ret, irq, num_slots, slots[MESON_GPIO_MAX_PARENT_IRQ_NUM];
+	unsigned int val = 0;
+
+	num_slots = (type == IRQ_TYPE_EDGE_BOTH) ? 2 : 1;
+	ret = meson_gpio_alloc_irq_slot(data, num_slots, slots);
+	if (ret)
+		return ret;
+
+	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+		val |= REG_EDGE_POL_EDGE(slots[0]);
+
+	if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))
+		val |= REG_EDGE_POL_LOW(slots[0]);
+
+	regmap_update_bits(meson_gpio_irq_regmap, REG_EDGE_POL,
+			   REG_EDGE_POL_MASK(slots[0]), val);
+
+	/*
+	 * The chip can create an interrupt for either rising or falling edge
+	 * only. Therefore use two interrupts in case of IRQ_TYPE_EDGE_BOTH,
+	 * first for falling edge and second one for rising edge.
+	 */
+	if (num_slots > 1) {
+		val = REG_EDGE_POL_EDGE(slots[1]);
+		regmap_update_bits(meson_gpio_irq_regmap, REG_EDGE_POL,
+				   REG_EDGE_POL_MASK(slots[1]), val);
+	}
+
+	if (type & IRQ_TYPE_EDGE_BOTH)
+		val = IRQ_TYPE_EDGE_RISING;
+	else
+		val = IRQ_TYPE_LEVEL_HIGH;
+
+	for (i = 0; i < num_slots; i++) {
+		irq = meson_gpio_irq_slots[slots[i]].irq;
+		irq_set_irq_type(irq, val);
+		irq_set_handler_data(irq, data);
+	}
+
+	if (ret)
+		while (--i >= 0)
+			irq_set_handler_data(meson_gpio_irq_slots[slots[i]].irq,
+					     NULL);
+	return ret;
+}
+
+struct irq_chip meson_gpio_irq_chip = {
+	.name = "GPIO",
+	.irq_set_type = meson_gpio_irq_set_type,
+	.irq_mask = meson_gpio_irq_mask,
+	.irq_unmask = meson_gpio_irq_unmask,
+	.irq_shutdown = meson_gpio_irq_shutdown,
+};
+
+static int meson_gpio_get_irqs(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int irq, i;
+
+	for (i = 0; i < MESON_GPIO_MAX_PARENT_IRQ_NUM; i++) {
+		irq = irq_of_parse_and_map(np, i);
+		if (!irq)
+			break;
+		meson_gpio_irq_slots[i].irq = irq;
+		irq_set_chained_handler_and_data(irq, meson_gpio_irq_handler,
+						 NULL);
+	}
+
+	meson_gpio_num_irq_slots = i;
+
+	return i ? 0 : -EINVAL;
+}
+
+static const struct regmap_config meson_gpio_regmap_config = {
+	.reg_bits       = 32,
+	.reg_stride     = 4,
+	.val_bits       = 32,
+	.max_register	= REG_FILTER_SEL,
+};
+
+static int meson_gpio_irq_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	void __iomem *io_base;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	io_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(io_base))
+		return PTR_ERR(io_base);
+
+	meson_gpio_irq_regmap = devm_regmap_init_mmio(&pdev->dev, io_base,
+						&meson_gpio_regmap_config);
+	if (IS_ERR(meson_gpio_irq_regmap))
+		return PTR_ERR(meson_gpio_irq_regmap);
+
+	/* initialize to IRQ_TYPE_LEVEL_HIGH */
+	regmap_write(meson_gpio_irq_regmap, REG_EDGE_POL, 0);
+	/* disable all GPIO interrupt sources */
+	regmap_write(meson_gpio_irq_regmap, REG_PIN_03_SEL, 0xffffffff);
+	regmap_write(meson_gpio_irq_regmap, REG_PIN_47_SEL, 0xffffffff);
+	/* disable filtering */
+	regmap_write(meson_gpio_irq_regmap, REG_FILTER_SEL, 0);
+
+	return meson_gpio_get_irqs(pdev);
+}
+
+static const struct of_device_id meson_gpio_irq_dt_match[] = {
+	{ .compatible = "amlogic,meson-gpio-interrupt" },
+	{ },
+};
+
+static struct platform_driver meson_gpio_irq_driver = {
+	.probe		= meson_gpio_irq_probe,
+	.driver = {
+		.name	= "meson-gpio-interrupt",
+		.of_match_table = meson_gpio_irq_dt_match,
+	},
+};
+builtin_platform_driver(meson_gpio_irq_driver);
diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c
index 39ad9861..48aa1427 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.c
+++ b/drivers/pinctrl/meson/pinctrl-meson.c
@@ -551,7 +551,8 @@ static int meson_gpiolib_register(struct meson_pinctrl *pc)
 		return ret;
 	}
 
-	return 0;
+	return gpiochip_irqchip_add(&pc->chip, &meson_gpio_irq_chip, 0,
+				    handle_simple_irq, IRQ_TYPE_NONE);
 }
 
 static struct regmap_config meson_regmap_config = {
diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h
index 40b56aff..4aa78f3e 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.h
+++ b/drivers/pinctrl/meson/pinctrl-meson.h
@@ -176,6 +176,7 @@ extern struct meson_pinctrl_data meson_gxbb_periphs_pinctrl_data;
 extern struct meson_pinctrl_data meson_gxbb_aobus_pinctrl_data;
 extern struct meson_pinctrl_data meson_gxl_periphs_pinctrl_data;
 extern struct meson_pinctrl_data meson_gxl_aobus_pinctrl_data;
+extern struct irq_chip meson_gpio_irq_chip;
 
 struct meson_bank *meson_pinctrl_get_bank(const struct meson_pinctrl *pc,
 					  unsigned int pin);
-- 
2.13.0



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

* [PATCH RfC v3 6/7] pinctrl: meson: add support for GPIO interrupts
@ 2017-05-17 20:17   ` Heiner Kallweit
  0 siblings, 0 replies; 22+ messages in thread
From: Heiner Kallweit @ 2017-05-17 20:17 UTC (permalink / raw)
  To: linus-amlogic

Add support for GPIO interrupts on Amlogic Meson SoC's.

There's a limit of 8 parent interupts which can be used in total.
Note that IRQ_TYPE_EDGE_BOTH interrupts reserve two parent IRQ's,
one for each edge.

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
---
v2:
- make the GPIO IRQ controller a separate driver
- several smaller improvements
v3:
- replace request_irq based parent irq allocation with chained irq
  handling
- this also fixes a spurious interrupt issue, therefore the related
  workaround code could be removed
- several smaller improvements
---
 drivers/pinctrl/Kconfig                   |   1 +
 drivers/pinctrl/meson/Makefile            |   2 +-
 drivers/pinctrl/meson/pinctrl-meson-irq.c | 320 ++++++++++++++++++++++++++++++
 drivers/pinctrl/meson/pinctrl-meson.c     |   3 +-
 drivers/pinctrl/meson/pinctrl-meson.h     |   1 +
 5 files changed, 325 insertions(+), 2 deletions(-)
 create mode 100644 drivers/pinctrl/meson/pinctrl-meson-irq.c

diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 37af5e30..f8f401a0 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -153,6 +153,7 @@ config PINCTRL_MESON
 	select PINCONF
 	select GENERIC_PINCONF
 	select GPIOLIB
+	select GPIOLIB_IRQCHIP
 	select OF_GPIO
 	select REGMAP_MMIO
 
diff --git a/drivers/pinctrl/meson/Makefile b/drivers/pinctrl/meson/Makefile
index 27c5b512..f711fd0a 100644
--- a/drivers/pinctrl/meson/Makefile
+++ b/drivers/pinctrl/meson/Makefile
@@ -1,3 +1,3 @@
 obj-y	+= pinctrl-meson8.o pinctrl-meson8b.o
 obj-y	+= pinctrl-meson-gxbb.o pinctrl-meson-gxl.o
-obj-y	+= pinctrl-meson.o
+obj-y	+= pinctrl-meson-irq.o pinctrl-meson.o
diff --git a/drivers/pinctrl/meson/pinctrl-meson-irq.c b/drivers/pinctrl/meson/pinctrl-meson-irq.c
new file mode 100644
index 00000000..f32c26e3
--- /dev/null
+++ b/drivers/pinctrl/meson/pinctrl-meson-irq.c
@@ -0,0 +1,320 @@
+/*
+ * Amlogic Meson GPIO IRQ driver
+ *
+ * Copyright 2017 Heiner Kallweit <hkallweit1@gmail.com>
+ * Based on a first version by Jerome Brunet <jbrunet@baylibre.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ */
+
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include "pinctrl-meson.h"
+
+#define REG_EDGE_POL		0x00
+#define REG_PIN_03_SEL		0x04
+#define REG_PIN_47_SEL		0x08
+#define REG_FILTER_SEL		0x0c
+
+#define REG_EDGE_POL_MASK(x)	(BIT(x) | BIT(16 + (x)))
+#define REG_EDGE_POL_EDGE(x)	BIT(x)
+#define REG_EDGE_POL_LOW(x)	BIT(16 + (x))
+
+#define MESON_GPIO_MAX_PARENT_IRQ_NUM	8
+
+struct meson_gpio_irq_slot {
+	int irq;
+	int owner;
+};
+
+static struct regmap *meson_gpio_irq_regmap;
+static struct meson_gpio_irq_slot
+		meson_gpio_irq_slots[MESON_GPIO_MAX_PARENT_IRQ_NUM];
+static int meson_gpio_num_irq_slots;
+static DEFINE_MUTEX(meson_gpio_irq_slot_mutex);
+
+static struct meson_pinctrl *meson_gpio_data_to_pc(struct irq_data *data)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+
+	return gpiochip_get_data(chip);
+}
+
+static int meson_gpio_to_hwirq(struct meson_bank *bank, unsigned int offset)
+{
+	int hwirq;
+
+	if (bank->irq_first < 0)
+		/* this bank cannot generate irqs */
+		return 0;
+
+	hwirq = offset - bank->first + bank->irq_first;
+
+	if (hwirq > bank->irq_last)
+		/* this pin cannot generate irqs */
+		return 0;
+
+	return hwirq;
+}
+
+static int meson_gpio_to_irq(struct meson_pinctrl *pc, unsigned int offset)
+{
+	struct meson_bank *bank;
+	int hwirq;
+
+	offset += pc->data->pin_base;
+
+	bank = meson_pinctrl_get_bank(pc, offset);
+	if (IS_ERR(bank))
+		return PTR_ERR(bank);
+
+	hwirq = meson_gpio_to_hwirq(bank, offset);
+	if (!hwirq)
+		dev_dbg(pc->dev, "no interrupt for pin %u\n", offset);
+
+	return hwirq;
+}
+
+static void meson_gpio_irq_handler(struct irq_desc *desc)
+{
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	struct irq_data *gpio_irq_data = irq_desc_get_handler_data(desc);
+
+	chained_irq_enter(chip, desc);
+
+	if (gpio_irq_data)
+		generic_handle_irq(gpio_irq_data->irq);
+
+	chained_irq_exit(chip, desc);
+}
+
+static int meson_gpio_alloc_irq_slot(struct irq_data *data, int num_slots,
+				     int *slots)
+{
+	int i, cnt = 0;
+
+	mutex_lock(&meson_gpio_irq_slot_mutex);
+
+	for (i = 0; i < meson_gpio_num_irq_slots; i++)
+		if (!meson_gpio_irq_slots[i].owner) {
+			meson_gpio_irq_slots[i].owner = data->irq;
+			slots[cnt++] = i;
+			if (cnt == num_slots)
+				break;
+		}
+
+	if (cnt < num_slots)
+		for (i = 0; i < cnt; i++)
+			meson_gpio_irq_slots[i].owner = 0;
+
+	mutex_unlock(&meson_gpio_irq_slot_mutex);
+
+	return cnt == num_slots ? 0 : -ENOSPC;
+}
+
+static void meson_gpio_free_irq_slot(struct irq_data *data)
+{
+	int i;
+
+	mutex_lock(&meson_gpio_irq_slot_mutex);
+
+	for (i = 0; i < meson_gpio_num_irq_slots; i++)
+		if (meson_gpio_irq_slots[i].owner == data->irq) {
+			irq_set_handler_data(meson_gpio_irq_slots[i].irq,
+					     NULL);
+			meson_gpio_irq_slots[i].owner = 0;
+		}
+
+	mutex_unlock(&meson_gpio_irq_slot_mutex);
+}
+
+static int meson_gpio_find_irq_slot(struct irq_data *data, int *slots)
+{
+	int i, cnt = 0;
+
+	mutex_lock(&meson_gpio_irq_slot_mutex);
+
+	for (i = 0; i < meson_gpio_num_irq_slots; i++)
+		if (meson_gpio_irq_slots[i].owner == data->irq)
+			slots[cnt++] = i;
+
+	mutex_unlock(&meson_gpio_irq_slot_mutex);
+
+	return cnt ?: -EINVAL;
+}
+
+static void meson_gpio_set_hwirq(int idx, int hwirq)
+{
+	int reg = idx > 3 ? REG_PIN_47_SEL : REG_PIN_03_SEL;
+	int shift = 8 * (idx % 4);
+
+	regmap_update_bits(meson_gpio_irq_regmap, reg, 0xff << shift,
+			   hwirq << shift);
+}
+
+static void meson_gpio_irq_set_hwirq(struct irq_data *data, int hwirq)
+{
+	struct meson_pinctrl *pc = meson_gpio_data_to_pc(data);
+	int i, cnt, slots[MESON_GPIO_MAX_PARENT_IRQ_NUM];
+
+	cnt = meson_gpio_find_irq_slot(data, slots);
+	if (cnt < 0) {
+		dev_err(pc->dev, "didn't find gpio irq slot\n");
+		return;
+	}
+
+	for (i = 0; i < cnt; i++)
+		meson_gpio_set_hwirq(slots[i], hwirq);
+}
+
+static void meson_gpio_irq_unmask(struct irq_data *data)
+{
+	struct meson_pinctrl *pc = meson_gpio_data_to_pc(data);
+	unsigned gpio = irqd_to_hwirq(data);
+	int hwirq = meson_gpio_to_irq(pc, gpio);
+
+	meson_gpio_irq_set_hwirq(data, hwirq);
+}
+
+static void meson_gpio_irq_mask(struct irq_data *data)
+{
+	meson_gpio_irq_set_hwirq(data, 0xff);
+}
+
+static void meson_gpio_irq_shutdown(struct irq_data *data)
+{
+	meson_gpio_irq_mask(data);
+	meson_gpio_free_irq_slot(data);
+}
+
+static int meson_gpio_irq_set_type(struct irq_data *data, unsigned int type)
+{
+	int i, ret, irq, num_slots, slots[MESON_GPIO_MAX_PARENT_IRQ_NUM];
+	unsigned int val = 0;
+
+	num_slots = (type == IRQ_TYPE_EDGE_BOTH) ? 2 : 1;
+	ret = meson_gpio_alloc_irq_slot(data, num_slots, slots);
+	if (ret)
+		return ret;
+
+	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+		val |= REG_EDGE_POL_EDGE(slots[0]);
+
+	if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))
+		val |= REG_EDGE_POL_LOW(slots[0]);
+
+	regmap_update_bits(meson_gpio_irq_regmap, REG_EDGE_POL,
+			   REG_EDGE_POL_MASK(slots[0]), val);
+
+	/*
+	 * The chip can create an interrupt for either rising or falling edge
+	 * only. Therefore use two interrupts in case of IRQ_TYPE_EDGE_BOTH,
+	 * first for falling edge and second one for rising edge.
+	 */
+	if (num_slots > 1) {
+		val = REG_EDGE_POL_EDGE(slots[1]);
+		regmap_update_bits(meson_gpio_irq_regmap, REG_EDGE_POL,
+				   REG_EDGE_POL_MASK(slots[1]), val);
+	}
+
+	if (type & IRQ_TYPE_EDGE_BOTH)
+		val = IRQ_TYPE_EDGE_RISING;
+	else
+		val = IRQ_TYPE_LEVEL_HIGH;
+
+	for (i = 0; i < num_slots; i++) {
+		irq = meson_gpio_irq_slots[slots[i]].irq;
+		irq_set_irq_type(irq, val);
+		irq_set_handler_data(irq, data);
+	}
+
+	if (ret)
+		while (--i >= 0)
+			irq_set_handler_data(meson_gpio_irq_slots[slots[i]].irq,
+					     NULL);
+	return ret;
+}
+
+struct irq_chip meson_gpio_irq_chip = {
+	.name = "GPIO",
+	.irq_set_type = meson_gpio_irq_set_type,
+	.irq_mask = meson_gpio_irq_mask,
+	.irq_unmask = meson_gpio_irq_unmask,
+	.irq_shutdown = meson_gpio_irq_shutdown,
+};
+
+static int meson_gpio_get_irqs(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int irq, i;
+
+	for (i = 0; i < MESON_GPIO_MAX_PARENT_IRQ_NUM; i++) {
+		irq = irq_of_parse_and_map(np, i);
+		if (!irq)
+			break;
+		meson_gpio_irq_slots[i].irq = irq;
+		irq_set_chained_handler_and_data(irq, meson_gpio_irq_handler,
+						 NULL);
+	}
+
+	meson_gpio_num_irq_slots = i;
+
+	return i ? 0 : -EINVAL;
+}
+
+static const struct regmap_config meson_gpio_regmap_config = {
+	.reg_bits       = 32,
+	.reg_stride     = 4,
+	.val_bits       = 32,
+	.max_register	= REG_FILTER_SEL,
+};
+
+static int meson_gpio_irq_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	void __iomem *io_base;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	io_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(io_base))
+		return PTR_ERR(io_base);
+
+	meson_gpio_irq_regmap = devm_regmap_init_mmio(&pdev->dev, io_base,
+						&meson_gpio_regmap_config);
+	if (IS_ERR(meson_gpio_irq_regmap))
+		return PTR_ERR(meson_gpio_irq_regmap);
+
+	/* initialize to IRQ_TYPE_LEVEL_HIGH */
+	regmap_write(meson_gpio_irq_regmap, REG_EDGE_POL, 0);
+	/* disable all GPIO interrupt sources */
+	regmap_write(meson_gpio_irq_regmap, REG_PIN_03_SEL, 0xffffffff);
+	regmap_write(meson_gpio_irq_regmap, REG_PIN_47_SEL, 0xffffffff);
+	/* disable filtering */
+	regmap_write(meson_gpio_irq_regmap, REG_FILTER_SEL, 0);
+
+	return meson_gpio_get_irqs(pdev);
+}
+
+static const struct of_device_id meson_gpio_irq_dt_match[] = {
+	{ .compatible = "amlogic,meson-gpio-interrupt" },
+	{ },
+};
+
+static struct platform_driver meson_gpio_irq_driver = {
+	.probe		= meson_gpio_irq_probe,
+	.driver = {
+		.name	= "meson-gpio-interrupt",
+		.of_match_table = meson_gpio_irq_dt_match,
+	},
+};
+builtin_platform_driver(meson_gpio_irq_driver);
diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c
index 39ad9861..48aa1427 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.c
+++ b/drivers/pinctrl/meson/pinctrl-meson.c
@@ -551,7 +551,8 @@ static int meson_gpiolib_register(struct meson_pinctrl *pc)
 		return ret;
 	}
 
-	return 0;
+	return gpiochip_irqchip_add(&pc->chip, &meson_gpio_irq_chip, 0,
+				    handle_simple_irq, IRQ_TYPE_NONE);
 }
 
 static struct regmap_config meson_regmap_config = {
diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h
index 40b56aff..4aa78f3e 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.h
+++ b/drivers/pinctrl/meson/pinctrl-meson.h
@@ -176,6 +176,7 @@ extern struct meson_pinctrl_data meson_gxbb_periphs_pinctrl_data;
 extern struct meson_pinctrl_data meson_gxbb_aobus_pinctrl_data;
 extern struct meson_pinctrl_data meson_gxl_periphs_pinctrl_data;
 extern struct meson_pinctrl_data meson_gxl_aobus_pinctrl_data;
+extern struct irq_chip meson_gpio_irq_chip;
 
 struct meson_bank *meson_pinctrl_get_bank(const struct meson_pinctrl *pc,
 					  unsigned int pin);
-- 
2.13.0

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

* [PATCH RfC v3 7/7] pinctrl: meson: add interrupt controller to GPIO DT nodes
  2017-05-17 20:02 ` Heiner Kallweit
@ 2017-05-17 20:17     ` Heiner Kallweit
  -1 siblings, 0 replies; 22+ messages in thread
From: Heiner Kallweit @ 2017-05-17 20:17 UTC (permalink / raw)
  To: Jerome Brunet, Mark Rutland, Marc Zyngier, Linus Walleij,
	Kevin Hilman, Thomas Gleixner, Rob Herring
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w, Thierry Reding

Add interrupt controller properties to the gpio controller nodes and
extend the gpio controller DT binding documentation.

Signed-off-by: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
v3:
- added to the patch series
---
 Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt | 4 ++++
 arch/arm/boot/dts/meson8.dtsi                               | 2 ++
 arch/arm/boot/dts/meson8b.dtsi                              | 2 ++
 arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi                 | 4 ++++
 arch/arm64/boot/dts/amlogic/meson-gxl.dtsi                  | 4 ++++
 5 files changed, 16 insertions(+)

diff --git a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt
index 2392557e..49a8118a 100644
--- a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt
@@ -24,6 +24,8 @@ Required properties for sub-nodes are:
    when it is missing the "pull" registers are used instead
  - gpio-controller: identifies the node as a gpio controller
  - #gpio-cells: must be 2
+ - interrupt-controller: identifies the node as interrupt controller
+ - #interrupt-cells: must be 2
 
 === Other sub-nodes ===
 
@@ -62,6 +64,8 @@ pinctrl-bindings.txt
 			reg-names = "mux", "pull", "pull-enable", "gpio";
 			gpio-controller;
 			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
                };
 
 		nand {
diff --git a/arch/arm/boot/dts/meson8.dtsi b/arch/arm/boot/dts/meson8.dtsi
index 1962e16e..4fe73050 100644
--- a/arch/arm/boot/dts/meson8.dtsi
+++ b/arch/arm/boot/dts/meson8.dtsi
@@ -119,6 +119,8 @@
 			reg-names = "mux", "pull", "pull-enable", "gpio";
 			gpio-controller;
 			#gpio-cells = <2>;
+			interrupt-controller;
+			#interupt-cells = <2>;
 			gpio-ranges = <&pinctrl_cbus 0 0 120>;
 		};
 
diff --git a/arch/arm/boot/dts/meson8b.dtsi b/arch/arm/boot/dts/meson8b.dtsi
index e48017be..16391a30 100644
--- a/arch/arm/boot/dts/meson8b.dtsi
+++ b/arch/arm/boot/dts/meson8b.dtsi
@@ -211,6 +211,8 @@
 				reg-names = "mux", "pull", "pull-enable", "gpio";
 				gpio-controller;
 				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
 				gpio-ranges = <&pinctrl_cbus 0 0 130>;
 			};
 		};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
index 07e405cf..e9177041 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
@@ -118,6 +118,8 @@
 			reg-names = "mux", "pull", "gpio";
 			gpio-controller;
 			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
 			gpio-ranges = <&pinctrl_aobus 0 0 14>;
 		};
 
@@ -267,6 +269,8 @@
 			reg-names = "mux", "pull", "pull-enable", "gpio";
 			gpio-controller;
 			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
 			gpio-ranges = <&pinctrl_periphs 0 14 120>;
 		};
 
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
index d8e096df..344a5243 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
@@ -80,6 +80,8 @@
 			reg-names = "mux", "pull", "gpio";
 			gpio-controller;
 			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
 			gpio-ranges = <&pinctrl_aobus 0 0 14>;
 		};
 
@@ -208,6 +210,8 @@
 			reg-names = "mux", "pull", "pull-enable", "gpio";
 			gpio-controller;
 			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
 			gpio-ranges = <&pinctrl_periphs 0 14 101>;
 		};
 
-- 
2.13.0


--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH RfC v3 7/7] pinctrl: meson: add interrupt controller to GPIO DT nodes
@ 2017-05-17 20:17     ` Heiner Kallweit
  0 siblings, 0 replies; 22+ messages in thread
From: Heiner Kallweit @ 2017-05-17 20:17 UTC (permalink / raw)
  To: linus-amlogic

Add interrupt controller properties to the gpio controller nodes and
extend the gpio controller DT binding documentation.

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
---
v3:
- added to the patch series
---
 Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt | 4 ++++
 arch/arm/boot/dts/meson8.dtsi                               | 2 ++
 arch/arm/boot/dts/meson8b.dtsi                              | 2 ++
 arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi                 | 4 ++++
 arch/arm64/boot/dts/amlogic/meson-gxl.dtsi                  | 4 ++++
 5 files changed, 16 insertions(+)

diff --git a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt
index 2392557e..49a8118a 100644
--- a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt
@@ -24,6 +24,8 @@ Required properties for sub-nodes are:
    when it is missing the "pull" registers are used instead
  - gpio-controller: identifies the node as a gpio controller
  - #gpio-cells: must be 2
+ - interrupt-controller: identifies the node as interrupt controller
+ - #interrupt-cells: must be 2
 
 === Other sub-nodes ===
 
@@ -62,6 +64,8 @@ pinctrl-bindings.txt
 			reg-names = "mux", "pull", "pull-enable", "gpio";
 			gpio-controller;
 			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
                };
 
 		nand {
diff --git a/arch/arm/boot/dts/meson8.dtsi b/arch/arm/boot/dts/meson8.dtsi
index 1962e16e..4fe73050 100644
--- a/arch/arm/boot/dts/meson8.dtsi
+++ b/arch/arm/boot/dts/meson8.dtsi
@@ -119,6 +119,8 @@
 			reg-names = "mux", "pull", "pull-enable", "gpio";
 			gpio-controller;
 			#gpio-cells = <2>;
+			interrupt-controller;
+			#interupt-cells = <2>;
 			gpio-ranges = <&pinctrl_cbus 0 0 120>;
 		};
 
diff --git a/arch/arm/boot/dts/meson8b.dtsi b/arch/arm/boot/dts/meson8b.dtsi
index e48017be..16391a30 100644
--- a/arch/arm/boot/dts/meson8b.dtsi
+++ b/arch/arm/boot/dts/meson8b.dtsi
@@ -211,6 +211,8 @@
 				reg-names = "mux", "pull", "pull-enable", "gpio";
 				gpio-controller;
 				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
 				gpio-ranges = <&pinctrl_cbus 0 0 130>;
 			};
 		};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
index 07e405cf..e9177041 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
@@ -118,6 +118,8 @@
 			reg-names = "mux", "pull", "gpio";
 			gpio-controller;
 			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
 			gpio-ranges = <&pinctrl_aobus 0 0 14>;
 		};
 
@@ -267,6 +269,8 @@
 			reg-names = "mux", "pull", "pull-enable", "gpio";
 			gpio-controller;
 			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
 			gpio-ranges = <&pinctrl_periphs 0 14 120>;
 		};
 
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
index d8e096df..344a5243 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
@@ -80,6 +80,8 @@
 			reg-names = "mux", "pull", "gpio";
 			gpio-controller;
 			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
 			gpio-ranges = <&pinctrl_aobus 0 0 14>;
 		};
 
@@ -208,6 +210,8 @@
 			reg-names = "mux", "pull", "pull-enable", "gpio";
 			gpio-controller;
 			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
 			gpio-ranges = <&pinctrl_periphs 0 14 101>;
 		};
 
-- 
2.13.0

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

* Re: [PATCH RfC v3 2/7] pinctrl: meson: document GPIO IRQ driver DT binding
  2017-05-17 20:16     ` Heiner Kallweit
@ 2017-05-23  0:56       ` Rob Herring
  -1 siblings, 0 replies; 22+ messages in thread
From: Rob Herring @ 2017-05-23  0:56 UTC (permalink / raw)
  To: Heiner Kallweit
  Cc: Jerome Brunet, Mark Rutland, Marc Zyngier, Linus Walleij,
	Kevin Hilman, Thomas Gleixner, devicetree, linux-amlogic,
	linux-gpio, thierry.reding, Thierry Reding

On Wed, May 17, 2017 at 10:16:35PM +0200, Heiner Kallweit wrote:
> Document the DT binding for GPIO IRQ support on Amlogic Meson SoC's.
> 
> This documentation is intentionally not placed under
> interrupt-controllers as GPIO IRQ support on these SoC's acts more
> like an interrupt multiplexer.

I've not seen anything in the discussion that indicates this is a better 
fit as gpio. Seems to me multiple people including me have said this 
sounds like an interrupt controller.

> 
> Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
> ---
> v2:
> - remove syscon
> v3:
> - no changes
> ---
>  .../bindings/gpio/amlogic,meson-gpio-interrupt.txt | 30 ++++++++++++++++++++++
>  1 file changed, 30 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/gpio/amlogic,meson-gpio-interrupt.txt

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

* [PATCH RfC v3 2/7] pinctrl: meson: document GPIO IRQ driver DT binding
@ 2017-05-23  0:56       ` Rob Herring
  0 siblings, 0 replies; 22+ messages in thread
From: Rob Herring @ 2017-05-23  0:56 UTC (permalink / raw)
  To: linus-amlogic

On Wed, May 17, 2017 at 10:16:35PM +0200, Heiner Kallweit wrote:
> Document the DT binding for GPIO IRQ support on Amlogic Meson SoC's.
> 
> This documentation is intentionally not placed under
> interrupt-controllers as GPIO IRQ support on these SoC's acts more
> like an interrupt multiplexer.

I've not seen anything in the discussion that indicates this is a better 
fit as gpio. Seems to me multiple people including me have said this 
sounds like an interrupt controller.

> 
> Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
> ---
> v2:
> - remove syscon
> v3:
> - no changes
> ---
>  .../bindings/gpio/amlogic,meson-gpio-interrupt.txt | 30 ++++++++++++++++++++++
>  1 file changed, 30 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/gpio/amlogic,meson-gpio-interrupt.txt

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

* Re: [PATCH RfC v3 6/7] pinctrl: meson: add support for GPIO interrupts
  2017-05-17 20:17   ` Heiner Kallweit
@ 2017-05-23  9:01     ` Jerome Brunet
  -1 siblings, 0 replies; 22+ messages in thread
From: Jerome Brunet @ 2017-05-23  9:01 UTC (permalink / raw)
  To: Heiner Kallweit, Mark Rutland, Marc Zyngier, Linus Walleij,
	Kevin Hilman, Thomas Gleixner, Rob Herring
  Cc: devicetree, linux-amlogic, linux-gpio, thierry.reding, Thierry Reding

On Wed, 2017-05-17 at 22:17 +0200, Heiner Kallweit wrote:
> Add support for GPIO interrupts on Amlogic Meson SoC's.
> 
> There's a limit of 8 parent interupts which can be used in total.
> Note that IRQ_TYPE_EDGE_BOTH interrupts reserve two parent IRQ's,
> one for each edge.

Heiner,

Several people (Neil, Rob and I) have pointed out that device should be an
interrupt controller. Going a bit further, it should be and *independent*
interrupt controller

Meson SoC, like gxbb and gxl, have 2 independent gpio controllers, with there
own register space and which can work on their own.

It is the same for the gpio-irq device, it is an independent device, with its
own register space. It can work even if the gpio device is not driven. The gpio-
irq device should not depend on the gpio controller.

The driver should reflect that, and IMO it should be:
- an independent driver inside driver/irqchip, working even if the gpio device
is not probed
- it should not use gpio stuff (like meson_get_bank). If gpio related
translation should be done to get the irq line number from the gpio number, it
should be done by the gpio driver.
- First, We should be able to request irq directly from this device (eg. through
DT). Then gpio controller could re-export this and make it available (through
gpio_to_irq and DT)

                          -------------------> IRQ consumer 1
                          |
-------     ------------  |    -----------
| GIC | --> | GPIO-IRQ | ----> | AO GPIO | --> IRQ consumer 2
-------     ------------  |    -----------
                          |
                          |    -----------
                          ---> | EE GPIO | --> IRQ consumer 3
                               -----------

Jerome
                 
> 
> Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
> ---
> v2:
> - make the GPIO IRQ controller a separate driver
> - several smaller improvements
> v3:
> - replace request_irq based parent irq allocation with chained irq
>   handling
> - this also fixes a spurious interrupt issue, therefore the related
>   workaround code could be removed
> - several smaller improvements
> ---
>  drivers/pinctrl/Kconfig                   |   1 +
>  drivers/pinctrl/meson/Makefile            |   2 +-
>  drivers/pinctrl/meson/pinctrl-meson-irq.c | 320
> ++++++++++++++++++++++++++++++
>  drivers/pinctrl/meson/pinctrl-meson.c     |   3 +-
>  drivers/pinctrl/meson/pinctrl-meson.h     |   1 +
>  5 files changed, 325 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/pinctrl/meson/pinctrl-meson-irq.c
> 
> diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
> index 37af5e30..f8f401a0 100644
> --- a/drivers/pinctrl/Kconfig
> +++ b/drivers/pinctrl/Kconfig
> @@ -153,6 +153,7 @@ config PINCTRL_MESON
>  	select PINCONF
>  	select GENERIC_PINCONF
>  	select GPIOLIB
> +	select GPIOLIB_IRQCHIP
>  	select OF_GPIO
>  	select REGMAP_MMIO
>  
> diff --git a/drivers/pinctrl/meson/Makefile b/drivers/pinctrl/meson/Makefile
> index 27c5b512..f711fd0a 100644
> --- a/drivers/pinctrl/meson/Makefile
> +++ b/drivers/pinctrl/meson/Makefile
> @@ -1,3 +1,3 @@
>  obj-y	+= pinctrl-meson8.o pinctrl-meson8b.o
>  obj-y	+= pinctrl-meson-gxbb.o pinctrl-meson-gxl.o
> -obj-y	+= pinctrl-meson.o
> +obj-y	+= pinctrl-meson-irq.o pinctrl-meson.o
> diff --git a/drivers/pinctrl/meson/pinctrl-meson-irq.c
> b/drivers/pinctrl/meson/pinctrl-meson-irq.c
> new file mode 100644
> index 00000000..f32c26e3
> --- /dev/null
> +++ b/drivers/pinctrl/meson/pinctrl-meson-irq.c
> @@ -0,0 +1,320 @@
> +/*
> + * Amlogic Meson GPIO IRQ driver
> + *
> + * Copyright 2017 Heiner Kallweit <hkallweit1@gmail.com>
> + * Based on a first version by Jerome Brunet <jbrunet@baylibre.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation, version 2.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/gpio.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/interrupt.h>
> +#include <linux/of.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include "pinctrl-meson.h"
> +
> +#define REG_EDGE_POL		0x00
> +#define REG_PIN_03_SEL		0x04
> +#define REG_PIN_47_SEL		0x08
> +#define REG_FILTER_SEL		0x0c
> +
> +#define REG_EDGE_POL_MASK(x)	(BIT(x) | BIT(16 + (x)))
> +#define REG_EDGE_POL_EDGE(x)	BIT(x)
> +#define REG_EDGE_POL_LOW(x)	BIT(16 + (x))
> +
> +#define MESON_GPIO_MAX_PARENT_IRQ_NUM	8
> +
> +struct meson_gpio_irq_slot {
> +	int irq;
> +	int owner;
> +};
> +
> +static struct regmap *meson_gpio_irq_regmap;
> +static struct meson_gpio_irq_slot
> +		meson_gpio_irq_slots[MESON_GPIO_MAX_PARENT_IRQ_NUM];
> +static int meson_gpio_num_irq_slots;
> +static DEFINE_MUTEX(meson_gpio_irq_slot_mutex);
> +
> +static struct meson_pinctrl *meson_gpio_data_to_pc(struct irq_data *data)
> +{
> +	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
> +
> +	return gpiochip_get_data(chip);
> +}
> +
> +static int meson_gpio_to_hwirq(struct meson_bank *bank, unsigned int offset)
> +{
> +	int hwirq;
> +
> +	if (bank->irq_first < 0)
> +		/* this bank cannot generate irqs */
> +		return 0;
> +
> +	hwirq = offset - bank->first + bank->irq_first;
> +
> +	if (hwirq > bank->irq_last)
> +		/* this pin cannot generate irqs */
> +		return 0;
> +
> +	return hwirq;
> +}
> +
> +static int meson_gpio_to_irq(struct meson_pinctrl *pc, unsigned int offset)
> +{
> +	struct meson_bank *bank;
> +	int hwirq;
> +
> +	offset += pc->data->pin_base;
> +
> +	bank = meson_pinctrl_get_bank(pc, offset);
> +	if (IS_ERR(bank))
> +		return PTR_ERR(bank);
> +
> +	hwirq = meson_gpio_to_hwirq(bank, offset);
> +	if (!hwirq)
> +		dev_dbg(pc->dev, "no interrupt for pin %u\n", offset);
> +
> +	return hwirq;
> +}
> +
> +static void meson_gpio_irq_handler(struct irq_desc *desc)
> +{
> +	struct irq_chip *chip = irq_desc_get_chip(desc);
> +	struct irq_data *gpio_irq_data = irq_desc_get_handler_data(desc);
> +
> +	chained_irq_enter(chip, desc);
> +
> +	if (gpio_irq_data)
> +		generic_handle_irq(gpio_irq_data->irq);
> +
> +	chained_irq_exit(chip, desc);
> +}
> +
> +static int meson_gpio_alloc_irq_slot(struct irq_data *data, int num_slots,
> +				     int *slots)
> +{
> +	int i, cnt = 0;
> +
> +	mutex_lock(&meson_gpio_irq_slot_mutex);
> +
> +	for (i = 0; i < meson_gpio_num_irq_slots; i++)
> +		if (!meson_gpio_irq_slots[i].owner) {
> +			meson_gpio_irq_slots[i].owner = data->irq;
> +			slots[cnt++] = i;
> +			if (cnt == num_slots)
> +				break;
> +		}
> +
> +	if (cnt < num_slots)
> +		for (i = 0; i < cnt; i++)
> +			meson_gpio_irq_slots[i].owner = 0;
> +
> +	mutex_unlock(&meson_gpio_irq_slot_mutex);
> +
> +	return cnt == num_slots ? 0 : -ENOSPC;
> +}
> +
> +static void meson_gpio_free_irq_slot(struct irq_data *data)
> +{
> +	int i;
> +
> +	mutex_lock(&meson_gpio_irq_slot_mutex);
> +
> +	for (i = 0; i < meson_gpio_num_irq_slots; i++)
> +		if (meson_gpio_irq_slots[i].owner == data->irq) {
> +			irq_set_handler_data(meson_gpio_irq_slots[i].irq,
> +					     NULL);
> +			meson_gpio_irq_slots[i].owner = 0;
> +		}
> +
> +	mutex_unlock(&meson_gpio_irq_slot_mutex);
> +}
> +
> +static int meson_gpio_find_irq_slot(struct irq_data *data, int *slots)
> +{
> +	int i, cnt = 0;
> +
> +	mutex_lock(&meson_gpio_irq_slot_mutex);
> +
> +	for (i = 0; i < meson_gpio_num_irq_slots; i++)
> +		if (meson_gpio_irq_slots[i].owner == data->irq)
> +			slots[cnt++] = i;
> +
> +	mutex_unlock(&meson_gpio_irq_slot_mutex);
> +
> +	return cnt ?: -EINVAL;
> +}
> +
> +static void meson_gpio_set_hwirq(int idx, int hwirq)
> +{
> +	int reg = idx > 3 ? REG_PIN_47_SEL : REG_PIN_03_SEL;
> +	int shift = 8 * (idx % 4);
> +
> +	regmap_update_bits(meson_gpio_irq_regmap, reg, 0xff << shift,
> +			   hwirq << shift);
> +}
> +
> +static void meson_gpio_irq_set_hwirq(struct irq_data *data, int hwirq)
> +{
> +	struct meson_pinctrl *pc = meson_gpio_data_to_pc(data);
> +	int i, cnt, slots[MESON_GPIO_MAX_PARENT_IRQ_NUM];
> +
> +	cnt = meson_gpio_find_irq_slot(data, slots);
> +	if (cnt < 0) {
> +		dev_err(pc->dev, "didn't find gpio irq slot\n");
> +		return;
> +	}
> +
> +	for (i = 0; i < cnt; i++)
> +		meson_gpio_set_hwirq(slots[i], hwirq);
> +}
> +
> +static void meson_gpio_irq_unmask(struct irq_data *data)
> +{
> +	struct meson_pinctrl *pc = meson_gpio_data_to_pc(data);
> +	unsigned gpio = irqd_to_hwirq(data);
> +	int hwirq = meson_gpio_to_irq(pc, gpio);
> +
> +	meson_gpio_irq_set_hwirq(data, hwirq);
> +}
> +
> +static void meson_gpio_irq_mask(struct irq_data *data)
> +{
> +	meson_gpio_irq_set_hwirq(data, 0xff);
> +}
> +
> +static void meson_gpio_irq_shutdown(struct irq_data *data)
> +{
> +	meson_gpio_irq_mask(data);
> +	meson_gpio_free_irq_slot(data);
> +}
> +
> +static int meson_gpio_irq_set_type(struct irq_data *data, unsigned int type)
> +{
> +	int i, ret, irq, num_slots, slots[MESON_GPIO_MAX_PARENT_IRQ_NUM];
> +	unsigned int val = 0;
> +
> +	num_slots = (type == IRQ_TYPE_EDGE_BOTH) ? 2 : 1;
> +	ret = meson_gpio_alloc_irq_slot(data, num_slots, slots);
> +	if (ret)
> +		return ret;
> +
> +	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
> +		val |= REG_EDGE_POL_EDGE(slots[0]);
> +
> +	if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))
> +		val |= REG_EDGE_POL_LOW(slots[0]);
> +
> +	regmap_update_bits(meson_gpio_irq_regmap, REG_EDGE_POL,
> +			   REG_EDGE_POL_MASK(slots[0]), val);
> +
> +	/*
> +	 * The chip can create an interrupt for either rising or falling edge
> +	 * only. Therefore use two interrupts in case of IRQ_TYPE_EDGE_BOTH,
> +	 * first for falling edge and second one for rising edge.
> +	 */
> +	if (num_slots > 1) {
> +		val = REG_EDGE_POL_EDGE(slots[1]);
> +		regmap_update_bits(meson_gpio_irq_regmap, REG_EDGE_POL,
> +				   REG_EDGE_POL_MASK(slots[1]), val);
> +	}
> +
> +	if (type & IRQ_TYPE_EDGE_BOTH)
> +		val = IRQ_TYPE_EDGE_RISING;
> +	else
> +		val = IRQ_TYPE_LEVEL_HIGH;
> +
> +	for (i = 0; i < num_slots; i++) {
> +		irq = meson_gpio_irq_slots[slots[i]].irq;
> +		irq_set_irq_type(irq, val);
> +		irq_set_handler_data(irq, data);
> +	}
> +
> +	if (ret)
> +		while (--i >= 0)
> +			irq_set_handler_data(meson_gpio_irq_slots[slots[i]].i
> rq,
> +					     NULL);
> +	return ret;
> +}
> +
> +struct irq_chip meson_gpio_irq_chip = {
> +	.name = "GPIO",
> +	.irq_set_type = meson_gpio_irq_set_type,
> +	.irq_mask = meson_gpio_irq_mask,
> +	.irq_unmask = meson_gpio_irq_unmask,
> +	.irq_shutdown = meson_gpio_irq_shutdown,
> +};
> +
> +static int meson_gpio_get_irqs(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	int irq, i;
> +
> +	for (i = 0; i < MESON_GPIO_MAX_PARENT_IRQ_NUM; i++) {
> +		irq = irq_of_parse_and_map(np, i);
> +		if (!irq)
> +			break;
> +		meson_gpio_irq_slots[i].irq = irq;
> +		irq_set_chained_handler_and_data(irq, meson_gpio_irq_handler,
> +						 NULL);
> +	}
> +
> +	meson_gpio_num_irq_slots = i;
> +
> +	return i ? 0 : -EINVAL;
> +}
> +
> +static const struct regmap_config meson_gpio_regmap_config = {
> +	.reg_bits       = 32,
> +	.reg_stride     = 4,
> +	.val_bits       = 32,
> +	.max_register	= REG_FILTER_SEL,
> +};
> +
> +static int meson_gpio_irq_probe(struct platform_device *pdev)
> +{
> +	struct resource *res;
> +	void __iomem *io_base;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	io_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(io_base))
> +		return PTR_ERR(io_base);
> +
> +	meson_gpio_irq_regmap = devm_regmap_init_mmio(&pdev->dev, io_base,
> +						&meson_gpio_regmap_config);
> +	if (IS_ERR(meson_gpio_irq_regmap))
> +		return PTR_ERR(meson_gpio_irq_regmap);
> +
> +	/* initialize to IRQ_TYPE_LEVEL_HIGH */
> +	regmap_write(meson_gpio_irq_regmap, REG_EDGE_POL, 0);
> +	/* disable all GPIO interrupt sources */
> +	regmap_write(meson_gpio_irq_regmap, REG_PIN_03_SEL, 0xffffffff);
> +	regmap_write(meson_gpio_irq_regmap, REG_PIN_47_SEL, 0xffffffff);
> +	/* disable filtering */
> +	regmap_write(meson_gpio_irq_regmap, REG_FILTER_SEL, 0);
> +
> +	return meson_gpio_get_irqs(pdev);
> +}
> +
> +static const struct of_device_id meson_gpio_irq_dt_match[] = {
> +	{ .compatible = "amlogic,meson-gpio-interrupt" },
> +	{ },
> +};
> +
> +static struct platform_driver meson_gpio_irq_driver = {
> +	.probe		= meson_gpio_irq_probe,
> +	.driver = {
> +		.name	= "meson-gpio-interrupt",
> +		.of_match_table = meson_gpio_irq_dt_match,
> +	},
> +};
> +builtin_platform_driver(meson_gpio_irq_driver);
> diff --git a/drivers/pinctrl/meson/pinctrl-meson.c
> b/drivers/pinctrl/meson/pinctrl-meson.c
> index 39ad9861..48aa1427 100644
> --- a/drivers/pinctrl/meson/pinctrl-meson.c
> +++ b/drivers/pinctrl/meson/pinctrl-meson.c
> @@ -551,7 +551,8 @@ static int meson_gpiolib_register(struct meson_pinctrl
> *pc)
>  		return ret;
>  	}
>  
> -	return 0;
> +	return gpiochip_irqchip_add(&pc->chip, &meson_gpio_irq_chip, 0,
> +				    handle_simple_irq, IRQ_TYPE_NONE);
>  }
>  
>  static struct regmap_config meson_regmap_config = {
> diff --git a/drivers/pinctrl/meson/pinctrl-meson.h
> b/drivers/pinctrl/meson/pinctrl-meson.h
> index 40b56aff..4aa78f3e 100644
> --- a/drivers/pinctrl/meson/pinctrl-meson.h
> +++ b/drivers/pinctrl/meson/pinctrl-meson.h
> @@ -176,6 +176,7 @@ extern struct meson_pinctrl_data
> meson_gxbb_periphs_pinctrl_data;
>  extern struct meson_pinctrl_data meson_gxbb_aobus_pinctrl_data;
>  extern struct meson_pinctrl_data meson_gxl_periphs_pinctrl_data;
>  extern struct meson_pinctrl_data meson_gxl_aobus_pinctrl_data;
> +extern struct irq_chip meson_gpio_irq_chip;
>  
>  struct meson_bank *meson_pinctrl_get_bank(const struct meson_pinctrl *pc,
>  					  unsigned int pin);


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

* [PATCH RfC v3 6/7] pinctrl: meson: add support for GPIO interrupts
@ 2017-05-23  9:01     ` Jerome Brunet
  0 siblings, 0 replies; 22+ messages in thread
From: Jerome Brunet @ 2017-05-23  9:01 UTC (permalink / raw)
  To: linus-amlogic

On Wed, 2017-05-17 at 22:17 +0200, Heiner Kallweit wrote:
> Add support for GPIO interrupts on Amlogic Meson SoC's.
> 
> There's a limit of 8 parent interupts which can be used in total.
> Note that IRQ_TYPE_EDGE_BOTH interrupts reserve two parent IRQ's,
> one for each edge.

Heiner,

Several people (Neil, Rob and I) have pointed out that device should be an
interrupt controller. Going a bit further, it should be and *independent*
interrupt controller

Meson SoC, like gxbb and gxl, have 2 independent gpio controllers, with there
own register space and which can work on their own.

It is the same for the gpio-irq device, it is an independent device, with its
own register space. It can work even if the gpio device is not driven. The gpio-
irq device should not depend on the gpio controller.

The driver should reflect that, and IMO it should be:
- an independent driver inside driver/irqchip, working even if the gpio device
is not probed
- it should not use gpio stuff (like meson_get_bank). If gpio related
translation should be done to get the irq line number from the gpio number, it
should be done by the gpio driver.
- First, We should be able to request irq directly from this device (eg. through
DT). Then gpio controller could re-export this and make it available (through
gpio_to_irq and DT)

                          -------------------> IRQ consumer 1
                          |
-------     ------------  |    -----------
| GIC | --> | GPIO-IRQ | ----> | AO GPIO | --> IRQ consumer 2
-------     ------------  |    -----------
                          |
                          |    -----------
                          ---> | EE GPIO | --> IRQ consumer 3
                               -----------

Jerome
                 
> 
> Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
> ---
> v2:
> - make the GPIO IRQ controller a separate driver
> - several smaller improvements
> v3:
> - replace request_irq based parent irq allocation with chained irq
> ? handling
> - this also fixes a spurious interrupt issue, therefore the related
> ? workaround code could be removed
> - several smaller improvements
> ---
> ?drivers/pinctrl/Kconfig???????????????????|???1 +
> ?drivers/pinctrl/meson/Makefile????????????|???2 +-
> ?drivers/pinctrl/meson/pinctrl-meson-irq.c | 320
> ++++++++++++++++++++++++++++++
> ?drivers/pinctrl/meson/pinctrl-meson.c?????|???3 +-
> ?drivers/pinctrl/meson/pinctrl-meson.h?????|???1 +
> ?5 files changed, 325 insertions(+), 2 deletions(-)
> ?create mode 100644 drivers/pinctrl/meson/pinctrl-meson-irq.c
> 
> diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
> index 37af5e30..f8f401a0 100644
> --- a/drivers/pinctrl/Kconfig
> +++ b/drivers/pinctrl/Kconfig
> @@ -153,6 +153,7 @@ config PINCTRL_MESON
> ?	select PINCONF
> ?	select GENERIC_PINCONF
> ?	select GPIOLIB
> +	select GPIOLIB_IRQCHIP
> ?	select OF_GPIO
> ?	select REGMAP_MMIO
> ?
> diff --git a/drivers/pinctrl/meson/Makefile b/drivers/pinctrl/meson/Makefile
> index 27c5b512..f711fd0a 100644
> --- a/drivers/pinctrl/meson/Makefile
> +++ b/drivers/pinctrl/meson/Makefile
> @@ -1,3 +1,3 @@
> ?obj-y	+= pinctrl-meson8.o pinctrl-meson8b.o
> ?obj-y	+= pinctrl-meson-gxbb.o pinctrl-meson-gxl.o
> -obj-y	+= pinctrl-meson.o
> +obj-y	+= pinctrl-meson-irq.o pinctrl-meson.o
> diff --git a/drivers/pinctrl/meson/pinctrl-meson-irq.c
> b/drivers/pinctrl/meson/pinctrl-meson-irq.c
> new file mode 100644
> index 00000000..f32c26e3
> --- /dev/null
> +++ b/drivers/pinctrl/meson/pinctrl-meson-irq.c
> @@ -0,0 +1,320 @@
> +/*
> + * Amlogic Meson GPIO IRQ driver
> + *
> + * Copyright 2017 Heiner Kallweit <hkallweit1@gmail.com>
> + * Based on a first version by Jerome Brunet <jbrunet@baylibre.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation, version 2.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/gpio.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/interrupt.h>
> +#include <linux/of.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include "pinctrl-meson.h"
> +
> +#define REG_EDGE_POL		0x00
> +#define REG_PIN_03_SEL		0x04
> +#define REG_PIN_47_SEL		0x08
> +#define REG_FILTER_SEL		0x0c
> +
> +#define REG_EDGE_POL_MASK(x)	(BIT(x) | BIT(16 + (x)))
> +#define REG_EDGE_POL_EDGE(x)	BIT(x)
> +#define REG_EDGE_POL_LOW(x)	BIT(16 + (x))
> +
> +#define MESON_GPIO_MAX_PARENT_IRQ_NUM	8
> +
> +struct meson_gpio_irq_slot {
> +	int irq;
> +	int owner;
> +};
> +
> +static struct regmap *meson_gpio_irq_regmap;
> +static struct meson_gpio_irq_slot
> +		meson_gpio_irq_slots[MESON_GPIO_MAX_PARENT_IRQ_NUM];
> +static int meson_gpio_num_irq_slots;
> +static DEFINE_MUTEX(meson_gpio_irq_slot_mutex);
> +
> +static struct meson_pinctrl *meson_gpio_data_to_pc(struct irq_data *data)
> +{
> +	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
> +
> +	return gpiochip_get_data(chip);
> +}
> +
> +static int meson_gpio_to_hwirq(struct meson_bank *bank, unsigned int offset)
> +{
> +	int hwirq;
> +
> +	if (bank->irq_first < 0)
> +		/* this bank cannot generate irqs */
> +		return 0;
> +
> +	hwirq = offset - bank->first + bank->irq_first;
> +
> +	if (hwirq > bank->irq_last)
> +		/* this pin cannot generate irqs */
> +		return 0;
> +
> +	return hwirq;
> +}
> +
> +static int meson_gpio_to_irq(struct meson_pinctrl *pc, unsigned int offset)
> +{
> +	struct meson_bank *bank;
> +	int hwirq;
> +
> +	offset += pc->data->pin_base;
> +
> +	bank = meson_pinctrl_get_bank(pc, offset);
> +	if (IS_ERR(bank))
> +		return PTR_ERR(bank);
> +
> +	hwirq = meson_gpio_to_hwirq(bank, offset);
> +	if (!hwirq)
> +		dev_dbg(pc->dev, "no interrupt for pin %u\n", offset);
> +
> +	return hwirq;
> +}
> +
> +static void meson_gpio_irq_handler(struct irq_desc *desc)
> +{
> +	struct irq_chip *chip = irq_desc_get_chip(desc);
> +	struct irq_data *gpio_irq_data = irq_desc_get_handler_data(desc);
> +
> +	chained_irq_enter(chip, desc);
> +
> +	if (gpio_irq_data)
> +		generic_handle_irq(gpio_irq_data->irq);
> +
> +	chained_irq_exit(chip, desc);
> +}
> +
> +static int meson_gpio_alloc_irq_slot(struct irq_data *data, int num_slots,
> +				?????int *slots)
> +{
> +	int i, cnt = 0;
> +
> +	mutex_lock(&meson_gpio_irq_slot_mutex);
> +
> +	for (i = 0; i < meson_gpio_num_irq_slots; i++)
> +		if (!meson_gpio_irq_slots[i].owner) {
> +			meson_gpio_irq_slots[i].owner = data->irq;
> +			slots[cnt++] = i;
> +			if (cnt == num_slots)
> +				break;
> +		}
> +
> +	if (cnt < num_slots)
> +		for (i = 0; i < cnt; i++)
> +			meson_gpio_irq_slots[i].owner = 0;
> +
> +	mutex_unlock(&meson_gpio_irq_slot_mutex);
> +
> +	return cnt == num_slots ? 0 : -ENOSPC;
> +}
> +
> +static void meson_gpio_free_irq_slot(struct irq_data *data)
> +{
> +	int i;
> +
> +	mutex_lock(&meson_gpio_irq_slot_mutex);
> +
> +	for (i = 0; i < meson_gpio_num_irq_slots; i++)
> +		if (meson_gpio_irq_slots[i].owner == data->irq) {
> +			irq_set_handler_data(meson_gpio_irq_slots[i].irq,
> +					?????NULL);
> +			meson_gpio_irq_slots[i].owner = 0;
> +		}
> +
> +	mutex_unlock(&meson_gpio_irq_slot_mutex);
> +}
> +
> +static int meson_gpio_find_irq_slot(struct irq_data *data, int *slots)
> +{
> +	int i, cnt = 0;
> +
> +	mutex_lock(&meson_gpio_irq_slot_mutex);
> +
> +	for (i = 0; i < meson_gpio_num_irq_slots; i++)
> +		if (meson_gpio_irq_slots[i].owner == data->irq)
> +			slots[cnt++] = i;
> +
> +	mutex_unlock(&meson_gpio_irq_slot_mutex);
> +
> +	return cnt ?: -EINVAL;
> +}
> +
> +static void meson_gpio_set_hwirq(int idx, int hwirq)
> +{
> +	int reg = idx > 3 ? REG_PIN_47_SEL : REG_PIN_03_SEL;
> +	int shift = 8 * (idx % 4);
> +
> +	regmap_update_bits(meson_gpio_irq_regmap, reg, 0xff << shift,
> +			???hwirq << shift);
> +}
> +
> +static void meson_gpio_irq_set_hwirq(struct irq_data *data, int hwirq)
> +{
> +	struct meson_pinctrl *pc = meson_gpio_data_to_pc(data);
> +	int i, cnt, slots[MESON_GPIO_MAX_PARENT_IRQ_NUM];
> +
> +	cnt = meson_gpio_find_irq_slot(data, slots);
> +	if (cnt < 0) {
> +		dev_err(pc->dev, "didn't find gpio irq slot\n");
> +		return;
> +	}
> +
> +	for (i = 0; i < cnt; i++)
> +		meson_gpio_set_hwirq(slots[i], hwirq);
> +}
> +
> +static void meson_gpio_irq_unmask(struct irq_data *data)
> +{
> +	struct meson_pinctrl *pc = meson_gpio_data_to_pc(data);
> +	unsigned gpio = irqd_to_hwirq(data);
> +	int hwirq = meson_gpio_to_irq(pc, gpio);
> +
> +	meson_gpio_irq_set_hwirq(data, hwirq);
> +}
> +
> +static void meson_gpio_irq_mask(struct irq_data *data)
> +{
> +	meson_gpio_irq_set_hwirq(data, 0xff);
> +}
> +
> +static void meson_gpio_irq_shutdown(struct irq_data *data)
> +{
> +	meson_gpio_irq_mask(data);
> +	meson_gpio_free_irq_slot(data);
> +}
> +
> +static int meson_gpio_irq_set_type(struct irq_data *data, unsigned int type)
> +{
> +	int i, ret, irq, num_slots, slots[MESON_GPIO_MAX_PARENT_IRQ_NUM];
> +	unsigned int val = 0;
> +
> +	num_slots = (type == IRQ_TYPE_EDGE_BOTH) ? 2 : 1;
> +	ret = meson_gpio_alloc_irq_slot(data, num_slots, slots);
> +	if (ret)
> +		return ret;
> +
> +	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
> +		val |= REG_EDGE_POL_EDGE(slots[0]);
> +
> +	if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))
> +		val |= REG_EDGE_POL_LOW(slots[0]);
> +
> +	regmap_update_bits(meson_gpio_irq_regmap, REG_EDGE_POL,
> +			???REG_EDGE_POL_MASK(slots[0]), val);
> +
> +	/*
> +	?* The chip can create an interrupt for either rising or falling edge
> +	?* only. Therefore use two interrupts in case of IRQ_TYPE_EDGE_BOTH,
> +	?* first for falling edge and second one for rising edge.
> +	?*/
> +	if (num_slots > 1) {
> +		val = REG_EDGE_POL_EDGE(slots[1]);
> +		regmap_update_bits(meson_gpio_irq_regmap, REG_EDGE_POL,
> +				???REG_EDGE_POL_MASK(slots[1]), val);
> +	}
> +
> +	if (type & IRQ_TYPE_EDGE_BOTH)
> +		val = IRQ_TYPE_EDGE_RISING;
> +	else
> +		val = IRQ_TYPE_LEVEL_HIGH;
> +
> +	for (i = 0; i < num_slots; i++) {
> +		irq = meson_gpio_irq_slots[slots[i]].irq;
> +		irq_set_irq_type(irq, val);
> +		irq_set_handler_data(irq, data);
> +	}
> +
> +	if (ret)
> +		while (--i >= 0)
> +			irq_set_handler_data(meson_gpio_irq_slots[slots[i]].i
> rq,
> +					?????NULL);
> +	return ret;
> +}
> +
> +struct irq_chip meson_gpio_irq_chip = {
> +	.name = "GPIO",
> +	.irq_set_type = meson_gpio_irq_set_type,
> +	.irq_mask = meson_gpio_irq_mask,
> +	.irq_unmask = meson_gpio_irq_unmask,
> +	.irq_shutdown = meson_gpio_irq_shutdown,
> +};
> +
> +static int meson_gpio_get_irqs(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	int irq, i;
> +
> +	for (i = 0; i < MESON_GPIO_MAX_PARENT_IRQ_NUM; i++) {
> +		irq = irq_of_parse_and_map(np, i);
> +		if (!irq)
> +			break;
> +		meson_gpio_irq_slots[i].irq = irq;
> +		irq_set_chained_handler_and_data(irq, meson_gpio_irq_handler,
> +						?NULL);
> +	}
> +
> +	meson_gpio_num_irq_slots = i;
> +
> +	return i ? 0 : -EINVAL;
> +}
> +
> +static const struct regmap_config meson_gpio_regmap_config = {
> +	.reg_bits???????= 32,
> +	.reg_stride?????= 4,
> +	.val_bits???????= 32,
> +	.max_register	= REG_FILTER_SEL,
> +};
> +
> +static int meson_gpio_irq_probe(struct platform_device *pdev)
> +{
> +	struct resource *res;
> +	void __iomem *io_base;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	io_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(io_base))
> +		return PTR_ERR(io_base);
> +
> +	meson_gpio_irq_regmap = devm_regmap_init_mmio(&pdev->dev, io_base,
> +						&meson_gpio_regmap_config);
> +	if (IS_ERR(meson_gpio_irq_regmap))
> +		return PTR_ERR(meson_gpio_irq_regmap);
> +
> +	/* initialize to IRQ_TYPE_LEVEL_HIGH */
> +	regmap_write(meson_gpio_irq_regmap, REG_EDGE_POL, 0);
> +	/* disable all GPIO interrupt sources */
> +	regmap_write(meson_gpio_irq_regmap, REG_PIN_03_SEL, 0xffffffff);
> +	regmap_write(meson_gpio_irq_regmap, REG_PIN_47_SEL, 0xffffffff);
> +	/* disable filtering */
> +	regmap_write(meson_gpio_irq_regmap, REG_FILTER_SEL, 0);
> +
> +	return meson_gpio_get_irqs(pdev);
> +}
> +
> +static const struct of_device_id meson_gpio_irq_dt_match[] = {
> +	{ .compatible = "amlogic,meson-gpio-interrupt" },
> +	{ },
> +};
> +
> +static struct platform_driver meson_gpio_irq_driver = {
> +	.probe		= meson_gpio_irq_probe,
> +	.driver = {
> +		.name	= "meson-gpio-interrupt",
> +		.of_match_table = meson_gpio_irq_dt_match,
> +	},
> +};
> +builtin_platform_driver(meson_gpio_irq_driver);
> diff --git a/drivers/pinctrl/meson/pinctrl-meson.c
> b/drivers/pinctrl/meson/pinctrl-meson.c
> index 39ad9861..48aa1427 100644
> --- a/drivers/pinctrl/meson/pinctrl-meson.c
> +++ b/drivers/pinctrl/meson/pinctrl-meson.c
> @@ -551,7 +551,8 @@ static int meson_gpiolib_register(struct meson_pinctrl
> *pc)
> ?		return ret;
> ?	}
> ?
> -	return 0;
> +	return gpiochip_irqchip_add(&pc->chip, &meson_gpio_irq_chip, 0,
> +				????handle_simple_irq, IRQ_TYPE_NONE);
> ?}
> ?
> ?static struct regmap_config meson_regmap_config = {
> diff --git a/drivers/pinctrl/meson/pinctrl-meson.h
> b/drivers/pinctrl/meson/pinctrl-meson.h
> index 40b56aff..4aa78f3e 100644
> --- a/drivers/pinctrl/meson/pinctrl-meson.h
> +++ b/drivers/pinctrl/meson/pinctrl-meson.h
> @@ -176,6 +176,7 @@ extern struct meson_pinctrl_data
> meson_gxbb_periphs_pinctrl_data;
> ?extern struct meson_pinctrl_data meson_gxbb_aobus_pinctrl_data;
> ?extern struct meson_pinctrl_data meson_gxl_periphs_pinctrl_data;
> ?extern struct meson_pinctrl_data meson_gxl_aobus_pinctrl_data;
> +extern struct irq_chip meson_gpio_irq_chip;
> ?
> ?struct meson_bank *meson_pinctrl_get_bank(const struct meson_pinctrl *pc,
> ?					??unsigned int pin);

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

* Re: [PATCH RfC v3 7/7] pinctrl: meson: add interrupt controller to GPIO DT nodes
  2017-05-17 20:17     ` Heiner Kallweit
@ 2017-05-30 21:44       ` Rob Herring
  -1 siblings, 0 replies; 22+ messages in thread
From: Rob Herring @ 2017-05-30 21:44 UTC (permalink / raw)
  To: Heiner Kallweit
  Cc: Jerome Brunet, Mark Rutland, Marc Zyngier, Linus Walleij,
	Kevin Hilman, Thomas Gleixner, devicetree, linux-amlogic,
	linux-gpio, thierry.reding, Thierry Reding

On Wed, May 17, 2017 at 10:17:10PM +0200, Heiner Kallweit wrote:
> Add interrupt controller properties to the gpio controller nodes and
> extend the gpio controller DT binding documentation.
> 
> Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
> ---
> v3:
> - added to the patch series
> ---
>  Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt | 4 ++++
>  arch/arm/boot/dts/meson8.dtsi                               | 2 ++
>  arch/arm/boot/dts/meson8b.dtsi                              | 2 ++
>  arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi                 | 4 ++++
>  arch/arm64/boot/dts/amlogic/meson-gxl.dtsi                  | 4 ++++
>  5 files changed, 16 insertions(+)

Bindings and dts changes should be separate patches. With that,

Acked-by: Rob Herring <robh@kernel.org>

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

* [PATCH RfC v3 7/7] pinctrl: meson: add interrupt controller to GPIO DT nodes
@ 2017-05-30 21:44       ` Rob Herring
  0 siblings, 0 replies; 22+ messages in thread
From: Rob Herring @ 2017-05-30 21:44 UTC (permalink / raw)
  To: linus-amlogic

On Wed, May 17, 2017 at 10:17:10PM +0200, Heiner Kallweit wrote:
> Add interrupt controller properties to the gpio controller nodes and
> extend the gpio controller DT binding documentation.
> 
> Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
> ---
> v3:
> - added to the patch series
> ---
>  Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt | 4 ++++
>  arch/arm/boot/dts/meson8.dtsi                               | 2 ++
>  arch/arm/boot/dts/meson8b.dtsi                              | 2 ++
>  arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi                 | 4 ++++
>  arch/arm64/boot/dts/amlogic/meson-gxl.dtsi                  | 4 ++++
>  5 files changed, 16 insertions(+)

Bindings and dts changes should be separate patches. With that,

Acked-by: Rob Herring <robh@kernel.org>

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

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

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-17 20:02 [PATCH RfC v3 0/7] pintrl: meson: add support for GPIO IRQs Heiner Kallweit
2017-05-17 20:02 ` Heiner Kallweit
2017-05-17 20:16 ` [PATCH RfC v3 1/7] pinctrl: meson: add interrupts to pinctrl data Heiner Kallweit
2017-05-17 20:16   ` Heiner Kallweit
2017-05-17 20:16 ` [PATCH RfC v3 3/7] pinctrl: meson: add DT node for GPIO IRQ on Meson GX Heiner Kallweit
2017-05-17 20:16   ` Heiner Kallweit
2017-05-17 20:16 ` [PATCH RfC v3 4/7] pinctrl: meson: add DT node for GPIO IRQ on Meson 8 / 8b Heiner Kallweit
2017-05-17 20:16   ` Heiner Kallweit
2017-05-17 20:17 ` [PATCH RfC v3 6/7] pinctrl: meson: add support for GPIO interrupts Heiner Kallweit
2017-05-17 20:17   ` Heiner Kallweit
2017-05-23  9:01   ` Jerome Brunet
2017-05-23  9:01     ` Jerome Brunet
     [not found] ` <16950080-b19d-e25c-fb48-bc79cfe4acc0-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2017-05-17 20:16   ` [PATCH RfC v3 2/7] pinctrl: meson: document GPIO IRQ driver DT binding Heiner Kallweit
2017-05-17 20:16     ` Heiner Kallweit
2017-05-23  0:56     ` Rob Herring
2017-05-23  0:56       ` Rob Herring
2017-05-17 20:16   ` [PATCH RfC v3 5/7] pinctrl: meson: improve meson_get_bank and export it Heiner Kallweit
2017-05-17 20:16     ` Heiner Kallweit
2017-05-17 20:17   ` [PATCH RfC v3 7/7] pinctrl: meson: add interrupt controller to GPIO DT nodes Heiner Kallweit
2017-05-17 20:17     ` Heiner Kallweit
2017-05-30 21:44     ` Rob Herring
2017-05-30 21:44       ` Rob Herring

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.