linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/5] pinctrl: sunxi: Add A31 external interrupts support
@ 2014-05-28 10:27 Maxime Ripard
  2014-05-28 10:27 ` [PATCH 1/5] pinctrl: sunxi: Remove irq_mask_ack and use irq_ack instead Maxime Ripard
                   ` (5 more replies)
  0 siblings, 6 replies; 11+ messages in thread
From: Maxime Ripard @ 2014-05-28 10:27 UTC (permalink / raw)
  To: linux-arm-kernel

Hi everyone,

This is an attempt at making the external interrupts on the A31 and
the A23 working.

The main difference with the previous code is that there's now several
banks and several parent interrupts, instead of a single bank with a
single parent interrupt in the older SoCs.

Most of the diffstat is to register the new irq pin functions. The
real code additions are those in the core pinctrl driver.

Maxime

Maxime Ripard (5):
  pinctrl: sunxi: Remove irq_mask_ack and use irq_ack instead
  pinctrl: sunxi: Add macro definition for pinctrl with more than one
    interrupt
  pinctrl: sunxi: Declare the number of interrupt banks in the
    descriptor
  pinctrl: sunxi: Declare the interrupt function for the A31
  pinctrl: sunxi: Implement multiple interrupt banks support

 drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c   |   1 +
 drivers/pinctrl/sunxi/pinctrl-sun5i-a10s.c  |   1 +
 drivers/pinctrl/sunxi/pinctrl-sun5i-a13.c   |   1 +
 drivers/pinctrl/sunxi/pinctrl-sun6i-a31-r.c |   1 +
 drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c   | 217 +++++++++++++++++++---------
 drivers/pinctrl/sunxi/pinctrl-sun7i-a20.c   |   1 +
 drivers/pinctrl/sunxi/pinctrl-sunxi.c       |  77 ++++++----
 drivers/pinctrl/sunxi/pinctrl-sunxi.h       |  21 ++-
 8 files changed, 219 insertions(+), 101 deletions(-)

-- 
1.9.3

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

* [PATCH 1/5] pinctrl: sunxi: Remove irq_mask_ack and use irq_ack instead
  2014-05-28 10:27 [PATCH 0/5] pinctrl: sunxi: Add A31 external interrupts support Maxime Ripard
@ 2014-05-28 10:27 ` Maxime Ripard
  2014-05-28 10:27 ` [PATCH 2/5] pinctrl: sunxi: Add macro definition for pinctrl with more than one interrupt Maxime Ripard
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: Maxime Ripard @ 2014-05-28 10:27 UTC (permalink / raw)
  To: linux-arm-kernel

If irq_mask_ack is not defined, mask_ack_irq will call irq_mask and then
irq_ack. In order to avoid code duplication, between irq_mask_ack and irq_mask,
just declare irq_ack.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/pinctrl/sunxi/pinctrl-sunxi.c | 15 ++-------------
 1 file changed, 2 insertions(+), 13 deletions(-)

diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index d69a440e728d..71d6cd10d56f 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -571,26 +571,15 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d,
 	return 0;
 }
 
-static void sunxi_pinctrl_irq_mask_ack(struct irq_data *d)
+static void sunxi_pinctrl_irq_ack(struct irq_data *d)
 {
 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
-	u32 ctrl_reg = sunxi_irq_ctrl_reg(d->hwirq);
-	u8 ctrl_idx = sunxi_irq_ctrl_offset(d->hwirq);
 	u32 status_reg = sunxi_irq_status_reg(d->hwirq);
 	u8 status_idx = sunxi_irq_status_offset(d->hwirq);
 	unsigned long flags;
-	u32 val;
-
-	spin_lock_irqsave(&pctl->lock, flags);
-
-	/* Mask the IRQ */
-	val = readl(pctl->membase + ctrl_reg);
-	writel(val & ~(1 << ctrl_idx), pctl->membase + ctrl_reg);
 
 	/* Clear the IRQ */
 	writel(1 << status_idx, pctl->membase + status_reg);
-
-	spin_unlock_irqrestore(&pctl->lock, flags);
 }
 
 static void sunxi_pinctrl_irq_mask(struct irq_data *d)
@@ -636,8 +625,8 @@ static void sunxi_pinctrl_irq_unmask(struct irq_data *d)
 }
 
 static struct irq_chip sunxi_pinctrl_irq_chip = {
+	.irq_ack	= sunxi_pinctrl_irq_ack,
 	.irq_mask	= sunxi_pinctrl_irq_mask,
-	.irq_mask_ack	= sunxi_pinctrl_irq_mask_ack,
 	.irq_unmask	= sunxi_pinctrl_irq_unmask,
 	.irq_set_type	= sunxi_pinctrl_irq_set_type,
 };
-- 
1.9.3

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

* [PATCH 2/5] pinctrl: sunxi: Add macro definition for pinctrl with more than one interrupt
  2014-05-28 10:27 [PATCH 0/5] pinctrl: sunxi: Add A31 external interrupts support Maxime Ripard
  2014-05-28 10:27 ` [PATCH 1/5] pinctrl: sunxi: Remove irq_mask_ack and use irq_ack instead Maxime Ripard
@ 2014-05-28 10:27 ` Maxime Ripard
  2014-05-28 10:27 ` [PATCH 3/5] pinctrl: sunxi: Declare the number of interrupt banks in the descriptor Maxime Ripard
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: Maxime Ripard @ 2014-05-28 10:27 UTC (permalink / raw)
  To: linux-arm-kernel

The A31 and A23, unlike the other Allwinner SoCs, have several interrupts banks
and parent interrupts, while the other only have up to 32 interrupts in a
single bank and a single parent interrupt.

Start supporting it by introducing a function macro to declare irq functions
and their banks.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/pinctrl/sunxi/pinctrl-sunxi.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
index 8169ba598876..cb87e15b1b3c 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
@@ -77,6 +77,7 @@
 struct sunxi_desc_function {
 	const char	*name;
 	u8		muxval;
+	u8		irqbank;
 	u8		irqnum;
 };
 
@@ -139,6 +140,14 @@ struct sunxi_pinctrl {
 		.irqnum = _irq,					\
 	}
 
+#define SUNXI_FUNCTION_IRQ_BANK(_val, _bank, _irq)		\
+	{							\
+		.name = "irq",					\
+		.muxval = _val,					\
+		.irqbank = _bank,				\
+		.irqnum = _irq,					\
+	}
+
 /*
  * The sunXi PIO registers are organized as is:
  * 0x00 - 0x0c	Muxing values.
-- 
1.9.3

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

* [PATCH 3/5] pinctrl: sunxi: Declare the number of interrupt banks in the descriptor
  2014-05-28 10:27 [PATCH 0/5] pinctrl: sunxi: Add A31 external interrupts support Maxime Ripard
  2014-05-28 10:27 ` [PATCH 1/5] pinctrl: sunxi: Remove irq_mask_ack and use irq_ack instead Maxime Ripard
  2014-05-28 10:27 ` [PATCH 2/5] pinctrl: sunxi: Add macro definition for pinctrl with more than one interrupt Maxime Ripard
@ 2014-05-28 10:27 ` Maxime Ripard
  2014-05-28 10:27 ` [PATCH 4/5] pinctrl: sunxi: Declare the interrupt function for the A31 Maxime Ripard
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: Maxime Ripard @ 2014-05-28 10:27 UTC (permalink / raw)
  To: linux-arm-kernel

Declare in the description structure associated to the compatible the number of
interrupt banks the device has. For now, we're not doing anything with it.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c   | 1 +
 drivers/pinctrl/sunxi/pinctrl-sun5i-a10s.c  | 1 +
 drivers/pinctrl/sunxi/pinctrl-sun5i-a13.c   | 1 +
 drivers/pinctrl/sunxi/pinctrl-sun6i-a31-r.c | 1 +
 drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c   | 1 +
 drivers/pinctrl/sunxi/pinctrl-sun7i-a20.c   | 1 +
 drivers/pinctrl/sunxi/pinctrl-sunxi.h       | 1 +
 7 files changed, 7 insertions(+)

diff --git a/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c b/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c
index fa1ff7c7e357..86b608bedca6 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c
@@ -1010,6 +1010,7 @@ static const struct sunxi_desc_pin sun4i_a10_pins[] = {
 static const struct sunxi_pinctrl_desc sun4i_a10_pinctrl_data = {
 	.pins = sun4i_a10_pins,
 	.npins = ARRAY_SIZE(sun4i_a10_pins),
+	.irq_banks = 1,
 };
 
 static int sun4i_a10_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun5i-a10s.c b/drivers/pinctrl/sunxi/pinctrl-sun5i-a10s.c
index 164d743f526c..2fa7430cabaf 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun5i-a10s.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun5i-a10s.c
@@ -661,6 +661,7 @@ static const struct sunxi_desc_pin sun5i_a10s_pins[] = {
 static const struct sunxi_pinctrl_desc sun5i_a10s_pinctrl_data = {
 	.pins = sun5i_a10s_pins,
 	.npins = ARRAY_SIZE(sun5i_a10s_pins),
+	.irq_banks = 1,
 };
 
 static int sun5i_a10s_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun5i-a13.c b/drivers/pinctrl/sunxi/pinctrl-sun5i-a13.c
index 1188a2b7b988..29c734a60b51 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun5i-a13.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun5i-a13.c
@@ -382,6 +382,7 @@ static const struct sunxi_desc_pin sun5i_a13_pins[] = {
 static const struct sunxi_pinctrl_desc sun5i_a13_pinctrl_data = {
 	.pins = sun5i_a13_pins,
 	.npins = ARRAY_SIZE(sun5i_a13_pins),
+	.irq_banks = 1,
 };
 
 static int sun5i_a13_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31-r.c b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31-r.c
index 8fcba48e0a42..9a2517b65113 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31-r.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31-r.c
@@ -93,6 +93,7 @@ static const struct sunxi_pinctrl_desc sun6i_a31_r_pinctrl_data = {
 	.pins = sun6i_a31_r_pins,
 	.npins = ARRAY_SIZE(sun6i_a31_r_pins),
 	.pin_base = PL_BASE,
+	.irq_banks = 2,
 };
 
 static int sun6i_a31_r_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c
index 8dea5856458b..7adc4888eb27 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c
@@ -836,6 +836,7 @@ static const struct sunxi_desc_pin sun6i_a31_pins[] = {
 static const struct sunxi_pinctrl_desc sun6i_a31_pinctrl_data = {
 	.pins = sun6i_a31_pins,
 	.npins = ARRAY_SIZE(sun6i_a31_pins),
+	.irq_banks = 4,
 };
 
 static int sun6i_a31_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun7i-a20.c b/drivers/pinctrl/sunxi/pinctrl-sun7i-a20.c
index d8577ce5f1a4..dac99e02bfdb 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun7i-a20.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun7i-a20.c
@@ -1036,6 +1036,7 @@ static const struct sunxi_desc_pin sun7i_a20_pins[] = {
 static const struct sunxi_pinctrl_desc sun7i_a20_pinctrl_data = {
 	.pins = sun7i_a20_pins,
 	.npins = ARRAY_SIZE(sun7i_a20_pins),
+	.irq_banks = 1,
 };
 
 static int sun7i_a20_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
index cb87e15b1b3c..7ddcce0f3c27 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
@@ -90,6 +90,7 @@ struct sunxi_pinctrl_desc {
 	const struct sunxi_desc_pin	*pins;
 	int				npins;
 	unsigned			pin_base;
+	unsigned			irq_banks;
 };
 
 struct sunxi_pinctrl_function {
-- 
1.9.3

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

* [PATCH 4/5] pinctrl: sunxi: Declare the interrupt function for the A31
  2014-05-28 10:27 [PATCH 0/5] pinctrl: sunxi: Add A31 external interrupts support Maxime Ripard
                   ` (2 preceding siblings ...)
  2014-05-28 10:27 ` [PATCH 3/5] pinctrl: sunxi: Declare the number of interrupt banks in the descriptor Maxime Ripard
@ 2014-05-28 10:27 ` Maxime Ripard
  2014-05-28 10:27 ` [PATCH 5/5] pinctrl: sunxi: Implement multiple interrupt banks support Maxime Ripard
  2014-05-28 12:14 ` [PATCH 0/5] pinctrl: sunxi: Add A31 external interrupts support Chen-Yu Tsai
  5 siblings, 0 replies; 11+ messages in thread
