]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
ARM: 7038/1: mach-davinci: move GPIO driver to GPIO subsystem
authorLinus Walleij <linus.walleij@linaro.org>
Mon, 22 Aug 2011 07:39:28 +0000 (08:39 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Mon, 22 Aug 2011 08:12:55 +0000 (09:12 +0100)
As per example from the other ARM boards, push the DaVinci GPIO
driver down to the GPIO subsystem so it can be consolidated.

Cc: Sekhar Nori <nsekhar@ti.com>
Cc: Kevin Hilman <khilman@ti.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/mach-davinci/Makefile
arch/arm/mach-davinci/gpio.c [deleted file]
drivers/gpio/Makefile
drivers/gpio/gpio-davinci.c [new file with mode: 0644]

index 0b87a1ca2bb3a187c78a6b20b68f7c8bb66c2288..8f3c8ee43ffa11e0baa94a507e148a4a3aa567f6 100644 (file)
@@ -5,7 +5,7 @@
 
 # Common objects
 obj-y                  := time.o clock.o serial.o io.o psc.o \
-                          gpio.o dma.o usb.o common.o sram.o aemif.o
+                          dma.o usb.o common.o sram.o aemif.o
 
 obj-$(CONFIG_DAVINCI_MUX)              += mux.o
 
diff --git a/arch/arm/mach-davinci/gpio.c b/arch/arm/mach-davinci/gpio.c
deleted file mode 100644 (file)
index a8066e8..0000000
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * TI DaVinci GPIO Support
- *
- * Copyright (c) 2006-2007 David Brownell
- * Copyright (c) 2007, MontaVista Software, Inc. <source@mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-#include <linux/gpio.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/io.h>
-
-#include <asm/mach/irq.h>
-
-struct davinci_gpio_regs {
-       u32     dir;
-       u32     out_data;
-       u32     set_data;
-       u32     clr_data;
-       u32     in_data;
-       u32     set_rising;
-       u32     clr_rising;
-       u32     set_falling;
-       u32     clr_falling;
-       u32     intstat;
-};
-
-#define chip2controller(chip)  \
-       container_of(chip, struct davinci_gpio_controller, chip)
-
-static struct davinci_gpio_controller chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];
-static void __iomem *gpio_base;
-
-static struct davinci_gpio_regs __iomem __init *gpio2regs(unsigned gpio)
-{
-       void __iomem *ptr;
-
-       if (gpio < 32 * 1)
-               ptr = gpio_base + 0x10;
-       else if (gpio < 32 * 2)
-               ptr = gpio_base + 0x38;
-       else if (gpio < 32 * 3)
-               ptr = gpio_base + 0x60;
-       else if (gpio < 32 * 4)
-               ptr = gpio_base + 0x88;
-       else if (gpio < 32 * 5)
-               ptr = gpio_base + 0xb0;
-       else
-               ptr = NULL;
-       return ptr;
-}
-
-static inline struct davinci_gpio_regs __iomem *irq2regs(int irq)
-{
-       struct davinci_gpio_regs __iomem *g;
-
-       g = (__force struct davinci_gpio_regs __iomem *)irq_get_chip_data(irq);
-
-       return g;
-}
-
-static int __init davinci_gpio_irq_setup(void);
-
-/*--------------------------------------------------------------------------*/
-
-/* board setup code *MUST* setup pinmux and enable the GPIO clock. */
-static inline int __davinci_direction(struct gpio_chip *chip,
-                       unsigned offset, bool out, int value)
-{
-       struct davinci_gpio_controller *d = chip2controller(chip);
-       struct davinci_gpio_regs __iomem *g = d->regs;
-       unsigned long flags;
-       u32 temp;
-       u32 mask = 1 << offset;
-
-       spin_lock_irqsave(&d->lock, flags);
-       temp = __raw_readl(&g->dir);
-       if (out) {
-               temp &= ~mask;
-               __raw_writel(mask, value ? &g->set_data : &g->clr_data);
-       } else {
-               temp |= mask;
-       }
-       __raw_writel(temp, &g->dir);
-       spin_unlock_irqrestore(&d->lock, flags);
-
-       return 0;
-}
-
-static int davinci_direction_in(struct gpio_chip *chip, unsigned offset)
-{
-       return __davinci_direction(chip, offset, false, 0);
-}
-
-static int
-davinci_direction_out(struct gpio_chip *chip, unsigned offset, int value)
-{
-       return __davinci_direction(chip, offset, true, value);
-}
-
-/*
- * Read the pin's value (works even if it's set up as output);
- * returns zero/nonzero.
- *
- * Note that changes are synched to the GPIO clock, so reading values back
- * right after you've set them may give old values.
- */
-static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
-       struct davinci_gpio_controller *d = chip2controller(chip);
-       struct davinci_gpio_regs __iomem *g = d->regs;
-
-       return (1 << offset) & __raw_readl(&g->in_data);
-}
-
-/*
- * Assuming the pin is muxed as a gpio output, set its output value.
- */
-static void
-davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
-       struct davinci_gpio_controller *d = chip2controller(chip);
-       struct davinci_gpio_regs __iomem *g = d->regs;
-
-       __raw_writel((1 << offset), value ? &g->set_data : &g->clr_data);
-}
-
-static int __init davinci_gpio_setup(void)
-{
-       int i, base;
-       unsigned ngpio;
-       struct davinci_soc_info *soc_info = &davinci_soc_info;
-       struct davinci_gpio_regs *regs;
-
-       if (soc_info->gpio_type != GPIO_TYPE_DAVINCI)
-               return 0;
-
-       /*
-        * The gpio banks conceptually expose a segmented bitmap,
-        * and "ngpio" is one more than the largest zero-based
-        * bit index that's valid.
-        */
-       ngpio = soc_info->gpio_num;
-       if (ngpio == 0) {
-               pr_err("GPIO setup:  how many GPIOs?\n");
-               return -EINVAL;
-       }
-
-       if (WARN_ON(DAVINCI_N_GPIO < ngpio))
-               ngpio = DAVINCI_N_GPIO;
-
-       gpio_base = ioremap(soc_info->gpio_base, SZ_4K);
-       if (WARN_ON(!gpio_base))
-               return -ENOMEM;
-
-       for (i = 0, base = 0; base < ngpio; i++, base += 32) {
-               chips[i].chip.label = "DaVinci";
-
-               chips[i].chip.direction_input = davinci_direction_in;
-               chips[i].chip.get = davinci_gpio_get;
-               chips[i].chip.direction_output = davinci_direction_out;
-               chips[i].chip.set = davinci_gpio_set;
-
-               chips[i].chip.base = base;
-               chips[i].chip.ngpio = ngpio - base;
-               if (chips[i].chip.ngpio > 32)
-                       chips[i].chip.ngpio = 32;
-
-               spin_lock_init(&chips[i].lock);
-
-               regs = gpio2regs(base);
-               chips[i].regs = regs;
-               chips[i].set_data = &regs->set_data;
-               chips[i].clr_data = &regs->clr_data;
-               chips[i].in_data = &regs->in_data;
-
-               gpiochip_add(&chips[i].chip);
-       }
-
-       soc_info->gpio_ctlrs = chips;
-       soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32);
-
-       davinci_gpio_irq_setup();
-       return 0;
-}
-pure_initcall(davinci_gpio_setup);
-
-/*--------------------------------------------------------------------------*/
-/*
- * We expect irqs will normally be set up as input pins, but they can also be
- * 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.
- *
- * All those INTC hookups (direct, plus several IRQ banks) can also
- * serve as EDMA event triggers.
- */
-
-static void gpio_irq_disable(struct irq_data *d)
-{
-       struct davinci_gpio_regs __iomem *g = irq2regs(d->irq);
-       u32 mask = (u32) irq_data_get_irq_handler_data(d);
-
-       __raw_writel(mask, &g->clr_falling);
-       __raw_writel(mask, &g->clr_rising);
-}
-
-static void gpio_irq_enable(struct irq_data *d)
-{
-       struct davinci_gpio_regs __iomem *g = irq2regs(d->irq);
-       u32 mask = (u32) irq_data_get_irq_handler_data(d);
-       unsigned status = irqd_get_trigger_type(d);
-
-       status &= IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING;
-       if (!status)
-               status = IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING;
-
-       if (status & IRQ_TYPE_EDGE_FALLING)
-               __raw_writel(mask, &g->set_falling);
-       if (status & IRQ_TYPE_EDGE_RISING)
-               __raw_writel(mask, &g->set_rising);
-}
-
-static int gpio_irq_type(struct irq_data *d, unsigned trigger)
-{
-       struct davinci_gpio_regs __iomem *g = irq2regs(d->irq);
-       u32 mask = (u32) irq_data_get_irq_handler_data(d);
-
-       if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
-               return -EINVAL;
-
-       return 0;
-}
-
-static struct irq_chip gpio_irqchip = {
-       .name           = "GPIO",
-       .irq_enable     = gpio_irq_enable,
-       .irq_disable    = gpio_irq_disable,
-       .irq_set_type   = gpio_irq_type,
-       .flags          = IRQCHIP_SET_TYPE_MASKED,
-};
-
-static void
-gpio_irq_handler(unsigned irq, struct irq_desc *desc)
-{
-       struct davinci_gpio_regs __iomem *g;
-       u32 mask = 0xffff;
-       struct davinci_gpio_controller *d;
-
-       d = (struct davinci_gpio_controller *)irq_desc_get_handler_data(desc);
-       g = (struct davinci_gpio_regs __iomem *)d->regs;
-
-       /* we only care about one bank */
-       if (irq & 1)
-               mask <<= 16;
-
-       /* temporarily mask (level sensitive) parent IRQ */
-       desc->irq_data.chip->irq_mask(&desc->irq_data);
-       desc->irq_data.chip->irq_ack(&desc->irq_data);
-       while (1) {
-               u32             status;
-               int             n;
-               int             res;
-
-               /* ack any irqs */
-               status = __raw_readl(&g->intstat) & mask;
-               if (!status)
-                       break;
-               __raw_writel(status, &g->intstat);
-
-               /* now demux them to the right lowlevel handler */
-               n = d->irq_base;
-               if (irq & 1) {
-                       n += 16;
-                       status >>= 16;
-               }
-
-               while (status) {
-                       res = ffs(status);
-                       n += res;
-                       generic_handle_irq(n - 1);
-                       status >>= res;
-               }
-       }
-       desc->irq_data.chip->irq_unmask(&desc->irq_data);
-       /* now it may re-trigger */
-}
-
-static int gpio_to_irq_banked(struct gpio_chip *chip, unsigned offset)
-{
-       struct davinci_gpio_controller *d = chip2controller(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(struct irq_data *d, unsigned trigger)
-{
-       struct davinci_gpio_regs __iomem *g = irq2regs(d->irq);
-       u32 mask = (u32) irq_data_get_irq_handler_data(d);
-
-       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()
- * calls ... so if no gpios are wakeup events the clock can be disabled,
- * with outputs left at previously set levels, and so that VDD3P3V.IOPWDN0
- * (dm6446) can be set appropriately for GPIOV33 pins.
- */
-
-static int __init davinci_gpio_irq_setup(void)
-{
-       unsigned        gpio, irq, bank;
-       struct clk      *clk;
-       u32             binten = 0;
-       unsigned        ngpio, bank_irq;
-       struct davinci_soc_info *soc_info = &davinci_soc_info;
-       struct davinci_gpio_regs        __iomem *g;
-
-       ngpio = soc_info->gpio_num;
-
-       bank_irq = soc_info->gpio_irq;
-       if (bank_irq == 0) {
-               printk(KERN_ERR "Don't know first GPIO bank IRQ.\n");
-               return -EINVAL;
-       }
-
-       clk = clk_get(NULL, "gpio");
-       if (IS_ERR(clk)) {
-               printk(KERN_ERR "Error %ld getting gpio clock?\n",
-                      PTR_ERR(clk));
-               return PTR_ERR(clk);
-       }
-       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 = *irq_get_chip(irq);
-               gpio_irqchip_unbanked.name = "GPIO-AINTC";
-               gpio_irqchip_unbanked.irq_set_type = gpio_irq_type_unbanked;
-
-               /* default trigger: both edges */
-               g = gpio2regs(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++) {
-                       irq_set_chip(irq, &gpio_irqchip_unbanked);
-                       irq_set_handler_data(irq, (void *)__gpio_mask(gpio));
-                       irq_set_chip_data(irq, (__force void *)g);
-                       irq_set_status_flags(irq, 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++) {
-               unsigned                i;
-
-               /* disabled by default, enabled only as needed */
-               g = gpio2regs(gpio);
-               __raw_writel(~0, &g->clr_falling);
-               __raw_writel(~0, &g->clr_rising);
-
-               /* set up all irqs in this bank */
-               irq_set_chained_handler(bank_irq, gpio_irq_handler);
-
-               /*
-                * Each chip handles 32 gpios, and each irq bank consists of 16
-                * gpio irqs. Pass the irq bank's corresponding controller to
-                * the chained irq handler.
-                */
-               irq_set_handler_data(bank_irq, &chips[gpio / 32]);
-
-               for (i = 0; i < 16 && gpio < ngpio; i++, irq++, gpio++) {
-                       irq_set_chip(irq, &gpio_irqchip);
-                       irq_set_chip_data(irq, (__force void *)g);
-                       irq_set_handler_data(irq, (void *)__gpio_mask(gpio));
-                       irq_set_handler(irq, handle_simple_irq);
-                       set_irq_flags(irq, IRQF_VALID);
-               }
-
-               binten |= BIT(bank);
-       }
-
-done:
-       /* BINTEN -- per-bank interrupt enable. genirq would also let these
-        * bits be set/cleared dynamically.
-        */
-       __raw_writel(binten, gpio_base + 0x08);
-
-       printk(KERN_INFO "DaVinci: %d gpio irqs\n", irq - gpio_to_irq(0));
-
-       return 0;
-}
index 27295cbadaf36f9d2cd6a24faa0aebe18476796e..a26fffacdfa530812f7b22592e17ce00d17f5426 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_GPIO_ADP5588)    += gpio-adp5588.o
 obj-$(CONFIG_GPIO_BT8XX)       += gpio-bt8xx.o
 obj-$(CONFIG_GPIO_CS5535)      += gpio-cs5535.o
 obj-$(CONFIG_GPIO_DA9052)      += gpio-da9052.o
+obj-$(CONFIG_ARCH_DAVINCI)     += gpio-davinci.o
 obj-$(CONFIG_GPIO_EP93XX)      += gpio-ep93xx.o
 obj-$(CONFIG_GPIO_EXYNOS4)     += gpio-exynos4.o
 obj-$(CONFIG_GPIO_IT8761E)     += gpio-it8761e.o
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
new file mode 100644 (file)
index 0000000..a8066e8
--- /dev/null
@@ -0,0 +1,458 @@
+/*
+ * TI DaVinci GPIO Support
+ *
+ * Copyright (c) 2006-2007 David Brownell
+ * Copyright (c) 2007, MontaVista Software, Inc. <source@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/gpio.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <asm/mach/irq.h>
+
+struct davinci_gpio_regs {
+       u32     dir;
+       u32     out_data;
+       u32     set_data;
+       u32     clr_data;
+       u32     in_data;
+       u32     set_rising;
+       u32     clr_rising;
+       u32     set_falling;
+       u32     clr_falling;
+       u32     intstat;
+};
+
+#define chip2controller(chip)  \
+       container_of(chip, struct davinci_gpio_controller, chip)
+
+static struct davinci_gpio_controller chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];
+static void __iomem *gpio_base;
+
+static struct davinci_gpio_regs __iomem __init *gpio2regs(unsigned gpio)
+{
+       void __iomem *ptr;
+
+       if (gpio < 32 * 1)
+               ptr = gpio_base + 0x10;
+       else if (gpio < 32 * 2)
+               ptr = gpio_base + 0x38;
+       else if (gpio < 32 * 3)
+               ptr = gpio_base + 0x60;
+       else if (gpio < 32 * 4)
+               ptr = gpio_base + 0x88;
+       else if (gpio < 32 * 5)
+               ptr = gpio_base + 0xb0;
+       else
+               ptr = NULL;
+       return ptr;
+}
+
+static inline struct davinci_gpio_regs __iomem *irq2regs(int irq)
+{
+       struct davinci_gpio_regs __iomem *g;
+
+       g = (__force struct davinci_gpio_regs __iomem *)irq_get_chip_data(irq);
+
+       return g;
+}
+
+static int __init davinci_gpio_irq_setup(void);
+
+/*--------------------------------------------------------------------------*/
+
+/* board setup code *MUST* setup pinmux and enable the GPIO clock. */
+static inline int __davinci_direction(struct gpio_chip *chip,
+                       unsigned offset, bool out, int value)
+{
+       struct davinci_gpio_controller *d = chip2controller(chip);
+       struct davinci_gpio_regs __iomem *g = d->regs;
+       unsigned long flags;
+       u32 temp;
+       u32 mask = 1 << offset;
+
+       spin_lock_irqsave(&d->lock, flags);
+       temp = __raw_readl(&g->dir);
+       if (out) {
+               temp &= ~mask;
+               __raw_writel(mask, value ? &g->set_data : &g->clr_data);
+       } else {
+               temp |= mask;
+       }
+       __raw_writel(temp, &g->dir);
+       spin_unlock_irqrestore(&d->lock, flags);
+
+       return 0;
+}
+
+static int davinci_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+       return __davinci_direction(chip, offset, false, 0);
+}
+
+static int
+davinci_direction_out(struct gpio_chip *chip, unsigned offset, int value)
+{
+       return __davinci_direction(chip, offset, true, value);
+}
+
+/*
+ * Read the pin's value (works even if it's set up as output);
+ * returns zero/nonzero.
+ *
+ * Note that changes are synched to the GPIO clock, so reading values back
+ * right after you've set them may give old values.
+ */
+static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       struct davinci_gpio_controller *d = chip2controller(chip);
+       struct davinci_gpio_regs __iomem *g = d->regs;
+
+       return (1 << offset) & __raw_readl(&g->in_data);
+}
+
+/*
+ * Assuming the pin is muxed as a gpio output, set its output value.
+ */
+static void
+davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct davinci_gpio_controller *d = chip2controller(chip);
+       struct davinci_gpio_regs __iomem *g = d->regs;
+
+       __raw_writel((1 << offset), value ? &g->set_data : &g->clr_data);
+}
+
+static int __init davinci_gpio_setup(void)
+{
+       int i, base;
+       unsigned ngpio;
+       struct davinci_soc_info *soc_info = &davinci_soc_info;
+       struct davinci_gpio_regs *regs;
+
+       if (soc_info->gpio_type != GPIO_TYPE_DAVINCI)
+               return 0;
+
+       /*
+        * The gpio banks conceptually expose a segmented bitmap,
+        * and "ngpio" is one more than the largest zero-based
+        * bit index that's valid.
+        */
+       ngpio = soc_info->gpio_num;
+       if (ngpio == 0) {
+               pr_err("GPIO setup:  how many GPIOs?\n");
+               return -EINVAL;
+       }
+
+       if (WARN_ON(DAVINCI_N_GPIO < ngpio))
+               ngpio = DAVINCI_N_GPIO;
+
+       gpio_base = ioremap(soc_info->gpio_base, SZ_4K);
+       if (WARN_ON(!gpio_base))
+               return -ENOMEM;
+
+       for (i = 0, base = 0; base < ngpio; i++, base += 32) {
+               chips[i].chip.label = "DaVinci";
+
+               chips[i].chip.direction_input = davinci_direction_in;
+               chips[i].chip.get = davinci_gpio_get;
+               chips[i].chip.direction_output = davinci_direction_out;
+               chips[i].chip.set = davinci_gpio_set;
+
+               chips[i].chip.base = base;
+               chips[i].chip.ngpio = ngpio - base;
+               if (chips[i].chip.ngpio > 32)
+                       chips[i].chip.ngpio = 32;
+
+               spin_lock_init(&chips[i].lock);
+
+               regs = gpio2regs(base);
+               chips[i].regs = regs;
+               chips[i].set_data = &regs->set_data;
+               chips[i].clr_data = &regs->clr_data;
+               chips[i].in_data = &regs->in_data;
+
+               gpiochip_add(&chips[i].chip);
+       }
+
+       soc_info->gpio_ctlrs = chips;
+       soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32);
+
+       davinci_gpio_irq_setup();
+       return 0;
+}
+pure_initcall(davinci_gpio_setup);
+
+/*--------------------------------------------------------------------------*/
+/*
+ * We expect irqs will normally be set up as input pins, but they can also be
+ * 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.
+ *
+ * All those INTC hookups (direct, plus several IRQ banks) can also
+ * serve as EDMA event triggers.
+ */
+
+static void gpio_irq_disable(struct irq_data *d)
+{
+       struct davinci_gpio_regs __iomem *g = irq2regs(d->irq);
+       u32 mask = (u32) irq_data_get_irq_handler_data(d);
+
+       __raw_writel(mask, &g->clr_falling);
+       __raw_writel(mask, &g->clr_rising);
+}
+
+static void gpio_irq_enable(struct irq_data *d)
+{
+       struct davinci_gpio_regs __iomem *g = irq2regs(d->irq);
+       u32 mask = (u32) irq_data_get_irq_handler_data(d);
+       unsigned status = irqd_get_trigger_type(d);
+
+       status &= IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING;
+       if (!status)
+               status = IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING;
+
+       if (status & IRQ_TYPE_EDGE_FALLING)
+               __raw_writel(mask, &g->set_falling);
+       if (status & IRQ_TYPE_EDGE_RISING)
+               __raw_writel(mask, &g->set_rising);
+}
+
+static int gpio_irq_type(struct irq_data *d, unsigned trigger)
+{
+       struct davinci_gpio_regs __iomem *g = irq2regs(d->irq);
+       u32 mask = (u32) irq_data_get_irq_handler_data(d);
+
+       if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
+               return -EINVAL;
+
+       return 0;
+}
+
+static struct irq_chip gpio_irqchip = {
+       .name           = "GPIO",
+       .irq_enable     = gpio_irq_enable,
+       .irq_disable    = gpio_irq_disable,
+       .irq_set_type   = gpio_irq_type,
+       .flags          = IRQCHIP_SET_TYPE_MASKED,
+};
+
+static void
+gpio_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+       struct davinci_gpio_regs __iomem *g;
+       u32 mask = 0xffff;
+       struct davinci_gpio_controller *d;
+
+       d = (struct davinci_gpio_controller *)irq_desc_get_handler_data(desc);
+       g = (struct davinci_gpio_regs __iomem *)d->regs;
+
+       /* we only care about one bank */
+       if (irq & 1)
+               mask <<= 16;
+
+       /* temporarily mask (level sensitive) parent IRQ */
+       desc->irq_data.chip->irq_mask(&desc->irq_data);
+       desc->irq_data.chip->irq_ack(&desc->irq_data);
+       while (1) {
+               u32             status;
+               int             n;
+               int             res;
+
+               /* ack any irqs */
+               status = __raw_readl(&g->intstat) & mask;
+               if (!status)
+                       break;
+               __raw_writel(status, &g->intstat);
+
+               /* now demux them to the right lowlevel handler */
+               n = d->irq_base;
+               if (irq & 1) {
+                       n += 16;
+                       status >>= 16;
+               }
+
+               while (status) {
+                       res = ffs(status);
+                       n += res;
+                       generic_handle_irq(n - 1);
+                       status >>= res;
+               }
+       }
+       desc->irq_data.chip->irq_unmask(&desc->irq_data);
+       /* now it may re-trigger */
+}
+
+static int gpio_to_irq_banked(struct gpio_chip *chip, unsigned offset)
+{
+       struct davinci_gpio_controller *d = chip2controller(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(struct irq_data *d, unsigned trigger)
+{
+       struct davinci_gpio_regs __iomem *g = irq2regs(d->irq);
+       u32 mask = (u32) irq_data_get_irq_handler_data(d);
+
+       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()
+ * calls ... so if no gpios are wakeup events the clock can be disabled,
+ * with outputs left at previously set levels, and so that VDD3P3V.IOPWDN0
+ * (dm6446) can be set appropriately for GPIOV33 pins.
+ */
+
+static int __init davinci_gpio_irq_setup(void)
+{
+       unsigned        gpio, irq, bank;
+       struct clk      *clk;
+       u32             binten = 0;
+       unsigned        ngpio, bank_irq;
+       struct davinci_soc_info *soc_info = &davinci_soc_info;
+       struct davinci_gpio_regs        __iomem *g;
+
+       ngpio = soc_info->gpio_num;
+
+       bank_irq = soc_info->gpio_irq;
+       if (bank_irq == 0) {
+               printk(KERN_ERR "Don't know first GPIO bank IRQ.\n");
+               return -EINVAL;
+       }
+
+       clk = clk_get(NULL, "gpio");
+       if (IS_ERR(clk)) {
+               printk(KERN_ERR "Error %ld getting gpio clock?\n",
+                      PTR_ERR(clk));
+               return PTR_ERR(clk);
+       }
+       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 = *irq_get_chip(irq);
+               gpio_irqchip_unbanked.name = "GPIO-AINTC";
+               gpio_irqchip_unbanked.irq_set_type = gpio_irq_type_unbanked;
+
+               /* default trigger: both edges */
+               g = gpio2regs(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++) {
+                       irq_set_chip(irq, &gpio_irqchip_unbanked);
+                       irq_set_handler_data(irq, (void *)__gpio_mask(gpio));
+                       irq_set_chip_data(irq, (__force void *)g);
+                       irq_set_status_flags(irq, 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++) {
+               unsigned                i;
+
+               /* disabled by default, enabled only as needed */
+               g = gpio2regs(gpio);
+               __raw_writel(~0, &g->clr_falling);
+               __raw_writel(~0, &g->clr_rising);
+
+               /* set up all irqs in this bank */
+               irq_set_chained_handler(bank_irq, gpio_irq_handler);
+
+               /*
+                * Each chip handles 32 gpios, and each irq bank consists of 16
+                * gpio irqs. Pass the irq bank's corresponding controller to
+                * the chained irq handler.
+                */
+               irq_set_handler_data(bank_irq, &chips[gpio / 32]);
+
+               for (i = 0; i < 16 && gpio < ngpio; i++, irq++, gpio++) {
+                       irq_set_chip(irq, &gpio_irqchip);
+                       irq_set_chip_data(irq, (__force void *)g);
+                       irq_set_handler_data(irq, (void *)__gpio_mask(gpio));
+                       irq_set_handler(irq, handle_simple_irq);
+                       set_irq_flags(irq, IRQF_VALID);
+               }
+
+               binten |= BIT(bank);
+       }
+
+done:
+       /* BINTEN -- per-bank interrupt enable. genirq would also let these
+        * bits be set/cleared dynamically.
+        */
+       __raw_writel(binten, gpio_base + 0x08);
+
+       printk(KERN_INFO "DaVinci: %d gpio irqs\n", irq - gpio_to_irq(0));
+
+       return 0;
+}