diff options
Diffstat (limited to 'target/linux/brcm2708/patches-4.9/950-0012-pinctrl-bcm2835-Fix-interrupt-handling-for-GPIOs-28-.patch')
-rw-r--r-- | target/linux/brcm2708/patches-4.9/950-0012-pinctrl-bcm2835-Fix-interrupt-handling-for-GPIOs-28-.patch | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.9/950-0012-pinctrl-bcm2835-Fix-interrupt-handling-for-GPIOs-28-.patch b/target/linux/brcm2708/patches-4.9/950-0012-pinctrl-bcm2835-Fix-interrupt-handling-for-GPIOs-28-.patch new file mode 100644 index 0000000000..b29aa8d7fb --- /dev/null +++ b/target/linux/brcm2708/patches-4.9/950-0012-pinctrl-bcm2835-Fix-interrupt-handling-for-GPIOs-28-.patch @@ -0,0 +1,146 @@ +From 6f92d02f7af5a9b5ed5ded7dbeb18bf2bbb2ad85 Mon Sep 17 00:00:00 2001 +From: Phil Elwell <phil@raspberrypi.org> +Date: Tue, 24 Feb 2015 13:40:50 +0000 +Subject: [PATCH] pinctrl-bcm2835: Fix interrupt handling for GPIOs 28-31 and + 46-53 + +Contrary to the documentation, the BCM2835 GPIO controller actually has +four interrupt lines - one each for the three IRQ groups and one common. Rather +confusingly, the GPIO interrupt groups don't correspond directly with the GPIO +control banks. Instead, GPIOs 0-27 generate IRQ GPIO0, 28-45 GPIO1 and +46-53 GPIO2. + +Awkwardly, the GPIOS for IRQ GPIO1 straddle two 32-entry GPIO banks, so it is +cleaner to split out a function to process the interrupts for a single GPIO +bank. + +This bug has only just been observed because GPIOs above 27 can only be +accessed on an old Raspberry Pi with the optional P5 header fitted, where +the pins are often used for I2S instead. +--- + drivers/pinctrl/bcm/pinctrl-bcm2835.c | 51 ++++++++++++++++++++++++++--------- + 1 file changed, 39 insertions(+), 12 deletions(-) + +--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c ++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c +@@ -47,6 +47,7 @@ + #define MODULE_NAME "pinctrl-bcm2835" + #define BCM2835_NUM_GPIOS 54 + #define BCM2835_NUM_BANKS 2 ++#define BCM2835_NUM_IRQS 3 + + #define BCM2835_PIN_BITMAP_SZ \ + DIV_ROUND_UP(BCM2835_NUM_GPIOS, sizeof(unsigned long) * 8) +@@ -88,13 +89,13 @@ enum bcm2835_pinconf_pull { + + struct bcm2835_gpio_irqdata { + struct bcm2835_pinctrl *pc; +- int bank; ++ int irqgroup; + }; + + struct bcm2835_pinctrl { + struct device *dev; + void __iomem *base; +- int irq[BCM2835_NUM_BANKS]; ++ int irq[BCM2835_NUM_IRQS]; + + /* note: locking assumes each bank will have its own unsigned long */ + unsigned long enabled_irq_map[BCM2835_NUM_BANKS]; +@@ -105,7 +106,7 @@ struct bcm2835_pinctrl { + struct gpio_chip gpio_chip; + struct pinctrl_gpio_range gpio_range; + +- struct bcm2835_gpio_irqdata irq_data[BCM2835_NUM_BANKS]; ++ struct bcm2835_gpio_irqdata irq_data[BCM2835_NUM_IRQS]; + spinlock_t irq_lock[BCM2835_NUM_BANKS]; + }; + +@@ -391,17 +392,16 @@ static struct gpio_chip bcm2835_gpio_chi + .can_sleep = false, + }; + +-static irqreturn_t bcm2835_gpio_irq_handler(int irq, void *dev_id) ++static int bcm2835_gpio_irq_handle_bank(struct bcm2835_pinctrl *pc, ++ unsigned int bank, u32 mask) + { +- struct bcm2835_gpio_irqdata *irqdata = dev_id; +- struct bcm2835_pinctrl *pc = irqdata->pc; +- int bank = irqdata->bank; + unsigned long events; + unsigned offset; + unsigned gpio; + unsigned int type; + + events = bcm2835_gpio_rd(pc, GPEDS0 + bank * 4); ++ events &= mask; + events &= pc->enabled_irq_map[bank]; + for_each_set_bit(offset, &events, 32) { + gpio = (32 * bank) + offset; +@@ -409,7 +409,30 @@ static irqreturn_t bcm2835_gpio_irq_hand + + generic_handle_irq(irq_linear_revmap(pc->irq_domain, gpio)); + } +- return events ? IRQ_HANDLED : IRQ_NONE; ++ ++ return (events != 0); ++} ++ ++static irqreturn_t bcm2835_gpio_irq_handler(int irq, void *dev_id) ++{ ++ struct bcm2835_gpio_irqdata *irqdata = dev_id; ++ struct bcm2835_pinctrl *pc = irqdata->pc; ++ int handled = 0; ++ ++ switch (irqdata->irqgroup) { ++ case 0: /* IRQ0 covers GPIOs 0-27 */ ++ handled = bcm2835_gpio_irq_handle_bank(pc, 0, 0x0fffffff); ++ break; ++ case 1: /* IRQ1 covers GPIOs 28-45 */ ++ handled = bcm2835_gpio_irq_handle_bank(pc, 0, 0xf0000000) | ++ bcm2835_gpio_irq_handle_bank(pc, 1, 0x00003fff); ++ break; ++ case 2: /* IRQ2 covers GPIOs 46-53 */ ++ handled = bcm2835_gpio_irq_handle_bank(pc, 1, 0x003fc000); ++ break; ++ } ++ ++ return handled ? IRQ_HANDLED : IRQ_NONE; + } + + static inline void __bcm2835_gpio_irq_config(struct bcm2835_pinctrl *pc, +@@ -998,8 +1021,6 @@ static int bcm2835_pinctrl_probe(struct + for (i = 0; i < BCM2835_NUM_BANKS; i++) { + unsigned long events; + unsigned offset; +- int len; +- char *name; + + /* clear event detection flags */ + bcm2835_gpio_wr(pc, GPREN0 + i * 4, 0); +@@ -1014,10 +1035,15 @@ static int bcm2835_pinctrl_probe(struct + for_each_set_bit(offset, &events, 32) + bcm2835_gpio_wr(pc, GPEDS0 + i * 4, BIT(offset)); + ++ spin_lock_init(&pc->irq_lock[i]); ++ } ++ ++ for (i = 0; i < BCM2835_NUM_IRQS; i++) { ++ int len; ++ char *name; + pc->irq[i] = irq_of_parse_and_map(np, i); + pc->irq_data[i].pc = pc; +- pc->irq_data[i].bank = i; +- spin_lock_init(&pc->irq_lock[i]); ++ pc->irq_data[i].irqgroup = i; + + len = strlen(dev_name(pc->dev)) + 16; + name = devm_kzalloc(pc->dev, len, GFP_KERNEL); +@@ -1074,6 +1100,7 @@ static struct platform_driver bcm2835_pi + .remove = bcm2835_pinctrl_remove, + .driver = { + .name = MODULE_NAME, ++ .owner = THIS_MODULE, + .of_match_table = bcm2835_pinctrl_match, + }, + }; |