From: Maxime Ripard @ 2014-05-28 10:27 UTC (permalink / raw)
  To: linux-arm-kernel

The primary pinctrl device has 4 interrupt banks. As usual, to be able to
generate interrupts, the pins supporting it need to be muxed to a special
function. Declare these functions in the pins array.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c | 216 ++++++++++++++++++++----------
 1 file changed, 144 insertions(+), 72 deletions(-)

diff --git a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c
index 7adc4888eb27..a2b4b85c5ad5 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c
@@ -24,208 +24,244 @@ static const struct sunxi_desc_pin sun6i_a31_pins[] = {
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* TXD0 */
 		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D0 */
-		  SUNXI_FUNCTION(0x4, "uart1")),	/* DTR */
+		  SUNXI_FUNCTION(0x4, "uart1"),		/* DTR */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)),	/* PA_EINT0 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 1),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* TXD1 */
 		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D1 */
-		  SUNXI_FUNCTION(0x4, "uart1")),	/* DSR */
+		  SUNXI_FUNCTION(0x4, "uart1"),		/* DSR */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)),	/* PA_EINT1 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 2),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* TXD2 */
 		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D2 */
-		  SUNXI_FUNCTION(0x4, "uart1")),	/* DCD */
+		  SUNXI_FUNCTION(0x4, "uart1"),		/* DCD */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 2)),	/* PA_EINT2 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 3),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* TXD3 */
 		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D3 */
-		  SUNXI_FUNCTION(0x4, "uart1")),	/* RING */
+		  SUNXI_FUNCTION(0x4, "uart1"),		/* RING */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 3)),	/* PA_EINT3 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 4),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* TXD4 */
 		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D4 */
-		  SUNXI_FUNCTION(0x4, "uart1")),	/* TX */
+		  SUNXI_FUNCTION(0x4, "uart1"),		/* TX */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 4)),	/* PA_EINT4 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 5),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* TXD5 */
 		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D5 */
-		  SUNXI_FUNCTION(0x4, "uart1")),	/* RX */
+		  SUNXI_FUNCTION(0x4, "uart1"),		/* RX */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 5)),	/* PA_EINT5 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 6),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* TXD6 */
 		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D6 */
-		  SUNXI_FUNCTION(0x4, "uart1")),	/* RTS */
+		  SUNXI_FUNCTION(0x4, "uart1"),		/* RTS */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 6)),	/* PA_EINT6 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 7),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* TXD7 */
 		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D7 */
-		  SUNXI_FUNCTION(0x4, "uart1")),	/* CTS */
+		  SUNXI_FUNCTION(0x4, "uart1"),		/* CTS */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 7)),	/* PA_EINT7 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 8),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* TXCLK */
-		  SUNXI_FUNCTION(0x3, "lcd1")),		/* D8 */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D8 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 8)),	/* PA_EINT8 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 9),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* TXEN */
 		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D9 */
 		  SUNXI_FUNCTION(0x4, "mmc3"),		/* CMD */
-		  SUNXI_FUNCTION(0x5, "mmc2")),		/* CMD */
+		  SUNXI_FUNCTION(0x5, "mmc2"),		/* CMD */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 9)),	/* PA_EINT9 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 10),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* GTXCLK */
 		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D10 */
 		  SUNXI_FUNCTION(0x4, "mmc3"),		/* CLK */
-		  SUNXI_FUNCTION(0x5, "mmc2")),		/* CLK */
+		  SUNXI_FUNCTION(0x5, "mmc2"),		/* CLK */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 10)),	/* PA_EINT10 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 11),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* RXD0 */
 		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D11 */
 		  SUNXI_FUNCTION(0x4, "mmc3"),		/* D0 */
-		  SUNXI_FUNCTION(0x5, "mmc2")),		/* D0 */
+		  SUNXI_FUNCTION(0x5, "mmc2"),		/* D0 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 11)),	/* PA_EINT11 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 12),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* RXD1 */
 		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D12 */
 		  SUNXI_FUNCTION(0x4, "mmc3"),		/* D1 */
-		  SUNXI_FUNCTION(0x5, "mmc2")),		/* D1 */
+		  SUNXI_FUNCTION(0x5, "mmc2"),		/* D1 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 12)),	/* PA_EINT12 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 13),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* RXD2 */
 		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D13 */
 		  SUNXI_FUNCTION(0x4, "mmc3"),		/* D2 */
-		  SUNXI_FUNCTION(0x5, "mmc2")),		/* D2 */
+		  SUNXI_FUNCTION(0x5, "mmc2"),		/* D2 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 13)),	/* PA_EINT13 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 14),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* RXD3 */
 		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D14 */
 		  SUNXI_FUNCTION(0x4, "mmc3"),		/* D3 */
-		  SUNXI_FUNCTION(0x5, "mmc2")),		/* D3 */
+		  SUNXI_FUNCTION(0x5, "mmc2"),		/* D3 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 14)),	/* PA_EINT14 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 15),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* RXD4 */
-		  SUNXI_FUNCTION(0x3, "lcd1")),		/* D15 */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D15 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 15)),	/* PA_EINT15 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 16),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* RXD5 */
-		  SUNXI_FUNCTION(0x3, "lcd1")),		/* D16 */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D16 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 16)),	/* PA_EINT16 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 17),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* RXD6 */
-		  SUNXI_FUNCTION(0x3, "lcd1")),		/* D17 */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D17 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 17)),	/* PA_EINT17 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 18),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* RXD7 */
-		  SUNXI_FUNCTION(0x3, "lcd1")),		/* D18 */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D18 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 18)),	/* PA_EINT18 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 19),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* RXDV */
 		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D19 */
