aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm2708/patches-4.9/0012-pinctrl-bcm2835-Fix-interrupt-handling-for-GPIOs-28-.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/brcm2708/patches-4.9/0012-pinctrl-bcm2835-Fix-interrupt-handling-for-GPIOs-28-.patch')
-rw-r--r--target/linux/brcm2708/patches-4.9/0012-pinctrl-bcm2835-Fix-interrupt-handling-for-GPIOs-28-.patch146
1 files changed, 146 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.9/0012-pinctrl-bcm2835-Fix-interrupt-handling-for-GPIOs-28-.patch b/target/linux/brcm2708/patches-4.9/0012-pinctrl-bcm2835-Fix-interrupt-handling-for-GPIOs-28-.patch
new file mode 100644
index 0000000000..67cc420511
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.9/0012-pinctrl-bcm2835-Fix-interrupt-handling-for-GPIOs-28-.patch
@@ -0,0 +1,146 @@
+From c7ab4eb8e79ceaa923a7c9f4e14dc085a1934a29 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,
+ },
+ };