Merge branch 'asus' into release
[sfrench/cifs-2.6.git] / arch / arm / mach-davinci / gpio.c
index 1b6532159c58813b8973aa906bcec26c9ea138de..f6ea9db11f417bee1882ab32d3ed1b35230b632d 100644 (file)
@@ -34,6 +34,7 @@ static DEFINE_SPINLOCK(gpio_lock);
 struct davinci_gpio {
        struct gpio_chip        chip;
        struct gpio_controller  *__iomem regs;
+       int                     irq_base;
 };
 
 static struct davinci_gpio chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];
@@ -161,8 +162,7 @@ pure_initcall(davinci_gpio_setup);
  * used as output pins ... which is convenient for testing.
  *
  * NOTE:  The first few GPIOs also have direct INTC hookups in addition
- * to their GPIOBNK0 irq, with a bit less overhead but less flexibility
- * on triggering (e.g. no edge options).  We don't try to use those.
+ * to their GPIOBNK0 irq, with a bit less overhead.
  *
  * All those INTC hookups (direct, plus several IRQ banks) can also
  * serve as EDMA event triggers.
@@ -171,7 +171,7 @@ pure_initcall(davinci_gpio_setup);
 static void gpio_irq_disable(unsigned irq)
 {
        struct gpio_controller *__iomem g = get_irq_chip_data(irq);
-       u32 mask = __gpio_mask(irq_to_gpio(irq));
+       u32 mask = (u32) get_irq_data(irq);
 
        __raw_writel(mask, &g->clr_falling);
        __raw_writel(mask, &g->clr_rising);
@@ -180,7 +180,7 @@ static void gpio_irq_disable(unsigned irq)
 static void gpio_irq_enable(unsigned irq)
 {
        struct gpio_controller *__iomem g = get_irq_chip_data(irq);
-       u32 mask = __gpio_mask(irq_to_gpio(irq));
+       u32 mask = (u32) get_irq_data(irq);
        unsigned status = irq_desc[irq].status;
 
        status &= IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING;
@@ -196,7 +196,7 @@ static void gpio_irq_enable(unsigned irq)
 static int gpio_irq_type(unsigned irq, unsigned trigger)
 {
        struct gpio_controller *__iomem g = get_irq_chip_data(irq);
-       u32 mask = __gpio_mask(irq_to_gpio(irq));
+       u32 mask = (u32) get_irq_data(irq);
 
        if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
                return -EINVAL;
@@ -260,6 +260,45 @@ gpio_irq_handler(unsigned irq, struct irq_desc *desc)
        /* now it may re-trigger */
 }
 
+static int gpio_to_irq_banked(struct gpio_chip *chip, unsigned offset)
+{
+       struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip);
+
+       if (d->irq_base >= 0)
+               return d->irq_base + offset;
+       else
+               return -ENODEV;
+}
+
+static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset)
+{
+       struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+       /* NOTE:  we assume for now that only irqs in the first gpio_chip
+        * can provide direct-mapped IRQs to AINTC (up to 32 GPIOs).
+        */
+       if (offset < soc_info->gpio_unbanked)
+               return soc_info->gpio_irq + offset;
+       else
+               return -ENODEV;
+}
+
+static int gpio_irq_type_unbanked(unsigned irq, unsigned trigger)
+{
+       struct gpio_controller *__iomem g = get_irq_chip_data(irq);
+       u32 mask = (u32) get_irq_data(irq);
+
+       if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
+               return -EINVAL;
+
+       __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_FALLING)
+                    ? &g->set_falling : &g->clr_falling);
+       __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_RISING)
+                    ? &g->set_rising : &g->clr_rising);
+
+       return 0;
+}
+
 /*
  * NOTE:  for suspend/resume, probably best to make a platform_device with
  * suspend_late/resume_resume calls hooking into results of the set_wake()
@@ -275,6 +314,7 @@ static int __init davinci_gpio_irq_setup(void)
        u32             binten = 0;
        unsigned        ngpio, bank_irq;
        struct davinci_soc_info *soc_info = &davinci_soc_info;
+       struct gpio_controller  *__iomem g;
 
        ngpio = soc_info->gpio_num;
 
@@ -292,12 +332,63 @@ static int __init davinci_gpio_irq_setup(void)
        }
        clk_enable(clk);
 
+       /* Arrange gpio_to_irq() support, handling either direct IRQs or
+        * banked IRQs.  Having GPIOs in the first GPIO bank use direct
+        * IRQs, while the others use banked IRQs, would need some setup
+        * tweaks to recognize hardware which can do that.
+        */
+       for (gpio = 0, bank = 0; gpio < ngpio; bank++, gpio += 32) {
+               chips[bank].chip.to_irq = gpio_to_irq_banked;
+               chips[bank].irq_base = soc_info->gpio_unbanked
+                       ? -EINVAL
+                       : (soc_info->intc_irq_num + gpio);
+       }
+
+       /*
+        * AINTC can handle direct/unbanked IRQs for GPIOs, with the GPIO
+        * controller only handling trigger modes.  We currently assume no
+        * IRQ mux conflicts; gpio_irq_type_unbanked() is only for GPIOs.
+        */
+       if (soc_info->gpio_unbanked) {
+               static struct irq_chip gpio_irqchip_unbanked;
+
+               /* pass "bank 0" GPIO IRQs to AINTC */
+               chips[0].chip.to_irq = gpio_to_irq_unbanked;
+               binten = BIT(0);
+
+               /* AINTC handles mask/unmask; GPIO handles triggering */
+               irq = bank_irq;
+               gpio_irqchip_unbanked = *get_irq_desc_chip(irq_to_desc(irq));
+               gpio_irqchip_unbanked.name = "GPIO-AINTC";
+               gpio_irqchip_unbanked.set_type = gpio_irq_type_unbanked;
+
+               /* default trigger: both edges */
+               g = gpio2controller(0);
+               __raw_writel(~0, &g->set_falling);
+               __raw_writel(~0, &g->set_rising);
+
+               /* set the direct IRQs up to use that irqchip */
+               for (gpio = 0; gpio < soc_info->gpio_unbanked; gpio++, irq++) {
+                       set_irq_chip(irq, &gpio_irqchip_unbanked);
+                       set_irq_data(irq, (void *) __gpio_mask(gpio));
+                       set_irq_chip_data(irq, g);
+                       irq_desc[irq].status |= IRQ_TYPE_EDGE_BOTH;
+               }
+
+               goto done;
+       }
+
+       /*
+        * Or, AINTC can handle IRQs for banks of 16 GPIO IRQs, which we
+        * then chain through our own handler.
+        */
        for (gpio = 0, irq = gpio_to_irq(0), bank = 0;
                        gpio < ngpio;
                        bank++, bank_irq++) {
-               struct gpio_controller  *__iomem g = gpio2controller(gpio);
                unsigned                i;
 
+               /* disabled by default, enabled only as needed */
+               g = gpio2controller(gpio);
                __raw_writel(~0, &g->clr_falling);
                __raw_writel(~0, &g->clr_rising);
 
@@ -309,6 +400,7 @@ static int __init davinci_gpio_irq_setup(void)
                for (i = 0; i < 16 && gpio < ngpio; i++, irq++, gpio++) {
                        set_irq_chip(irq, &gpio_irqchip);
                        set_irq_chip_data(irq, g);
+                       set_irq_data(irq, (void *) __gpio_mask(gpio));
                        set_irq_handler(irq, handle_simple_irq);
                        set_irq_flags(irq, IRQF_VALID);
                }
@@ -316,6 +408,7 @@ static int __init davinci_gpio_irq_setup(void)
                binten |= BIT(bank);
        }
 
+done:
        /* BINTEN -- per-bank interrupt enable. genirq would also let these
         * bits be set/cleared dynamically.
         */