-		  SUNXI_FUNCTION(0x4, "pwm3")),		/* Positive */
+		  SUNXI_FUNCTION(0x4, "pwm3"),		/* Positive */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 19)),	/* PA_EINT19 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 20),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* RXCLK */
 		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D20 */
-		  SUNXI_FUNCTION(0x4, "pwm3")),		/* Negative */
+		  SUNXI_FUNCTION(0x4, "pwm3"),		/* Negative */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 20)),	/* PA_EINT20 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 21),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* TXERR */
 		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D21 */
-		  SUNXI_FUNCTION(0x4, "spi3")),		/* CS0 */
+		  SUNXI_FUNCTION(0x4, "spi3"),		/* CS0 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 21)),	/* PA_EINT21 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 22),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* RXERR */
 		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D22 */
-		  SUNXI_FUNCTION(0x4, "spi3")),		/* CLK */
+		  SUNXI_FUNCTION(0x4, "spi3"),		/* CLK */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 22)),	/* PA_EINT22 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 23),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* COL */
 		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D23 */
-		  SUNXI_FUNCTION(0x4, "spi3")),		/* MOSI */
+		  SUNXI_FUNCTION(0x4, "spi3"),		/* MOSI */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 23)),	/* PA_EINT23 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 24),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* CRS */
 		  SUNXI_FUNCTION(0x3, "lcd1"),		/* CLK */
-		  SUNXI_FUNCTION(0x4, "spi3")),		/* MISO */
+		  SUNXI_FUNCTION(0x4, "spi3"),		/* MISO */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 24)),	/* PA_EINT24 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 25),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* CLKIN */
 		  SUNXI_FUNCTION(0x3, "lcd1"),		/* DE */
-		  SUNXI_FUNCTION(0x4, "spi3")),		/* CS1 */
+		  SUNXI_FUNCTION(0x4, "spi3"),		/* CS1 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 25)),	/* PA_EINT25 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 26),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* MDC */
-		  SUNXI_FUNCTION(0x3, "lcd1")),		/* HSYNC */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* HSYNC */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 26)),	/* PA_EINT26 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 27),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "gmac"),		/* MDIO */
-		  SUNXI_FUNCTION(0x3, "lcd1")),		/* VSYNC */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* VSYNC */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 27)),	/* PA_EINT27 */
 	/* Hole */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "i2s0"),		/* MCLK */
 		  SUNXI_FUNCTION(0x3, "uart3"),		/* CTS */
-		  SUNXI_FUNCTION(0x4, "csi")),		/* MCLK1 */
+		  SUNXI_FUNCTION(0x4, "csi"),		/* MCLK1 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 0)),	/* PB_EINT0 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
-		  SUNXI_FUNCTION(0x2, "i2s0")),		/* BCLK */
+		  SUNXI_FUNCTION(0x2, "i2s0"),		/* BCLK */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 1)),	/* PB_EINT1 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
-		  SUNXI_FUNCTION(0x2, "i2s0")),		/* LRCK */
+		  SUNXI_FUNCTION(0x2, "i2s0"),		/* LRCK */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 2)),	/* PB_EINT2 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
-		  SUNXI_FUNCTION(0x2, "i2s0")),		/* DO0 */
+		  SUNXI_FUNCTION(0x2, "i2s0"),		/* DO0 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 3)),	/* PB_EINT3 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "i2s0"),		/* DO1 */
-		  SUNXI_FUNCTION(0x3, "uart3")),	/* RTS */
+		  SUNXI_FUNCTION(0x3, "uart3"),		/* RTS */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 4)),	/* PB_EINT4 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 5),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "i2s0"),		/* DO2 */
 		  SUNXI_FUNCTION(0x3, "uart3"),		/* TX */
-		  SUNXI_FUNCTION(0x4, "i2c3")),		/* SCK */
+		  SUNXI_FUNCTION(0x4, "i2c3"),		/* SCK */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 5)),	/* PB_EINT5 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 6),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "i2s0"),		/* DO3 */
 		  SUNXI_FUNCTION(0x3, "uart3"),		/* RX */
-		  SUNXI_FUNCTION(0x4, "i2c3")),		/* SDA */
+		  SUNXI_FUNCTION(0x4, "i2c3"),		/* SDA */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 6)),	/* PB_EINT6 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 7),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
-		  SUNXI_FUNCTION(0x3, "i2s0")),		/* DI */
+		  SUNXI_FUNCTION(0x3, "i2s0"),		/* DI */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 7)),	/* PB_EINT7 */
 	/* Hole */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
@@ -510,86 +546,103 @@ static const struct sunxi_desc_pin sun6i_a31_pins[] = {
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "csi"),		/* PCLK */
-		  SUNXI_FUNCTION(0x3, "ts")),		/* CLK */
+		  SUNXI_FUNCTION(0x3, "ts"),		/* CLK */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 0)),	/* PE_EINT0 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "csi"),		/* MCLK */
-		  SUNXI_FUNCTION(0x3, "ts")),		/* ERR */
+		  SUNXI_FUNCTION(0x3, "ts"),		/* ERR */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 1)),	/* PE_EINT1 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "csi"),		/* HSYNC */
-		  SUNXI_FUNCTION(0x3, "ts")),		/* SYNC */
+		  SUNXI_FUNCTION(0x3, "ts"),		/* SYNC */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 2)),	/* PE_EINT2 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "csi"),		/* VSYNC */
-		  SUNXI_FUNCTION(0x3, "ts")),		/* DVLD */
+		  SUNXI_FUNCTION(0x3, "ts"),		/* DVLD */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 3)),	/* PE_EINT3 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "csi"),		/* D0 */
-		  SUNXI_FUNCTION(0x3, "uart5")),	/* TX */
+		  SUNXI_FUNCTION(0x3, "uart5"),		/* TX */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 4)),	/* PE_EINT4 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "csi"),		/* D1 */
-		  SUNXI_FUNCTION(0x3, "uart5")),	/* RX */
+		  SUNXI_FUNCTION(0x3, "uart5"),		/* RX */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 5)),	/* PE_EINT5 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "csi"),		/* D2 */
-		  SUNXI_FUNCTION(0x3, "uart5")),	/* RTS */
+		  SUNXI_FUNCTION(0x3, "uart5"),		/* RTS */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 6)),	/* PE_EINT6 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "csi"),		/* D3 */
-		  SUNXI_FUNCTION(0x3, "uart5")),	/* CTS */
+		  SUNXI_FUNCTION(0x3, "uart5"),		/* CTS */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 7)),	/* PE_EINT7 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "csi"),		/* D4 */
-		  SUNXI_FUNCTION(0x3, "ts")),		/* D0 */
+		  SUNXI_FUNCTION(0x3, "ts"),		/* D0 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 8)),	/* PE_EINT8 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "csi"),		/* D5 */
-		  SUNXI_FUNCTION(0x3, "ts")),		/* D1 */
+		  SUNXI_FUNCTION(0x3, "ts"),		/* D1 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 9)),	/* PE_EINT9 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "csi"),		/* D6 */
-		  SUNXI_FUNCTION(0x3, "ts")),		/* D2 */
+		  SUNXI_FUNCTION(0x3, "ts"),		/* D2 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 10)),	/* PE_EINT10 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "csi"),		/* D7 */
-		  SUNXI_FUNCTION(0x3, "ts")),		/* D3 */
+		  SUNXI_FUNCTION(0x3, "ts"),		/* D3 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 11)),	/* PE_EINT11 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 12),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "csi"),		/* D8 */
-		  SUNXI_FUNCTION(0x3, "ts")),		/* D4 */
+		  SUNXI_FUNCTION(0x3, "ts"),		/* D4 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 12)),	/* PE_EINT12 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 13),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "csi"),		/* D9 */
-		  SUNXI_FUNCTION(0x3, "ts")),		/* D5 */
+		  SUNXI_FUNCTION(0x3, "ts"),		/* D5 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 13)),	/* PE_EINT13 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 14),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "csi"),		/* D10 */
-		  SUNXI_FUNCTION(0x3, "ts")),		/* D6 */
+		  SUNXI_FUNCTION(0x3, "ts"),		/* D6 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 14)),	/* PE_EINT14 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 15),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "csi"),		/* D11 */
-		  SUNXI_FUNCTION(0x3, "ts")),		/* D7 */
+		  SUNXI_FUNCTION(0x3, "ts"),		/* D7 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 15)),	/* PE_EINT15 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 16),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
-		  SUNXI_FUNCTION(0x2, "csi")),		/* MIPI CSI MCLK */
+		  SUNXI_FUNCTION(0x2, "csi"),		/* MIPI CSI MCLK */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 16)),	/* PE_EINT16 */
 	/* Hole */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
