]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/arm/mach-at91rm9200/gpio.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6-omap-h63xx.git] / arch / arm / mach-at91rm9200 / gpio.c
index cec199fd67217bd171303762431843a6722354c8..af22659c8a2895a4c90b66a2f8203790e6e509f4 100644 (file)
@@ -9,6 +9,7 @@
  * (at your option) any later version.
  */
 
+#include <linux/clk.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 
 #include <asm/io.h>
 #include <asm/hardware.h>
+#include <asm/arch/at91_pio.h>
 #include <asm/arch/gpio.h>
 
-static const u32 pio_controller_offset[4] = {
-       AT91_PIOA,
-       AT91_PIOB,
-       AT91_PIOC,
-       AT91_PIOD,
-};
+#include "generic.h"
+
+
+static struct at91_gpio_bank *gpio;
+static int gpio_banks;
+
 
 static inline void __iomem *pin_to_controller(unsigned pin)
 {
@@ -33,8 +35,8 @@ static inline void __iomem *pin_to_controller(unsigned pin)
 
        pin -= PIN_BASE;
        pin /= 32;
-       if (likely(pin < BGA_GPIO_BANKS))
-               return sys_base + pio_controller_offset[pin];
+       if (likely(pin < gpio_banks))
+               return sys_base + gpio[pin].offset;
 
        return NULL;
 }
@@ -179,7 +181,6 @@ EXPORT_SYMBOL(at91_set_multi_drive);
 
 /*--------------------------------------------------------------------------*/
 
-
 /*
  * assuming the pin is muxed as a gpio output, set its value.
  */
@@ -216,23 +217,23 @@ EXPORT_SYMBOL(at91_get_gpio_value);
 
 #ifdef CONFIG_PM
 
-static u32 wakeups[BGA_GPIO_BANKS];
-static u32 backups[BGA_GPIO_BANKS];
+static u32 wakeups[MAX_GPIO_BANKS];
+static u32 backups[MAX_GPIO_BANKS];
 
 static int gpio_irq_set_wake(unsigned pin, unsigned state)
 {
        unsigned        mask = pin_to_mask(pin);
+       unsigned        bank = (pin - PIN_BASE) / 32;
 
-       pin -= PIN_BASE;
-       pin /= 32;
-
-       if (unlikely(pin >= BGA_GPIO_BANKS))
+       if (unlikely(bank >= MAX_GPIO_BANKS))
                return -EINVAL;
 
        if (state)
-               wakeups[pin] |= mask;
+               wakeups[bank] |= mask;
        else
-               wakeups[pin] &= ~mask;
+               wakeups[bank] &= ~mask;
+
+       set_irq_wake(gpio[bank].id, state);
 
        return 0;
 }
