diff options
author | Hans de Goede <hdegoede@redhat.com> | 2016-03-12 13:44:57 -0500 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2016-03-30 04:57:52 -0400 |
commit | 5e7515ba78fff2f5407eaa2f97c1d5c07801ac3d (patch) | |
tree | 4782fca73c49328bf1de288206ef4cc4432fd2ec /drivers/pinctrl/sunxi | |
parent | e9adb336d0bf391be23e820975ca5cd12c31d781 (diff) |
pinctrl: sunxi: Fix A33 external interrupts not working
pinctrl-sun8i-a33.c (and the dts) declare only 2 interrupt banks,
where as the closely related a23 has 3 banks. This matches with the
datasheet for the A33 where only interrupt banks B and G are specified
where as the A23 has banks A, B and G.
However the A33 being the A23 derative it is means that the interrupt
configure/status io-addresses for the 2 banks it has are not changed
from the A23, iow they have the same address as if bank A was still
present. Where as the sunxi pinctrl currently tries to use the A23 bank
A addresses for bank B, since the pinctrl code does not know about the
removed bank A.
Add a irq_bank_base parameter and use this where appropriate to take
the missing bank A into account.
This fixes external interrupts not working on the A33 (tested with
an i2c touchscreen controller which uses an external interrupt).
Cc: stable@vger.kernel.org
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl/sunxi')
-rw-r--r-- | drivers/pinctrl/sunxi/pinctrl-sun8i-a33.c | 1 | ||||
-rw-r--r-- | drivers/pinctrl/sunxi/pinctrl-sunxi.c | 17 | ||||
-rw-r--r-- | drivers/pinctrl/sunxi/pinctrl-sunxi.h | 21 |
3 files changed, 22 insertions, 17 deletions
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun8i-a33.c b/drivers/pinctrl/sunxi/pinctrl-sun8i-a33.c index 00265f0435a7..8b381d69df86 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sun8i-a33.c +++ b/drivers/pinctrl/sunxi/pinctrl-sun8i-a33.c | |||
@@ -485,6 +485,7 @@ static const struct sunxi_pinctrl_desc sun8i_a33_pinctrl_data = { | |||
485 | .pins = sun8i_a33_pins, | 485 | .pins = sun8i_a33_pins, |
486 | .npins = ARRAY_SIZE(sun8i_a33_pins), | 486 | .npins = ARRAY_SIZE(sun8i_a33_pins), |
487 | .irq_banks = 2, | 487 | .irq_banks = 2, |
488 | .irq_bank_base = 1, | ||
488 | }; | 489 | }; |
489 | 490 | ||
490 | static int sun8i_a33_pinctrl_probe(struct platform_device *pdev) | 491 | static int sun8i_a33_pinctrl_probe(struct platform_device *pdev) |
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 12a1dfabb1af..3b017dbd289c 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c | |||
@@ -579,7 +579,7 @@ static void sunxi_pinctrl_irq_release_resources(struct irq_data *d) | |||
579 | static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type) | 579 | static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type) |
580 | { | 580 | { |
581 | struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); | 581 | struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); |
582 | u32 reg = sunxi_irq_cfg_reg(d->hwirq); | 582 | u32 reg = sunxi_irq_cfg_reg(d->hwirq, pctl->desc->irq_bank_base); |
583 | u8 index = sunxi_irq_cfg_offset(d->hwirq); | 583 | u8 index = sunxi_irq_cfg_offset(d->hwirq); |
584 | unsigned long flags; | 584 | unsigned long flags; |
585 | u32 regval; | 585 | u32 regval; |
@@ -626,7 +626,8 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type) | |||
626 | static void sunxi_pinctrl_irq_ack(struct irq_data *d) | 626 | static void sunxi_pinctrl_irq_ack(struct irq_data *d) |
627 | { | 627 | { |
628 | struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); | 628 | struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); |
629 | u32 status_reg = sunxi_irq_status_reg(d->hwirq); | 629 | u32 status_reg = sunxi_irq_status_reg(d->hwirq, |
630 | pctl->desc->irq_bank_base); | ||
630 | u8 status_idx = sunxi_irq_status_offset(d->hwirq); | 631 | u8 status_idx = sunxi_irq_status_offset(d->hwirq); |
631 | 632 | ||
632 | /* Clear the IRQ */ | 633 | /* Clear the IRQ */ |
@@ -636,7 +637,7 @@ static void sunxi_pinctrl_irq_ack(struct irq_data *d) | |||
636 | static void sunxi_pinctrl_irq_mask(struct irq_data *d) | 637 | static void sunxi_pinctrl_irq_mask(struct irq_data *d) |
637 | { | 638 | { |
638 | struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); | 639 | struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); |
639 | u32 reg = sunxi_irq_ctrl_reg(d->hwirq); | 640 | u32 reg = sunxi_irq_ctrl_reg(d->hwirq, pctl->desc->irq_bank_base); |
640 | u8 idx = sunxi_irq_ctrl_offset(d->hwirq); | 641 | u8 idx = sunxi_irq_ctrl_offset(d->hwirq); |
641 | unsigned long flags; | 642 | unsigned long flags; |
642 | u32 val; | 643 | u32 val; |
@@ -653,7 +654,7 @@ static void sunxi_pinctrl_irq_mask(struct irq_data *d) | |||
653 | static void sunxi_pinctrl_irq_unmask(struct irq_data *d) | 654 | static void sunxi_pinctrl_irq_unmask(struct irq_data *d) |
654 | { | 655 | { |
655 | struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); | 656 | struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); |
656 | u32 reg = sunxi_irq_ctrl_reg(d->hwirq); | 657 | u32 reg = sunxi_irq_ctrl_reg(d->hwirq, pctl->desc->irq_bank_base); |
657 | u8 idx = sunxi_irq_ctrl_offset(d->hwirq); | 658 | u8 idx = sunxi_irq_ctrl_offset(d->hwirq); |
658 | unsigned long flags; | 659 | unsigned long flags; |
659 | u32 val; | 660 | u32 val; |
@@ -745,7 +746,7 @@ static void sunxi_pinctrl_irq_handler(struct irq_desc *desc) | |||
745 | if (bank == pctl->desc->irq_banks) | 746 | if (bank == pctl->desc->irq_banks) |
746 | return; | 747 | return; |
747 | 748 | ||
748 | reg = sunxi_irq_status_reg_from_bank(bank); | 749 | reg = sunxi_irq_status_reg_from_bank(bank, pctl->desc->irq_bank_base); |
749 | val = readl(pctl->membase + reg); | 750 | val = readl(pctl->membase + reg); |
750 | 751 | ||
751 | if (val) { | 752 | if (val) { |
@@ -1024,9 +1025,11 @@ int sunxi_pinctrl_init(struct platform_device *pdev, | |||
1024 | 1025 | ||
1025 | for (i = 0; i < pctl->desc->irq_banks; i++) { | 1026 | for (i = 0; i < pctl->desc->irq_banks; i++) { |
1026 | /* Mask and clear all IRQs before registering a handler */ | 1027 | /* Mask and clear all IRQs before registering a handler */ |
1027 | writel(0, pctl->membase + sunxi_irq_ctrl_reg_from_bank(i)); | 1028 | writel(0, pctl->membase + sunxi_irq_ctrl_reg_from_bank(i, |
1029 | pctl->desc->irq_bank_base)); | ||
1028 | writel(0xffffffff, | 1030 | writel(0xffffffff, |
1029 | pctl->membase + sunxi_irq_status_reg_from_bank(i)); | 1031 | pctl->membase + sunxi_irq_status_reg_from_bank(i, |
1032 | pctl->desc->irq_bank_base)); | ||
1030 | 1033 | ||
1031 | irq_set_chained_handler_and_data(pctl->irq[i], | 1034 | irq_set_chained_handler_and_data(pctl->irq[i], |
1032 | sunxi_pinctrl_irq_handler, | 1035 | sunxi_pinctrl_irq_handler, |
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h index e248e81a0f9e..0afce1ab12d0 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h | |||
@@ -97,6 +97,7 @@ struct sunxi_pinctrl_desc { | |||
97 | int npins; | 97 | int npins; |
98 | unsigned pin_base; | 98 | unsigned pin_base; |
99 | unsigned irq_banks; | 99 | unsigned irq_banks; |
100 | unsigned irq_bank_base; | ||
100 | bool irq_read_needs_mux; | 101 | bool irq_read_needs_mux; |
101 | }; | 102 | }; |
102 | 103 | ||
@@ -233,12 +234,12 @@ static inline u32 sunxi_pull_offset(u16 pin) | |||
233 | return pin_num * PULL_PINS_BITS; | 234 | return pin_num * PULL_PINS_BITS; |
234 | } | 235 | } |
235 | 236 | ||
236 | static inline u32 sunxi_irq_cfg_reg(u16 irq) | 237 | static inline u32 sunxi_irq_cfg_reg(u16 irq, unsigned bank_base) |
237 | { | 238 | { |
238 | u8 bank = irq / IRQ_PER_BANK; | 239 | u8 bank = irq / IRQ_PER_BANK; |
239 | u8 reg = (irq % IRQ_PER_BANK) / IRQ_CFG_IRQ_PER_REG * 0x04; | 240 | u8 reg = (irq % IRQ_PER_BANK) / IRQ_CFG_IRQ_PER_REG * 0x04; |
240 | 241 | ||
241 | return IRQ_CFG_REG + bank * IRQ_MEM_SIZE + reg; | 242 | return IRQ_CFG_REG + (bank_base + bank) * IRQ_MEM_SIZE + reg; |
242 | } | 243 | } |
243 | 244 | ||
244 | static inline u32 sunxi_irq_cfg_offset(u16 irq) | 245 | static inline u32 sunxi_irq_cfg_offset(u16 irq) |
@@ -247,16 +248,16 @@ static inline u32 sunxi_irq_cfg_offset(u16 irq) | |||
247 | return irq_num * IRQ_CFG_IRQ_BITS; | 248 | return irq_num * IRQ_CFG_IRQ_BITS; |
248 | } | 249 | } |
249 | 250 | ||
250 | static inline u32 sunxi_irq_ctrl_reg_from_bank(u8 bank) | 251 | static inline u32 sunxi_irq_ctrl_reg_from_bank(u8 bank, unsigned bank_base) |
251 | { | 252 | { |
252 | return IRQ_CTRL_REG + bank * IRQ_MEM_SIZE; | 253 | return IRQ_CTRL_REG + (bank_base + bank) * IRQ_MEM_SIZE; |
253 | } | 254 | } |
254 | 255 | ||
255 | static inline u32 sunxi_irq_ctrl_reg(u16 irq) | 256 | static inline u32 sunxi_irq_ctrl_reg(u16 irq, unsigned bank_base) |
256 | { | 257 | { |
257 | u8 bank = irq / IRQ_PER_BANK; | 258 | u8 bank = irq / IRQ_PER_BANK; |
258 | 259 | ||
259 | return sunxi_irq_ctrl_reg_from_bank(bank); | 260 | return sunxi_irq_ctrl_reg_from_bank(bank, bank_base); |
260 | } | 261 | } |
261 | 262 | ||
262 | static inline u32 sunxi_irq_ctrl_offset(u16 irq) | 263 | static inline u32 sunxi_irq_ctrl_offset(u16 irq) |
@@ -265,16 +266,16 @@ static inline u32 sunxi_irq_ctrl_offset(u16 irq) | |||
265 | return irq_num * IRQ_CTRL_IRQ_BITS; | 266 | return irq_num * IRQ_CTRL_IRQ_BITS; |
266 | } | 267 | } |
267 | 268 | ||
268 | static inline u32 sunxi_irq_status_reg_from_bank(u8 bank) | 269 | static inline u32 sunxi_irq_status_reg_from_bank(u8 bank, unsigned bank_base) |
269 | { | 270 | { |
270 | return IRQ_STATUS_REG + bank * IRQ_MEM_SIZE; | 271 | return IRQ_STATUS_REG + (bank_base + bank) * IRQ_MEM_SIZE; |
271 | } | 272 | } |
272 | 273 | ||
273 | static inline u32 sunxi_irq_status_reg(u16 irq) | 274 | static inline u32 sunxi_irq_status_reg(u16 irq, unsigned bank_base) |
274 | { | 275 | { |
275 | u8 bank = irq / IRQ_PER_BANK; | 276 | u8 bank = irq / IRQ_PER_BANK; |
276 | 277 | ||
277 | return sunxi_irq_status_reg_from_bank(bank); | 278 | return sunxi_irq_status_reg_from_bank(bank, bank_base); |
278 | } | 279 | } |
279 | 280 | ||
280 | static inline u32 sunxi_irq_status_offset(u16 irq) | 281 | static inline u32 sunxi_irq_status_offset(u16 irq) |