@@ -625,86 +678,105 @@ static const struct sunxi_desc_pin sun6i_a31_pins[] = {
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
-		  SUNXI_FUNCTION(0x2, "mmc1")),		/* CLK */
+		  SUNXI_FUNCTION(0x2, "mmc1"),		/* CLK */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 0)),	/* PG_EINT0 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
-		  SUNXI_FUNCTION(0x2, "mmc1")),		/* CMD */
+		  SUNXI_FUNCTION(0x2, "mmc1"),		/* CMD */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 1)),	/* PG_EINT1 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
-		  SUNXI_FUNCTION(0x2, "mmc1")),		/* D0 */
+		  SUNXI_FUNCTION(0x2, "mmc1"),		/* D0 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 2)),	/* PG_EINT2 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
-		  SUNXI_FUNCTION(0x2, "mmc1")),		/* D1 */
+		  SUNXI_FUNCTION(0x2, "mmc1"),		/* D1 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 3)),	/* PG_EINT3 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
-		  SUNXI_FUNCTION(0x2, "mmc1")),		/* D2 */
+		  SUNXI_FUNCTION(0x2, "mmc1"),		/* D2 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 4)),	/* PG_EINT4 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
-		  SUNXI_FUNCTION(0x2, "mmc1")),		/* D3 */
+		  SUNXI_FUNCTION(0x2, "mmc1"),		/* D3 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 5)),	/* PG_EINT5 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 6),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
-		  SUNXI_FUNCTION(0x2, "uart2")),	/* TX */
+		  SUNXI_FUNCTION(0x2, "uart2"),		/* TX */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 6)),	/* PG_EINT6 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 7),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
-		  SUNXI_FUNCTION(0x2, "uart2")),	/* RX */
+		  SUNXI_FUNCTION(0x2, "uart2"),		/* RX */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 7)),	/* PG_EINT7 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
-		  SUNXI_FUNCTION(0x2, "uart2")),	/* RTS */
+		  SUNXI_FUNCTION(0x2, "uart2"),		/* RTS */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 8)),	/* PG_EINT8 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
-		  SUNXI_FUNCTION(0x2, "uart2")),	/* CTS */
+		  SUNXI_FUNCTION(0x2, "uart2"),		/* CTS */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 9)),	/* PG_EINT9 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "i2c3"),		/* SCK */
-		  SUNXI_FUNCTION(0x3, "usb")),		/* DP3 */
+		  SUNXI_FUNCTION(0x3, "usb"),		/* DP3 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 10)),	/* PG_EINT10 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "i2c3"),		/* SDA */
-		  SUNXI_FUNCTION(0x3, "usb")),		/* DM3 */
+		  SUNXI_FUNCTION(0x3, "usb"),		/* DM3 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 11)),	/* PG_EINT11 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "spi1"),		/* CS1 */
-		  SUNXI_FUNCTION(0x3, "i2s1")),		/* MCLK */
+		  SUNXI_FUNCTION(0x3, "i2s1"),		/* MCLK */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 12)),	/* PG_EINT12 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 13),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "spi1"),		/* CS0 */
-		  SUNXI_FUNCTION(0x3, "i2s1")),		/* BCLK */
+		  SUNXI_FUNCTION(0x3, "i2s1"),		/* BCLK */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 13)),	/* PG_EINT13 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 14),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "spi1"),		/* CLK */
-		  SUNXI_FUNCTION(0x3, "i2s1")),		/* LRCK */
+		  SUNXI_FUNCTION(0x3, "i2s1"),		/* LRCK */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 14)),	/* PG_EINT14 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 15),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "spi1"),		/* MOSI */
-		  SUNXI_FUNCTION(0x3, "i2s1")),		/* DIN */
+		  SUNXI_FUNCTION(0x3, "i2s1"),		/* DIN */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 15)),	/* PG_EINT15 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 16),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
 		  SUNXI_FUNCTION(0x2, "spi1"),		/* MISO */
-		  SUNXI_FUNCTION(0x3, "i2s1")),		/* DOUT */
+		  SUNXI_FUNCTION(0x3, "i2s1"),		/* DOUT */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 16)),	/* PG_EINT16 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 17),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
-		  SUNXI_FUNCTION(0x2, "uart4")),	/* TX */
+		  SUNXI_FUNCTION(0x2, "uart4"),		/* TX */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 17)),	/* PG_EINT17 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 18),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
 		  SUNXI_FUNCTION(0x1, "gpio_out"),
-		  SUNXI_FUNCTION(0x2, "uart4")),	/* RX */
+		  SUNXI_FUNCTION(0x2, "uart4"),		/* RX */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 18)),	/* PG_EINT18 */
 	/* Hole */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 0),
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
-- 
1.9.3

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

* [PATCH 5/5] pinctrl: sunxi: Implement multiple interrupt banks support
  2014-05-28 10:27 [PATCH 0/5] pinctrl: sunxi: Add A31 external interrupts support Maxime Ripard
                   ` (3 preceding siblings ...)
  2014-05-28 10:27 ` [PATCH 4/5] pinctrl: sunxi: Declare the interrupt function for the A31 Maxime Ripard
