Merge branch 'timers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / arch / arm / mach-davinci / gpio.c
index c77683c..bf0ff58 100644 (file)
 
 #include <asm/mach/irq.h>
 
-static DEFINE_SPINLOCK(gpio_lock);
+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;
 
-/* create a non-inlined version */
 static struct davinci_gpio_regs __iomem __init *gpio2regs(unsigned gpio)
 {
-       return __gpio_to_controller(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)
@@ -46,20 +71,17 @@ static int __init davinci_gpio_irq_setup(void);
 
 /*--------------------------------------------------------------------------*/
 
-/*
- * board setup code *MUST* set PINMUX0 and PINMUX1 as
- * needed, and enable the GPIO clock.
- */
-
+/* 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(&gpio_lock);
+       spin_lock_irqsave(&d->lock, flags);
        temp = __raw_readl(&g->dir);
        if (out) {
                temp &= ~mask;
@@ -68,7 +90,7 @@ static inline int __davinci_direction(struct gpio_chip *chip,
                temp |= mask;
        }
        __raw_writel(temp, &g->dir);
-       spin_unlock(&gpio_lock);
+       spin_unlock_irqrestore(&d->lock, flags);
 
        return 0;
 }
@@ -116,6 +138,10 @@ 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,
@@ -131,6 +157,10 @@ static int __init davinci_gpio_setup(void)
        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";
 
@@ -144,11 +174,20 @@ static int __init davinci_gpio_setup(void)
                if (chips[i].chip.ngpio > 32)
                        chips[i].chip.ngpio = 32;
 
-               chips[i].regs = gpio2regs(base);
+               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;
 }
@@ -410,7 +449,7 @@ done:
        /* BINTEN -- per-bank interrupt enable. genirq would also let these
         * bits be set/cleared dynamically.
         */
-       __raw_writel(binten, soc_info->gpio_base + 0x08);
+       __raw_writel(binten, gpio_base + 0x08);
 
        printk(KERN_INFO "DaVinci: %d gpio irqs\n", irq - gpio_to_irq(0));