brcm2708: add linux 4.9 support
[openwrt/staging/yousong.git] / target / linux / brcm2708 / patches-4.9 / 0012-pinctrl-bcm2835-Fix-interrupt-handling-for-GPIOs-28-.patch
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 (file)
index 0000000..67cc420
--- /dev/null
@@ -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,
+       },
+ };