@@ -241,32 +242,18 @@ void at91_gpio_suspend(void)
 {
        int i;
 
-       for (i = 0; i < BGA_GPIO_BANKS; i++) {
-               u32 pio = pio_controller_offset[i];
-
-               /*
-                * Note: drivers should have disabled GPIO interrupts that
-                * aren't supposed to be wakeup sources.
-                * But that is not much good on ARM.....  disable_irq() does
-                * not update the hardware immediately, so the hardware mask
-                * (IMR) has the wrong value (not current, too much is
-                * permitted).
-                *
-                * Our workaround is to disable all non-wakeup IRQs ...
-                * which is exactly what correct drivers asked for in the
-                * first place!
-                */
+       for (i = 0; i < gpio_banks; i++) {
+               u32 pio = gpio[i].offset;
+
                backups[i] = at91_sys_read(pio + PIO_IMR);
-               at91_sys_write(pio_controller_offset[i] + PIO_IDR, backups[i]);
-               at91_sys_write(pio_controller_offset[i] + PIO_IER, wakeups[i]);
-
-               if (!wakeups[i]) {
-                       disable_irq_wake(AT91_ID_PIOA + i);
-                       at91_sys_write(AT91_PMC_PCDR, 1 << (AT91_ID_PIOA + i));
-               } else {
-                       enable_irq_wake(AT91_ID_PIOA + i);
+               at91_sys_write(pio + PIO_IDR, backups[i]);
+               at91_sys_write(pio + PIO_IER, wakeups[i]);
+
+               if (!wakeups[i])
+                       clk_disable(gpio[i].clock);
+               else {
 #ifdef CONFIG_PM_DEBUG
-                       printk(KERN_DEBUG "GPIO-%c may wake for %08x\n", "ABCD"[i], wakeups[i]);
+                       printk(KERN_DEBUG "GPIO-%c may wake for %08x\n", 'A'+i, wakeups[i]);
 #endif
                }
        }
@@ -276,16 +263,15 @@ void at91_gpio_resume(void)
 {
        int i;
 
-       for (i = 0; i < BGA_GPIO_BANKS; i++) {
-               at91_sys_write(pio_controller_offset[i] + PIO_IDR, wakeups[i]);
-               at91_sys_write(pio_controller_offset[i] + PIO_IER, backups[i]);
-       }
+       for (i = 0; i < gpio_banks; i++) {
+               u32 pio = gpio[i].offset;
+
+               if (!wakeups[i])
+                       clk_enable(gpio[i].clock);
 
-       at91_sys_write(AT91_PMC_PCER,
-                         (1 << AT91_ID_PIOA)
-                       | (1 << AT91_ID_PIOB)
-                       | (1 << AT91_ID_PIOC)
-                       | (1 << AT91_ID_PIOD));
+               at91_sys_write(pio + PIO_IDR, wakeups[i]);
+               at91_sys_write(pio + PIO_IER, backups[i]);
+       }
 }
 
 #else
@@ -335,10 +321,10 @@ static struct irq_chip gpio_irqchip = {
        .set_wake       = gpio_irq_set_wake,
 };
 
-static void gpio_irq_handler(unsigned irq, struct irqdesc *desc, struct pt_regs *regs)
+static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
 {
        unsigned        pin;
-       struct irqdesc  *gpio;
+       struct irq_desc *gpio;
        void __iomem    *pio;
        u32             isr;
 
@@ -366,7 +352,7 @@ static void gpio_irq_handler(unsigned irq, struct irqdesc *desc, struct pt_regs
                                        gpio_irq_mask(pin);
                                }
                                else
-                                       desc_handle_irq(pin, gpio, regs);
+                                       desc_handle_irq(pin, gpio);
                        }
                        pin++;
                        gpio++;
@@ -377,24 +363,29 @@ static void gpio_irq_handler(unsigned irq, struct irqdesc *desc, struct pt_regs
        /* now it may re-trigger */
 }
 
-/* call this from board-specific init_irq */
-void __init at91_gpio_irq_setup(unsigned banks)
+/*--------------------------------------------------------------------------*/
+
+/*
+ * Called from the processor-specific init to enable GPIO interrupt support.
+ */
+void __init at91_gpio_irq_setup(void)
 {
-       unsigned        pioc, pin, id;
+       unsigned        pioc, pin;
 
-       if (banks > 4)
-               banks = 4;
-       for (pioc = 0, pin = PIN_BASE, id = AT91_ID_PIOA;
-                       pioc < banks;
-                       pioc++, id++) {
+       for (pioc = 0, pin = PIN_BASE;
+                       pioc < gpio_banks;
+                       pioc++) {
                void __iomem    *controller;
+               unsigned        id = gpio[pioc].id;
                unsigned        i;
 
-               controller = (void __iomem *) AT91_VA_BASE_SYS + pio_controller_offset[pioc];
+               clk_enable(gpio[pioc].clock);   /* enable PIO controller's clock */
+
+               controller = (void __iomem *) AT91_VA_BASE_SYS + gpio[pioc].offset;
                __raw_writel(~0, controller + PIO_IDR);
 
                set_irq_data(id, (void *) pin);
-               set_irq_chipdata(id, controller);
+               set_irq_chip_data(id, controller);
 
                for (i = 0; i < 32; i++, pin++) {
                        /*
@@ -402,11 +393,22 @@ void __init at91_gpio_irq_setup(unsigned banks)
                         * shorter, and the AIC handles interupts sanely.
                         */
                        set_irq_chip(pin, &gpio_irqchip);
-                       set_irq_handler(pin, do_simple_IRQ);
+                       set_irq_handler(pin, handle_simple_irq);
                        set_irq_flags(pin, IRQF_VALID);
                }
 
                set_irq_chained_handler(id, gpio_irq_handler);
        }
-       pr_info("AT91: %d gpio irqs in %d banks\n", pin - PIN_BASE, banks);
+       pr_info("AT91: %d gpio irqs in %d banks\n", pin - PIN_BASE, gpio_banks);
+}
+
+/*
+ * Called from the processor-specific init to enable GPIO pin support.
+ */
+void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks)
+{
+       BUG_ON(nr_banks > MAX_GPIO_BANKS);
+
+       gpio = data;
+       gpio_banks = nr_banks;
 }