@ 2014-05-28 10:27 ` Maxime Ripard
  2014-05-28 11:47   ` Chen-Yu Tsai
  2014-05-28 12:14 ` [PATCH 0/5] pinctrl: sunxi: Add A31 external interrupts support Chen-Yu Tsai
  5 siblings, 1 reply; 11+ messages in thread
From: Maxime Ripard @ 2014-05-28 10:27 UTC (permalink / raw)
  To: linux-arm-kernel

The A23 and A31 support multiple interrupt banks. Support it by adding a linear
domain covering all the banks. It's trickier than it should because there's an
interrupt per bank, so we have multiple interrupts using the same domain.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/pinctrl/sunxi/pinctrl-sunxi.c | 62 +++++++++++++++++++++++++++--------
 drivers/pinctrl/sunxi/pinctrl-sunxi.h | 11 +++++--
 2 files changed, 57 insertions(+), 16 deletions(-)

diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index 71d6cd10d56f..69b58aacc636 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -635,17 +635,25 @@ static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
 {
 	struct irq_chip *chip = irq_get_chip(irq);
 	struct sunxi_pinctrl *pctl = irq_get_handler_data(irq);
-	const unsigned long reg = readl(pctl->membase + IRQ_STATUS_REG);
+	unsigned long bank, reg, val;
+
+	for (bank = 0; bank < pctl->desc->irq_banks; bank++)
+		if (irq == pctl->irq[bank])
+			break;
+
+	reg = sunxi_irq_status_reg_from_bank(bank);
+	val = readl(pctl->membase + reg);
 
 	/* Clear all interrupts */
-	writel(reg, pctl->membase + IRQ_STATUS_REG);
+	writel(val, pctl->membase + reg);
 
-	if (reg) {
+	if (val) {
 		int irqoffset;
 
 		chained_irq_enter(chip, desc);
-		for_each_set_bit(irqoffset, &reg, SUNXI_IRQ_NUMBER) {
-			int pin_irq = irq_find_mapping(pctl->domain, irqoffset);
+		for_each_set_bit(irqoffset, &val, SUNXI_IRQ_NUMBER) {
+			int pin_irq = irq_find_mapping(pctl->domain,
+						       bank * SUNXI_IRQ_NUMBER + irqoffset);
 			generic_handle_irq(pin_irq);
 		}
 		chained_irq_exit(chip, desc);
@@ -713,8 +721,11 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
 
 		while (func->name) {
 			/* Create interrupt mapping while we're at it */
-			if (!strcmp(func->name, "irq"))
-				pctl->irq_array[func->irqnum] = pin->pin.number;
+			if (!strcmp(func->name, "irq")) {
+				int irqnum = func->irqnum + func->irqbank * SUNXI_IRQ_NUMBER;
+				pctl->irq_array[irqnum] = pin->pin.number;
+			}
+
 			sunxi_pinctrl_add_function(pctl, func->name);
 			func++;
 		}
@@ -784,6 +795,13 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
 	pctl->dev = &pdev->dev;
 	pctl->desc = desc;
 
+	pctl->irq_array = devm_kcalloc(&pdev->dev,
+				       SUNXI_IRQ_NUMBER * pctl->desc->irq_banks,
+				       sizeof(*pctl->irq_array),
+				       GFP_KERNEL);
+	if (!pctl->irq_array)
+		return -ENOMEM;
+
 	ret = sunxi_pinctrl_build_state(pdev);
 	if (ret) {
 		dev_err(&pdev->dev, "dt probe failed: %d\n", ret);
@@ -868,21 +886,34 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
 	if (ret)
 		goto gpiochip_error;
 
-	pctl->irq = irq_of_parse_and_map(node, 0);
+	pctl->irq = devm_kcalloc(&pdev->dev,
+				 pctl->desc->irq_banks,
+				 sizeof(*pctl->irq),
+				 GFP_KERNEL);
 	if (!pctl->irq) {
-		ret = -EINVAL;
+		ret = -ENOMEM;
 		goto clk_error;
 	}
 
-	pctl->domain = irq_domain_add_linear(node, SUNXI_IRQ_NUMBER,
-					     &irq_domain_simple_ops, NULL);
+	for (i = 0; i < pctl->desc->irq_banks; i++) {
+		pctl->irq[i] = platform_get_irq(pdev, i);
+		if (pctl->irq[i] < 0) {
+			ret = pctl->irq[i];
+			goto clk_error;
+		}
+	}
+
+	pctl->domain = irq_domain_add_linear(node,
+					     pctl->desc->irq_banks * SUNXI_IRQ_NUMBER,
+					     &irq_domain_simple_ops,
+					     NULL);
 	if (!pctl->domain) {
 		dev_err(&pdev->dev, "Couldn't register IRQ domain\n");
 		ret = -ENOMEM;
 		goto clk_error;
 	}
 
-	for (i = 0; i < SUNXI_IRQ_NUMBER; i++) {
+	for (i = 0; i < (pctl->desc->irq_banks * SUNXI_IRQ_NUMBER); i++) {
 		int irqno = irq_create_mapping(pctl->domain, i);
 
 		irq_set_chip_and_handler(irqno, &sunxi_pinctrl_irq_chip,
@@ -890,8 +921,11 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
 		irq_set_chip_data(irqno, pctl);
 	};
 
-	irq_set_chained_handler(pctl->irq, sunxi_pinctrl_irq_handler);
-	irq_set_handler_data(pctl->irq, pctl);
+	for (i = 0; i < pctl->desc->irq_banks; i++) {
+		irq_set_chained_handler(pctl->irq[i],
+					sunxi_pinctrl_irq_handler);
+		irq_set_handler_data(pctl->irq[i], pctl);
+	}
 
 	dev_info(&pdev->dev, "initialized sunXi PIO driver\n");
 
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
index 7ddcce0f3c27..e4a808e66fd2 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
@@ -68,6 +68,8 @@
 #define IRQ_STATUS_IRQ_BITS		1
 #define IRQ_STATUS_IRQ_MASK		((1 << IRQ_STATUS_IRQ_BITS) - 1)
 
+#define IRQ_MEM_SIZE		0x20
+
 #define IRQ_EDGE_RISING		0x00
 #define IRQ_EDGE_FALLING	0x01
 #define IRQ_LEVEL_HIGH		0x02
@@ -115,8 +117,8 @@ struct sunxi_pinctrl {
 	unsigned			nfunctions;
 	struct sunxi_pinctrl_group	*groups;
 	unsigned			ngroups;
-	int				irq;
-	int				irq_array[SUNXI_IRQ_NUMBER];
+	int				*irq;
+	unsigned			*irq_array;
 	spinlock_t			lock;
 	struct pinctrl_dev		*pctl_dev;
 };
@@ -250,6 +252,11 @@ static inline u32 sunxi_irq_ctrl_offset(u16 irq)
 	return irq_num * IRQ_CTRL_IRQ_BITS;
 }
 
+static inline u32 sunxi_irq_status_reg_from_bank(u8 bank)
+{
+	return IRQ_STATUS_REG + bank * IRQ_MEM_SIZE;
+}
+
 static inline u32 sunxi_irq_status_reg(u16 irq)
 {
 	u8 reg = irq / IRQ_STATUS_IRQ_PER_REG * 0x04;
-- 
1.9.3

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

* [PATCH 5/5] pinctrl: sunxi: Implement multiple interrupt banks support
  2014-05-28 10:27 ` [PATCH 5/5] pinctrl: sunxi: Implement multiple interrupt banks support Maxime Ripard
@ 2014-05-28 11:47   ` Chen-Yu Tsai
  2014-05-28 12:04     ` Chen-Yu Tsai
  2014-05-29 17:59     ` Maxime Ripard
  0 siblings, 2 replies; 11+ messages in thread
From: Chen-Yu Tsai @ 2014-05-28 11:47 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Wed, May 28, 2014 at 6:27 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> The A23 and A31 support multiple interrupt banks. Support it by adding a linear
> domain covering all the banks. It's trickier than it should because there's an
> interrupt per bank, so we have multiple interrupts using the same domain.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/pinctrl/sunxi/pinctrl-sunxi.c | 62 +++++++++++++++++++++++++++--------
>  drivers/pinctrl/sunxi/pinctrl-sunxi.h | 11 +++++--
>  2 files changed, 57 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
> index 71d6cd10d56f..69b58aacc636 100644
> --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
> +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
> @@ -635,17 +635,25 @@ static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
>  {
>         struct irq_chip *chip = irq_get_chip(irq);
>         struct sunxi_pinctrl *pctl = irq_get_handler_data(irq);
> -       const unsigned long reg = readl(pctl->membase + IRQ_STATUS_REG);
> +       unsigned long bank, reg, val;
> +
> +       for (bank = 0; bank < pctl->desc->irq_banks; bank++)
> +               if (irq == pctl->irq[bank])
> +                       break;

bail out or BUG_ON(bank == pctl->desc->irq_banks)?
(dumb question: would this even happen?)

> +
> +       reg = sunxi_irq_status_reg_from_bank(bank);
> +       val = readl(pctl->membase + reg);
>
>         /* Clear all interrupts */
> -       writel(reg, pctl->membase + IRQ_STATUS_REG);
> +       writel(val, pctl->membase + reg);
>
> -       if (reg) {
> +       if (val) {
>                 int irqoffset;
>
>                 chained_irq_enter(chip, desc);
> -               for_each_set_bit(irqoffset, &reg, SUNXI_IRQ_NUMBER) {
> -                       int pin_irq = irq_find_mapping(pctl->domain, irqoffset);
> +               for_each_set_bit(irqoffset, &val, SUNXI_IRQ_NUMBER) {
> +                       int pin_irq = irq_find_mapping(pctl->domain,
> +                                                      bank * SUNXI_IRQ_NUMBER + irqoffset);
>                         generic_handle_irq(pin_irq);
>                 }
>                 chained_irq_exit(chip, desc);
> @@ -713,8 +721,11 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
>
>                 while (func->name) {
>                         /* Create interrupt mapping while we're at it */
> -                       if (!strcmp(func->name, "irq"))
> -                               pctl->irq_array[func->irqnum] = pin->pin.number;
> +                       if (!strcmp(func->name, "irq")) {
> +                               int irqnum = func->irqnum + func->irqbank * SUNXI_IRQ_NUMBER;
> +                               pctl->irq_array[irqnum] = pin->pin.number;
> +                       }
> +
>                         sunxi_pinctrl_add_function(pctl, func->name);
>                         func++;
>                 }
> @@ -784,6 +795,13 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
>         pctl->dev = &pdev->dev;
>         pctl->desc = desc;
>
> +       pctl->irq_array = devm_kcalloc(&pdev->dev,
> +                                      SUNXI_IRQ_NUMBER * pctl->desc->irq_banks,
> +                                      sizeof(*pctl->irq_array),
> +                                      GFP_KERNEL);
> +       if (!pctl->irq_array)
> +               return -ENOMEM;
> +
>         ret = sunxi_pinctrl_build_state(pdev);
>         if (ret) {
>                 dev_err(&pdev->dev, "dt probe failed: %d\n", ret);
> @@ -868,21 +886,34 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
>         if (ret)
>                 goto gpiochip_error;
>
> -       pctl->irq = irq_of_parse_and_map(node, 0);
> +       pctl->irq = devm_kcalloc(&pdev->dev,
> +                                pctl->desc->irq_banks,
> +                                sizeof(*pctl->irq),
> +                                GFP_KERNEL);
>         if (!pctl->irq) {
> -               ret = -EINVAL;
> +               ret = -ENOMEM;
>                 goto clk_error;
>         }
>
> -       pctl->domain = irq_domain_add_linear(node, SUNXI_IRQ_NUMBER,
> -                                            &irq_domain_simple_ops, NULL);
> +       for (i = 0; i < pctl->desc->irq_banks; i++) {
> +               pctl->irq[i] = platform_get_irq(pdev, i);
> +               if (pctl->irq[i] < 0) {
> +                       ret = pctl->irq[i];
> +                       goto clk_error;
> +               }
> +       }
> +
> +       pctl->domain = irq_domain_add_linear(node,
> +                                            pctl->desc->irq_banks * SUNXI_IRQ_NUMBER,
> +                                            &irq_domain_simple_ops,
> +                                            NULL);
>         if (!pctl->domain) {
>                 dev_err(&pdev->dev, "Couldn't register IRQ domain\n");
>                 ret = -ENOMEM;
>                 goto clk_error;
>         }
>
> -       for (i = 0; i < SUNXI_IRQ_NUMBER; i++) {
> +       for (i = 0; i < (pctl->desc->irq_banks * SUNXI_IRQ_NUMBER); i++) {
>                 int irqno = irq_create_mapping(pctl->domain, i);
>
>                 irq_set_chip_and_handler(irqno, &sunxi_pinctrl_irq_chip,
> @@ -890,8 +921,11 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
>                 irq_set_chip_data(irqno, pctl);
>         };
>
> -       irq_set_chained_handler(pctl->irq, sunxi_pinctrl_irq_handler);
> -       irq_set_handler_data(pctl->irq, pctl);
> +       for (i = 0; i < pctl->desc->irq_banks; i++) {
> +               irq_set_chained_handler(pctl->irq[i],
> +                                       sunxi_pinctrl_irq_handler);
> +               irq_set_handler_data(pctl->irq[i], pctl);
> +       }
>
>         dev_info(&pdev->dev, "initialized sunXi PIO driver\n");
>
> diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
> index 7ddcce0f3c27..e4a808e66fd2 100644
> --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h
> +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
> @@ -68,6 +68,8 @@
>  #define IRQ_STATUS_IRQ_BITS            1
>  #define IRQ_STATUS_IRQ_MASK            ((1 << IRQ_STATUS_IRQ_BITS) - 1)
>
> +#define IRQ_MEM_SIZE           0x20
> +
>  #define IRQ_EDGE_RISING                0x00
>  #define IRQ_EDGE_FALLING       0x01
>  #define IRQ_LEVEL_HIGH         0x02
> @@ -115,8 +117,8 @@ struct sunxi_pinctrl {
>         unsigned                        nfunctions;
>         struct sunxi_pinctrl_group      *groups;
>         unsigned                        ngroups;
> -       int                             irq;
> -       int                             irq_array[SUNXI_IRQ_NUMBER];
> +       int                             *irq;
> +       unsigned                        *irq_array;
>         spinlock_t                      lock;
>         struct pinctrl_dev              *pctl_dev;
>  };
> @@ -250,6 +252,11 @@ static inline u32 sunxi_irq_ctrl_offset(u16 irq)
>         return irq_num * IRQ_CTRL_IRQ_BITS;
>  }
>
> +static inline u32 sunxi_irq_status_reg_from_bank(u8 bank)
> +{
> +       return IRQ_STATUS_REG + bank * IRQ_MEM_SIZE;
> +}
> +
>  static inline u32 sunxi_irq_status_reg(u16 irq)
>  {
>         u8 reg = irq / IRQ_STATUS_IRQ_PER_REG * 0x04;
> --
> 1.9.3
>

The rest looks good. Thanks for making it happen!


Cheers
ChenYu

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

* [PATCH 5/5] pinctrl: sunxi: Implement multiple interrupt banks support
  2014-05-28 11:47   ` Chen-Yu Tsai
