]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
davinci: dm365 gpio irq support
authorDavid Brownell <dbrownell@users.sourceforge.net>
Fri, 26 Jun 2009 00:01:31 +0000 (17:01 -0700)
committerKevin Hilman <khilman@deeprootsystems.com>
Wed, 26 Aug 2009 07:57:00 +0000 (10:57 +0300)
Support DM365 GPIOs ... primarily by handling non-banked GPIO IRQs:

 - Flag DM365 chips as using non-banked GPIO interrupts, using a
   new soc_info field.

 - Replace the gpio_to_irq() mapping logic.  This now uses some
   runtime infrastructure, keyed off that new soc_info field,
   which doesn't handle irq_to_gpio().

 - Provide a new irq_chip ... GPIO IRQs handled directly by AINTC
   still need edge triggering managed by the GPIO controller.

DM365 chips no longer falsely report 104 GPIO IRQs as they boot.

Intelligence about IRQ muxing is missing, so for the moment this
only exposes the first eight DM365 GPIOs, which are never muxed.
The next eight are muxed, half with Ethernet (which uses most of
those pins anyway).

Tested on DM355 (10 unbanked IRQs _or_ 104 banked ones) and also
on DM365 (16 unbanked ones, only 8 made available).

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
arch/arm/mach-davinci/dm365.c
arch/arm/mach-davinci/gpio.c
arch/arm/mach-davinci/include/mach/common.h
arch/arm/mach-davinci/include/mach/gpio.h

index e5873bc0a0fa9b81b5b8d45f65bff225dfe8a452..f02bce8eeba4d1047fd81598de3ea07394a7b415 100644 (file)
@@ -882,7 +882,8 @@ static struct davinci_soc_info davinci_soc_info_dm365 = {
        .timer_info             = &dm365_timer_info,
        .gpio_base              = IO_ADDRESS(DAVINCI_GPIO_BASE),
        .gpio_num               = 104,
-       .gpio_irq               = 44,
+       .gpio_irq               = IRQ_DM365_GPIO0,
+       .gpio_unbanked          = 8,    /* really 16 ... skip muxed GPIOs */
        .serial_dev             = &dm365_serial_device,
        .emac_pdata             = &dm365_emac_pdata,
        .sram_dma               = 0x00010000,
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.
         */
index b21393b24d65559e084b732731111bef2b34cccb..1fd3917cae4e8722570ef2953e0d653063a2b7b4 100644 (file)
@@ -63,6 +63,7 @@ struct davinci_soc_info {
        void __iomem                    *gpio_base;
        unsigned                        gpio_num;
        unsigned                        gpio_irq;
+       unsigned                        gpio_unbanked;
        struct platform_device          *serial_dev;
        struct emac_platform_data       *emac_pdata;
        dma_addr_t                      sram_dma;
index ae07455683162117c30fec9e3cf0ea157ca8dd2d..ebcc29babeaee1059372158b92f0949d7a911a64 100644 (file)
@@ -142,15 +142,13 @@ static inline int gpio_cansleep(unsigned gpio)
 
 static inline int gpio_to_irq(unsigned gpio)
 {
-       if (gpio >= DAVINCI_N_GPIO)
-               return -EINVAL;
-       return davinci_soc_info.intc_irq_num + gpio;
+       return __gpio_to_irq(gpio);
 }
 
 static inline int irq_to_gpio(unsigned irq)
 {
-       /* caller guarantees gpio_to_irq() succeeded */
-       return irq - davinci_soc_info.intc_irq_num;
+       /* don't support the reverse mapping */
+       return -ENOSYS;
 }
 
 #endif                         /* __DAVINCI_GPIO_H */