@ 2014-05-28 12:04     ` Chen-Yu Tsai
  2014-05-29 18:32       ` Maxime Ripard
  2014-05-29 17:59     ` Maxime Ripard
  1 sibling, 1 reply; 11+ messages in thread
From: Chen-Yu Tsai @ 2014-05-28 12:04 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, May 28, 2014 at 7:47 PM, Chen-Yu Tsai <wens@csie.org> wrote:
> Hi,
>
> On Wed, May 28, 2014 at 6:27 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
>> The A23 and A31 support multiple interrupt banks. Support it by adding a linear
>> domain covering all the banks. It's trickier than it should because there's an
>> interrupt per bank, so we have multiple interrupts using the same domain.
>>
>> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
>> ---
>>  drivers/pinctrl/sunxi/pinctrl-sunxi.c | 62 +++++++++++++++++++++++++++--------
>>  drivers/pinctrl/sunxi/pinctrl-sunxi.h | 11 +++++--
>>  2 files changed, 57 insertions(+), 16 deletions(-)
>>
>> diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
>> index 71d6cd10d56f..69b58aacc636 100644
>> --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
>> +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
>> @@ -635,17 +635,25 @@ static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
>>  {
>>         struct irq_chip *chip = irq_get_chip(irq);
>>         struct sunxi_pinctrl *pctl = irq_get_handler_data(irq);
>> -       const unsigned long reg = readl(pctl->membase + IRQ_STATUS_REG);
>> +       unsigned long bank, reg, val;
>> +
>> +       for (bank = 0; bank < pctl->desc->irq_banks; bank++)
>> +               if (irq == pctl->irq[bank])
>> +                       break;
>
> bail out or BUG_ON(bank == pctl->desc->irq_banks)?
> (dumb question: would this even happen?)
>
>> +
>> +       reg = sunxi_irq_status_reg_from_bank(bank);
>> +       val = readl(pctl->membase + reg);
>>
>>         /* Clear all interrupts */
>> -       writel(reg, pctl->membase + IRQ_STATUS_REG);
>> +       writel(val, pctl->membase + reg);
>>
>> -       if (reg) {
>> +       if (val) {
>>                 int irqoffset;
>>
>>                 chained_irq_enter(chip, desc);
>> -               for_each_set_bit(irqoffset, &reg, SUNXI_IRQ_NUMBER) {
>> -                       int pin_irq = irq_find_mapping(pctl->domain, irqoffset);
>> +               for_each_set_bit(irqoffset, &val, SUNXI_IRQ_NUMBER) {
>> +                       int pin_irq = irq_find_mapping(pctl->domain,
>> +                                                      bank * SUNXI_IRQ_NUMBER + irqoffset);
>>                         generic_handle_irq(pin_irq);
>>                 }
>>                 chained_irq_exit(chip, desc);
>> @@ -713,8 +721,11 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
>>
>>                 while (func->name) {
>>                         /* Create interrupt mapping while we're at it */
>> -                       if (!strcmp(func->name, "irq"))
>> -                               pctl->irq_array[func->irqnum] = pin->pin.number;
>> +                       if (!strcmp(func->name, "irq")) {
>> +                               int irqnum = func->irqnum + func->irqbank * SUNXI_IRQ_NUMBER;
>> +                               pctl->irq_array[irqnum] = pin->pin.number;
>> +                       }
>> +
>>                         sunxi_pinctrl_add_function(pctl, func->name);
>>                         func++;
>>                 }
>> @@ -784,6 +795,13 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
>>         pctl->dev = &pdev->dev;
>>         pctl->desc = desc;
>>
>> +       pctl->irq_array = devm_kcalloc(&pdev->dev,
>> +                                      SUNXI_IRQ_NUMBER * pctl->desc->irq_banks,
>> +                                      sizeof(*pctl->irq_array),
>> +                                      GFP_KERNEL);
>> +       if (!pctl->irq_array)
>> +               return -ENOMEM;
>> +
>>         ret = sunxi_pinctrl_build_state(pdev);
>>         if (ret) {
>>                 dev_err(&pdev->dev, "dt probe failed: %d\n", ret);
>> @@ -868,21 +886,34 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
>>         if (ret)
>>                 goto gpiochip_error;
>>
>> -       pctl->irq = irq_of_parse_and_map(node, 0);
>> +       pctl->irq = devm_kcalloc(&pdev->dev,
>> +                                pctl->desc->irq_banks,
>> +                                sizeof(*pctl->irq),
>> +                                GFP_KERNEL);
>>         if (!pctl->irq) {
>> -               ret = -EINVAL;
>> +               ret = -ENOMEM;
>>                 goto clk_error;
>>         }
>>
>> -       pctl->domain = irq_domain_add_linear(node, SUNXI_IRQ_NUMBER,
>> -                                            &irq_domain_simple_ops, NULL);
>> +       for (i = 0; i < pctl->desc->irq_banks; i++) {
>> +               pctl->irq[i] = platform_get_irq(pdev, i);
>> +               if (pctl->irq[i] < 0) {
>> +                       ret = pctl->irq[i];
>> +                       goto clk_error;
>> +               }
>> +       }
>> +
>> +       pctl->domain = irq_domain_add_linear(node,
>> +                                            pctl->desc->irq_banks * SUNXI_IRQ_NUMBER,
>> +                                            &irq_domain_simple_ops,
>> +                                            NULL);
>>         if (!pctl->domain) {
>>                 dev_err(&pdev->dev, "Couldn't register IRQ domain\n");
>>                 ret = -ENOMEM;
>>                 goto clk_error;
>>         }
>>
>> -       for (i = 0; i < SUNXI_IRQ_NUMBER; i++) {
>> +       for (i = 0; i < (pctl->desc->irq_banks * SUNXI_IRQ_NUMBER); i++) {
>>                 int irqno = irq_create_mapping(pctl->domain, i);
>>
>>                 irq_set_chip_and_handler(irqno, &sunxi_pinctrl_irq_chip,
>> @@ -890,8 +921,11 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
>>                 irq_set_chip_data(irqno, pctl);
>>         };
>>
>> -       irq_set_chained_handler(pctl->irq, sunxi_pinctrl_irq_handler);
>> -       irq_set_handler_data(pctl->irq, pctl);
>> +       for (i = 0; i < pctl->desc->irq_banks; i++) {
>> +               irq_set_chained_handler(pctl->irq[i],
>> +                                       sunxi_pinctrl_irq_handler);
>> +               irq_set_handler_data(pctl->irq[i], pctl);
>> +       }
>>
>>         dev_info(&pdev->dev, "initialized sunXi PIO driver\n");
>>
>> diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
>> index 7ddcce0f3c27..e4a808e66fd2 100644
>> --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h
>> +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
>> @@ -68,6 +68,8 @@
>>  #define IRQ_STATUS_IRQ_BITS            1
>>  #define IRQ_STATUS_IRQ_MASK            ((1 << IRQ_STATUS_IRQ_BITS) - 1)
>>
>> +#define IRQ_MEM_SIZE           0x20
>> +
>>  #define IRQ_EDGE_RISING                0x00
>>  #define IRQ_EDGE_FALLING       0x01
>>  #define IRQ_LEVEL_HIGH         0x02
>> @@ -115,8 +117,8 @@ struct sunxi_pinctrl {
>>         unsigned                        nfunctions;
>>         struct sunxi_pinctrl_group      *groups;
>>         unsigned                        ngroups;
>> -       int                             irq;
>> -       int                             irq_array[SUNXI_IRQ_NUMBER];
>> +       int                             *irq;
>> +       unsigned                        *irq_array;
>>         spinlock_t                      lock;
>>         struct pinctrl_dev              *pctl_dev;
>>  };
>> @@ -250,6 +252,11 @@ static inline u32 sunxi_irq_ctrl_offset(u16 irq)
>>         return irq_num * IRQ_CTRL_IRQ_BITS;
>>  }
>>
>> +static inline u32 sunxi_irq_status_reg_from_bank(u8 bank)
>> +{
>> +       return IRQ_STATUS_REG + bank * IRQ_MEM_SIZE;
>> +}
>> +
>>  static inline u32 sunxi_irq_status_reg(u16 irq)
>>  {
>>         u8 reg = irq / IRQ_STATUS_IRQ_PER_REG * 0x04;

Sorry, missed this. You should also change 0x04 to IRQ_MEM_SIZE
(I believe that was the original intention?) for sunxi_irq_*_reg.

This should fix the mask/unmask/set_type callbacks.

>> --
>> 1.9.3
>>
>
> The rest looks good. Thanks for making it happen!
>
>
> Cheers
> ChenYu

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

* [PATCH 0/5] pinctrl: sunxi: Add A31 external interrupts support
  2014-05-28 10:27 [PATCH 0/5] pinctrl: sunxi: Add A31 external interrupts support Maxime Ripard
                   ` (4 preceding siblings ...)
  2014-05-28 10:27 ` [PATCH 5/5] pinctrl: sunxi: Implement multiple interrupt banks support Maxime Ripard
@ 2014-05-28 12:14 ` Chen-Yu Tsai
  5 siblings, 0 replies; 11+ messages in thread
From: Chen-Yu Tsai @ 2014-05-28 12:14 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Wed, May 28, 2014 at 6:27 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Hi everyone,
>
> This is an attempt at making the external interrupts on the A31 and
> the A23 working.
>
> The main difference with the previous code is that there's now several
> banks and several parent interrupts, instead of a single bank with a
> single parent interrupt in the older SoCs.
>
> Most of the diffstat is to register the new irq pin functions. The
> real code additions are those in the core pinctrl driver.
>
> Maxime
>
> Maxime Ripard (5):
>   pinctrl: sunxi: Remove irq_mask_ack and use irq_ack instead
>   pinctrl: sunxi: Add macro definition for pinctrl with more than one
>     interrupt
>   pinctrl: sunxi: Declare the number of interrupt banks in the
>     descriptor
>   pinctrl: sunxi: Declare the interrupt function for the A31
>   pinctrl: sunxi: Implement multiple interrupt banks support

The first 4 patches look good. The last one needs some work with the
sunxi_irq_*_reg helpers.


Thanks
ChenYu

>  drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c   |   1 +
>  drivers/pinctrl/sunxi/pinctrl-sun5i-a10s.c  |   1 +
>  drivers/pinctrl/sunxi/pinctrl-sun5i-a13.c   |   1 +
>  drivers/pinctrl/sunxi/pinctrl-sun6i-a31-r.c |   1 +
>  drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c   | 217 +++++++++++++++++++---------
>  drivers/pinctrl/sunxi/pinctrl-sun7i-a20.c   |   1 +
>  drivers/pinctrl/sunxi/pinctrl-sunxi.c       |  77 ++++++----
>  drivers/pinctrl/sunxi/pinctrl-sunxi.h       |  21 ++-
>  8 files changed, 219 insertions(+), 101 deletions(-)
>
> --
> 1.9.3
>

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

* [PATCH 5/5] pinctrl: sunxi: Implement multiple interrupt banks support
  2014-05-28 11:47   ` Chen-Yu Tsai
  2014-05-28 12:04     ` Chen-Yu Tsai
@ 2014-05-29 17:59     ` Maxime Ripard
  1 sibling, 0 replies; 11+ messages in thread
From: Maxime Ripard @ 2014-05-29 17:59 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, May 28, 2014 at 07:47:15PM +0800, Chen-Yu Tsai wrote:
> Hi,
> 
> On Wed, May 28, 2014 at 6:27 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > The A23 and A31 support multiple interrupt banks. Support it by adding a linear
> > domain covering all the banks. It's trickier than it should because there's an
> > interrupt per bank, so we have multiple interrupts using the same domain.
> >
> > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > ---
> >  drivers/pinctrl/sunxi/pinctrl-sunxi.c | 62 +++++++++++++++++++++++++++--------
> >  drivers/pinctrl/sunxi/pinctrl-sunxi.h | 11 +++++--
> >  2 files changed, 57 insertions(+), 16 deletions(-)
> >
> > diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
> > index 71d6cd10d56f..69b58aacc636 100644
> > --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
> > +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
> > @@ -635,17 +635,25 @@ static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
> >  {
> >         struct irq_chip *chip = irq_get_chip(irq);
> >         struct sunxi_pinctrl *pctl = irq_get_handler_data(irq);
> > -       const unsigned long reg = readl(pctl->membase + IRQ_STATUS_REG);
> > +       unsigned long bank, reg, val;
> > +
> > +       for (bank = 0; bank < pctl->desc->irq_banks; bank++)
> > +               if (irq == pctl->irq[bank])
> > +                       break;
> 
> bail out or BUG_ON(bank == pctl->desc->irq_banks)?
> (dumb question: would this even happen?)

This can be a spurious interrupt, so I'd prefer to just bail out.

Thanks,
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140529/6ea9a852/attachment.sig>

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

* [PATCH 5/5] pinctrl: sunxi: Implement multiple interrupt banks support
  2014-05-28 12:04     ` Chen-Yu Tsai
@ 2014-05-29 18:32       ` Maxime Ripard
  0 siblings, 0 replies; 11+ messages in thread
From: Maxime Ripard @ 2014-05-29 18:32 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, May 28, 2014 at 08:04:00PM +0800, Chen-Yu Tsai wrote:
> On Wed, May 28, 2014 at 7:47 PM, Chen-Yu Tsai <wens@csie.org> wrote:
> > Hi,
> >
> > On Wed, May 28, 2014 at 6:27 PM, Maxime Ripard
> > <maxime.ripard@free-electrons.com> wrote:
> >> The A23 and A31 support multiple interrupt banks. Support it by adding a linear
> >> domain covering all the banks. It's trickier than it should because there's an
> >> interrupt per bank, so we have multiple interrupts using the same domain.
> >>
> >> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> >> ---
> >>  drivers/pinctrl/sunxi/pinctrl-sunxi.c | 62 +++++++++++++++++++++++++++--------
> >>  drivers/pinctrl/sunxi/pinctrl-sunxi.h | 11 +++++--
> >>  2 files changed, 57 insertions(+), 16 deletions(-)
> >>
> >> diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
> >> index 71d6cd10d56f..69b58aacc636 100644
> >> --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
> >> +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
> >> @@ -635,17 +635,25 @@ static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
> >>  {
> >>         struct irq_chip *chip = irq_get_chip(irq);
> >>         struct sunxi_pinctrl *pctl = irq_get_handler_data(irq);
> >> -       const unsigned long reg = readl(pctl->membase + IRQ_STATUS_REG);
> >> +       unsigned long bank, reg, val;
> >> +
> >> +       for (bank = 0; bank < pctl->desc->irq_banks; bank++)
> >> +               if (irq == pctl->irq[bank])
> >> +                       break;
> >
> > bail out or BUG_ON(bank == pctl->desc->irq_banks)?
> > (dumb question: would this even happen?)
> >
> >> +
> >> +       reg = sunxi_irq_status_reg_from_bank(bank);
> >> +       val = readl(pctl->membase + reg);
> >>
> >>         /* Clear all interrupts */
> >> -       writel(reg, pctl->membase + IRQ_STATUS_REG);
> >> +       writel(val, pctl->membase + reg);
> >>
> >> -       if (reg) {
> >> +       if (val) {
> >>                 int irqoffset;
> >>
> >>                 chained_irq_enter(chip, desc);
> >> -               for_each_set_bit(irqoffset, &reg, SUNXI_IRQ_NUMBER) {
> >> -                       int pin_irq = irq_find_mapping(pctl->domain, irqoffset);
> >> +               for_each_set_bit(irqoffset, &val, SUNXI_IRQ_NUMBER) {
> >> +                       int pin_irq = irq_find_mapping(pctl->domain,
> >> +                                                      bank * SUNXI_IRQ_NUMBER + irqoffset);
> >>                         generic_handle_irq(pin_irq);
> >>                 }
> >>                 chained_irq_exit(chip, desc);
> >> @@ -713,8 +721,11 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
> >>
> >>                 while (func->name) {
> >>                         /* Create interrupt mapping while we're at it */
> >> -                       if (!strcmp(func->name, "irq"))
> >> -                               pctl->irq_array[func->irqnum] = pin->pin.number;
> >> +                       if (!strcmp(func->name, "irq")) {
> >> +                               int irqnum = func->irqnum + func->irqbank * SUNXI_IRQ_NUMBER;
> >> +                               pctl->irq_array[irqnum] = pin->pin.number;
> >> +                       }
> >> +
> >>                         sunxi_pinctrl_add_function(pctl, func->name);
> >>                         func++;
> >>                 }
> >> @@ -784,6 +795,13 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
> >>         pctl->dev = &pdev->dev;
> >>         pctl->desc = desc;
> >>
> >> +       pctl->irq_array = devm_kcalloc(&pdev->dev,
> >> +                                      SUNXI_IRQ_NUMBER * pctl->desc->irq_banks,
> >> +                                      sizeof(*pctl->irq_array),
> >> +                                      GFP_KERNEL);
> >> +       if (!pctl->irq_array)
> >> +               return -ENOMEM;
> >> +
> >>         ret = sunxi_pinctrl_build_state(pdev);
> >>         if (ret) {
> >>                 dev_err(&pdev->dev, "dt probe failed: %d\n", ret);
> >> @@ -868,21 +886,34 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
> >>         if (ret)
> >>                 goto gpiochip_error;
> >>
> >> -       pctl->irq = irq_of_parse_and_map(node, 0);
> >> +       pctl->irq = devm_kcalloc(&pdev->dev,
> >> +                                pctl->desc->irq_banks,
> >> +                                sizeof(*pctl->irq),
> >> +                                GFP_KERNEL);
> >>         if (!pctl->irq) {
> >> -               ret = -EINVAL;
> >> +               ret = -ENOMEM;
> >>                 goto clk_error;
> >>         }
> >>
> >> -       pctl->domain = irq_domain_add_linear(node, SUNXI_IRQ_NUMBER,
> >> -                                            &irq_domain_simple_ops, NULL);
> >> +       for (i = 0; i < pctl->desc->irq_banks; i++) {
> >> +               pctl->irq[i] = platform_get_irq(pdev, i);
> >> +               if (pctl->irq[i] < 0) {
> >> +                       ret = pctl->irq[i];
> >> +                       goto clk_error;
> >> +               }
> >> +       }
> >> +
> >> +       pctl->domain = irq_domain_add_linear(node,
> >> +                                            pctl->desc->irq_banks * SUNXI_IRQ_NUMBER,
> >> +                                            &irq_domain_simple_ops,
> >> +                                            NULL);
> >>         if (!pctl->domain) {
> >>                 dev_err(&pdev->dev, "Couldn't register IRQ domain\n");
> >>                 ret = -ENOMEM;
> >>                 goto clk_error;
> >>         }
> >>
> >> -       for (i = 0; i < SUNXI_IRQ_NUMBER; i++) {
> >> +       for (i = 0; i < (pctl->desc->irq_banks * SUNXI_IRQ_NUMBER); i++) {
> >>                 int irqno = irq_create_mapping(pctl->domain, i);
> >>
> >>                 irq_set_chip_and_handler(irqno, &sunxi_pinctrl_irq_chip,
> >> @@ -890,8 +921,11 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
> >>                 irq_set_chip_data(irqno, pctl);
> >>         };
> >>
> >> -       irq_set_chained_handler(pctl->irq, sunxi_pinctrl_irq_handler);
> >> -       irq_set_handler_data(pctl->irq, pctl);
> >> +       for (i = 0; i < pctl->desc->irq_banks; i++) {
> >> +               irq_set_chained_handler(pctl->irq[i],
> >> +                                       sunxi_pinctrl_irq_handler);
> >> +               irq_set_handler_data(pctl->irq[i], pctl);
> >> +       }
> >>
> >>         dev_info(&pdev->dev, "initialized sunXi PIO driver\n");
> >>
> >> diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
> >> index 7ddcce0f3c27..e4a808e66fd2 100644
> >> --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h
> >> +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
> >> @@ -68,6 +68,8 @@
> >>  #define IRQ_STATUS_IRQ_BITS            1
> >>  #define IRQ_STATUS_IRQ_MASK            ((1 << IRQ_STATUS_IRQ_BITS) - 1)
> >>
> >> +#define IRQ_MEM_SIZE           0x20
> >> +
> >>  #define IRQ_EDGE_RISING                0x00
> >>  #define IRQ_EDGE_FALLING       0x01
> >>  #define IRQ_LEVEL_HIGH         0x02
> >> @@ -115,8 +117,8 @@ struct sunxi_pinctrl {
> >>         unsigned                        nfunctions;
> >>         struct sunxi_pinctrl_group      *groups;
> >>         unsigned                        ngroups;
> >> -       int                             irq;
> >> -       int                             irq_array[SUNXI_IRQ_NUMBER];
> >> +       int                             *irq;
> >> +       unsigned                        *irq_array;
> >>         spinlock_t                      lock;
> >>         struct pinctrl_dev              *pctl_dev;
> >>  };
> >> @@ -250,6 +252,11 @@ static inline u32 sunxi_irq_ctrl_offset(u16 irq)
> >>         return irq_num * IRQ_CTRL_IRQ_BITS;
> >>  }
> >>
> >> +static inline u32 sunxi_irq_status_reg_from_bank(u8 bank)
> >> +{
> >> +       return IRQ_STATUS_REG + bank * IRQ_MEM_SIZE;
> >> +}
> >> +
> >>  static inline u32 sunxi_irq_status_reg(u16 irq)
> >>  {
> >>         u8 reg = irq / IRQ_STATUS_IRQ_PER_REG * 0x04;
> 
> Sorry, missed this. You should also change 0x04 to IRQ_MEM_SIZE
> (I believe that was the original intention?) for sunxi_irq_*_reg.
> 
> This should fix the mask/unmask/set_type callbacks.

Hmm right. I completely missed this, and used a PA* pin, so it never
made any difference.

I'm sending a new version.

Thanks,
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140529/7dc0fb98/attachment.sig>

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

end of thread, other threads:[~2014-05-29 18:32 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-05-28 10:27 [PATCH 0/5] pinctrl: sunxi: Add A31 external interrupts support Maxime Ripard
2014-05-28 10:27 ` [PATCH 1/5] pinctrl: sunxi: Remove irq_mask_ack and use irq_ack instead Maxime Ripard
2014-05-28 10:27 ` [PATCH 2/5] pinctrl: sunxi: Add macro definition for pinctrl with more than one interrupt Maxime Ripard
2014-05-28 10:27 ` [PATCH 3/5] pinctrl: sunxi: Declare the number of interrupt banks in the descriptor Maxime Ripard
2014-05-28 10:27 ` [PATCH 4/5] pinctrl: sunxi: Declare the interrupt function for the A31 Maxime Ripard
2014-05-28 10:27 ` [PATCH 5/5] pinctrl: sunxi: Implement multiple interrupt banks support Maxime Ripard
2014-05-28 11:47   ` Chen-Yu Tsai
2014-05-28 12:04     ` Chen-Yu Tsai
2014-05-29 18:32       ` Maxime Ripard
2014-05-29 17:59     ` Maxime Ripard
2014-05-28 12:14 ` [PATCH 0/5] pinctrl: sunxi: Add A31 external interrupts support Chen-Yu Tsai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).