Maemo patchset 20101501+0m5
[h-e-n] / arch / arm / plat-omap / gpio.c
index 424049d..4dbeedc 100644 (file)
 #include <linux/io.h>
 
 #include <mach/hardware.h>
+#include <mach/control.h>
 #include <asm/irq.h>
 #include <mach/irqs.h>
 #include <mach/gpio.h>
 #include <asm/mach/irq.h>
+#include <mach/powerdomain.h>
+#include <mach/mux.h>
 
 /*
  * OMAP1510 GPIO registers
@@ -152,6 +155,8 @@ struct gpio_bank {
        u32 level_mask;
        spinlock_t lock;
        struct gpio_chip chip;
+       struct clk *dbck;
+       u32 dbck_enable_mask;
 };
 
 #define METHOD_MPUIO           0
@@ -218,6 +223,74 @@ static struct gpio_bank gpio_bank_34xx[6] = {
        { OMAP34XX_GPIO6_BASE, INT_34XX_GPIO_BANK6, IH_GPIO_BASE + 160, METHOD_GPIO_24XX },
 };
 
+#define OMAP34XX_PAD_SAFE_MODE 0x7
+#define OMAP34XX_PAD_IN_PU_GPIO 0x11c
+#define OMAP34XX_PAD_IN_PD_GPIO 0x10c
+#define OMAP34XX_PAD_WAKE_EN (1 << 14)
+
+struct omap3_gpio_regs {
+       u32 sysconfig;
+       u32 irqenable1;
+       u32 irqenable2;
+       u32 wake_en;
+       u32 ctrl;
+       u32 oe;
+       u32 leveldetect0;
+       u32 leveldetect1;
+       u32 risingdetect;
+       u32 fallingdetect;
+       u32 dataout;
+};
+
+static struct omap3_gpio_regs gpio_context[OMAP34XX_NR_GPIOS];
+
+/* GPIO -> PAD init configuration struct */
+struct gpio_pad_range {
+       /* Range start GPIO # */
+       u16 min;
+       /* Range end GPIO # */
+       u16 max;
+       /* Start pad config offset */
+       u16 offset;
+};
+
+/*
+ * Defines GPIO to padconfig mapping. For example first definition tells
+ * us that there is a range of GPIOs 34...43 which have their padconfigs
+ * starting from offset 0x7a, i.e. gpio 34->0x7a, 35->0x7c, 36->0x7e ... etc.
+ */
+static const struct gpio_pad_range gpio_pads_config[] = {
+       { 34, 43, 0x7a },
+       { 44, 51, 0x9e },
+       { 52, 59, 0xb0 },
+       { 60, 62, 0xc6 },
+       { 63, 111, 0xce },
+       { 167, 167, 0x130 },
+       { 126, 126, 0x132 },
+       { 112, 166, 0x134 },
+       { 120, 122, 0x1a2 },
+       { 124, 125, 0x1a8 },
+       { 130, 131, 0x1ac },
+       { 169, 169, 0x1b0 },
+       { 188, 191, 0x1b2 },
+       { 168, 168, 0x1be },
+       { 183, 185, 0x1c0 },
+       { 170, 182, 0x1c6 },
+       { 0, 0, 0x1e0 },
+       { 186, 186, 0x1e2 },
+       { 12, 29, 0x5d8 },
+};
+
+/* GPIO -> PAD config mapping for OMAP3 */
+struct gpio_pad {
+       s16 gpio;
+       u16 offset;
+       u16 save;
+};
+
+#define OMAP34XX_GPIO_AMT      (32 * OMAP34XX_NR_GPIOS)
+
+struct gpio_pad *gpio_pads;
 #endif
 
 static struct gpio_bank *gpio_bank;
@@ -244,6 +317,8 @@ static inline struct gpio_bank *get_gpio_bank(int gpio)
                return &gpio_bank[gpio >> 5];
        if (cpu_is_omap34xx())
                return &gpio_bank[gpio >> 5];
+       BUG();
+       return NULL;
 }
 
 static inline int get_gpio_index(int gpio)
@@ -332,19 +407,6 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
        __raw_writel(l, reg);
 }
 
-void omap_set_gpio_direction(int gpio, int is_input)
-{
-       struct gpio_bank *bank;
-       unsigned long flags;
-
-       if (check_gpio(gpio) < 0)
-               return;
-       bank = get_gpio_bank(gpio);
-       spin_lock_irqsave(&bank->lock, flags);
-       _set_gpio_direction(bank, get_gpio_index(gpio), is_input);
-       spin_unlock_irqrestore(&bank->lock, flags);
-}
-
 static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
 {
        void __iomem *reg = bank->base;
@@ -406,20 +468,7 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
        __raw_writel(l, reg);
 }
 
-void omap_set_gpio_dataout(int gpio, int enable)
-{
-       struct gpio_bank *bank;
-       unsigned long flags;
-
-       if (check_gpio(gpio) < 0)
-               return;
-       bank = get_gpio_bank(gpio);
-       spin_lock_irqsave(&bank->lock, flags);
-       _set_gpio_dataout(bank, get_gpio_index(gpio), enable);
-       spin_unlock_irqrestore(&bank->lock, flags);
-}
-
-int omap_get_gpio_datain(int gpio)
+static int __omap_get_gpio_datain(int gpio)
 {
        struct gpio_bank *bank;
        void __iomem *reg;
@@ -473,6 +522,7 @@ void omap_set_gpio_debounce(int gpio, int enable)
 {
        struct gpio_bank *bank;
        void __iomem *reg;
+       unsigned long flags;
        u32 val, l = 1 << get_gpio_index(gpio);
 
        if (cpu_class_is_omap1())
@@ -480,16 +530,29 @@ void omap_set_gpio_debounce(int gpio, int enable)
 
        bank = get_gpio_bank(gpio);
        reg = bank->base;
-
        reg += OMAP24XX_GPIO_DEBOUNCE_EN;
+
+       spin_lock_irqsave(&bank->lock, flags);
        val = __raw_readl(reg);
 
-       if (enable)
+       if (enable && !(val & l))
                val |= l;
-       else
+       else if (!enable && (val & l))
                val &= ~l;
+       else
+               goto done;
+
+       if (cpu_is_omap34xx()) {
+               bank->dbck_enable_mask = val;
+               if (enable)
+                       clk_enable(bank->dbck);
+               else
+                       clk_disable(bank->dbck);
+       }
 
        __raw_writel(val, reg);
+done:
+       spin_unlock_irqrestore(&bank->lock, flags);
 }
 EXPORT_SYMBOL(omap_set_gpio_debounce);
 
@@ -516,6 +579,9 @@ static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio,
 {
        void __iomem *base = bank->base;
        u32 gpio_bit = 1 << gpio;
+       struct gpio_pad *pad;
+       int gpio_num;
+       u16 val;
 
        MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT0, gpio_bit,
                trigger & IRQ_TYPE_LEVEL_LOW);
@@ -527,13 +593,30 @@ static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio,
                trigger & IRQ_TYPE_EDGE_FALLING);
 
        if (likely(!(bank->non_wakeup_gpios & gpio_bit))) {
+               pad = gpio_pads;
+
+               gpio_num = bank->virtual_irq_start - IH_GPIO_BASE + gpio;
+               /* Find the pad corresponding the GPIO */
+               while (pad->gpio >= 0 && pad->gpio != gpio_num)
+                       pad++;
+               /* Enable / disable pad wakeup */
+               if (pad->gpio == gpio_num) {
+                       val = omap_ctrl_readw(pad->offset);
+                       if (trigger)
+                               val |= OMAP34XX_PAD_WAKE_EN;
+                       else
+                               val &= ~(u16)OMAP34XX_PAD_WAKE_EN;
+                       omap_ctrl_writew(val, pad->offset);
+               }
                if (trigger != 0)
                        __raw_writel(1 << gpio, bank->base
                                        + OMAP24XX_GPIO_SETWKUENA);
                else
                        __raw_writel(1 << gpio, bank->base
                                        + OMAP24XX_GPIO_CLEARWKUENA);
-       } else {
+       }
+       /* This part needs to be executed always for OMAP34xx */
+       if (cpu_is_omap34xx() || (bank->non_wakeup_gpios & gpio_bit)) {
                if (trigger != 0)
                        bank->enabled_non_wakeup_gpios |= gpio_bit;
                else
@@ -701,8 +784,12 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
 
        /* Workaround for clearing DSP GPIO interrupts to allow retention */
 #if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+       reg = bank->base + OMAP24XX_GPIO_IRQSTATUS2;
        if (cpu_is_omap24xx() || cpu_is_omap34xx())
-               __raw_writel(gpio_mask, bank->base + OMAP24XX_GPIO_IRQSTATUS2);
+               __raw_writel(gpio_mask, reg);
+
+       /* Flush posted write for the irq status to avoid spurious interrupts */
+       __raw_readl(reg);
 #endif
 }
 
@@ -847,13 +934,10 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
        case METHOD_MPUIO:
        case METHOD_GPIO_1610:
                spin_lock_irqsave(&bank->lock, flags);
-               if (enable) {
+               if (enable)
                        bank->suspend_wakeup |= (1 << gpio);
-                       enable_irq_wake(bank->irq);
-               } else {
-                       disable_irq_wake(bank->irq);
+               else
                        bank->suspend_wakeup &= ~(1 << gpio);
-               }
                spin_unlock_irqrestore(&bank->lock, flags);
                return 0;
 #endif
@@ -866,13 +950,10 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
                        return -EINVAL;
                }
                spin_lock_irqsave(&bank->lock, flags);
-               if (enable) {
+               if (enable)
                        bank->suspend_wakeup |= (1 << gpio);
-                       enable_irq_wake(bank->irq);
-               } else {
-                       disable_irq_wake(bank->irq);
+               else
                        bank->suspend_wakeup &= ~(1 << gpio);
-               }
                spin_unlock_irqrestore(&bank->lock, flags);
                return 0;
 #endif
@@ -906,26 +987,17 @@ static int gpio_wake_enable(unsigned int irq, unsigned int enable)
        return retval;
 }
 
-int omap_request_gpio(int gpio)
+static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
 {
-       struct gpio_bank *bank;
+       struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
        unsigned long flags;
-       int status;
-
-       if (check_gpio(gpio) < 0)
-               return -EINVAL;
-
-       status = gpio_request(gpio, NULL);
-       if (status < 0)
-               return status;
 
-       bank = get_gpio_bank(gpio);
        spin_lock_irqsave(&bank->lock, flags);
 
        /* Set trigger to none. You need to enable the desired trigger with
         * request_irq() or set_irq_type().
         */
-       _set_gpio_triggering(bank, get_gpio_index(gpio), IRQ_TYPE_NONE);
+       _set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
 
 #ifdef CONFIG_ARCH_OMAP15XX
        if (bank->method == METHOD_GPIO_1510) {
@@ -933,7 +1005,7 @@ int omap_request_gpio(int gpio)
 
                /* Claim the pin for MPU */
                reg = bank->base + OMAP1510_GPIO_PIN_CONTROL;
-               __raw_writel(__raw_readl(reg) | (1 << get_gpio_index(gpio)), reg);
+               __raw_writel(__raw_readl(reg) | (1 << offset), reg);
        }
 #endif
        spin_unlock_irqrestore(&bank->lock, flags);
@@ -941,39 +1013,28 @@ int omap_request_gpio(int gpio)
        return 0;
 }
 
-void omap_free_gpio(int gpio)
+static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
-       struct gpio_bank *bank;
+       struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
        unsigned long flags;
 
-       if (check_gpio(gpio) < 0)
-               return;
-       bank = get_gpio_bank(gpio);
        spin_lock_irqsave(&bank->lock, flags);
-       if (unlikely(!gpiochip_is_requested(&bank->chip,
-                               get_gpio_index(gpio)))) {
-               spin_unlock_irqrestore(&bank->lock, flags);
-               printk(KERN_ERR "omap-gpio: GPIO %d wasn't reserved!\n", gpio);
-               dump_stack();
-               return;
-       }
 #ifdef CONFIG_ARCH_OMAP16XX
        if (bank->method == METHOD_GPIO_1610) {
                /* Disable wake-up during idle for dynamic tick */
                void __iomem *reg = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
-               __raw_writel(1 << get_gpio_index(gpio), reg);
+               __raw_writel(1 << offset, reg);
        }
 #endif
 #if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
        if (bank->method == METHOD_GPIO_24XX) {
                /* Disable wake-up during idle for dynamic tick */
                void __iomem *reg = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
-               __raw_writel(1 << get_gpio_index(gpio), reg);
+               __raw_writel(1 << offset, reg);
        }
 #endif
-       _reset_gpio(bank, gpio);
+       _reset_gpio(bank, bank->chip.base + offset);
        spin_unlock_irqrestore(&bank->lock, flags);
-       gpio_free(gpio);
 }
 
 /*
@@ -1089,6 +1150,7 @@ static void gpio_mask_irq(unsigned int irq)
        struct gpio_bank *bank = get_irq_chip_data(irq);
 
        _set_gpio_irqenable(bank, gpio, 0);
+       _set_gpio_triggering(bank, get_gpio_index(gpio), IRQ_TYPE_NONE);
 }
 
 static void gpio_unmask_irq(unsigned int irq)
@@ -1096,6 +1158,11 @@ static void gpio_unmask_irq(unsigned int irq)
        unsigned int gpio = irq - IH_GPIO_BASE;
        struct gpio_bank *bank = get_irq_chip_data(irq);
        unsigned int irq_mask = 1 << get_gpio_index(gpio);
+       struct irq_desc *desc = irq_to_desc(irq);
+       u32 trigger = desc->status & IRQ_TYPE_SENSE_MASK;
+
+       if (trigger)
+               _set_gpio_triggering(bank, get_gpio_index(gpio), trigger);
 
        /* For level-triggered GPIOs, the clearing must be done after
         * the HW source is cleared, thus after the handler has run */
@@ -1252,7 +1319,7 @@ static int gpio_input(struct gpio_chip *chip, unsigned offset)
 
 static int gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-       return omap_get_gpio_datain(chip->base + offset);
+       return __omap_get_gpio_datain(chip->base + offset);
 }
 
 static int gpio_output(struct gpio_chip *chip, unsigned offset, int value)
@@ -1279,6 +1346,14 @@ static void gpio_set(struct gpio_chip *chip, unsigned offset, int value)
        spin_unlock_irqrestore(&bank->lock, flags);
 }
 
+static int gpio_2irq(struct gpio_chip *chip, unsigned offset)
+{
+       struct gpio_bank *bank;
+
+       bank = container_of(chip, struct gpio_bank, chip);
+       return bank->virtual_irq_start + offset;
+}
+
 /*---------------------------------------------------------------------*/
 
 static int initialized;
@@ -1296,8 +1371,69 @@ static struct clk * gpio5_fck;
 #endif
 
 #if defined(CONFIG_ARCH_OMAP3)
-static struct clk *gpio_fclks[OMAP34XX_NR_GPIOS];
 static struct clk *gpio_iclks[OMAP34XX_NR_GPIOS];
+
+/*
+ * Following pad init code in addition to the context / restore hooks are
+ * needed to fix glitches in GPIO outputs during off-mode. See OMAP3
+ * errate section 1.158
+ */
+static int __init omap3_gpio_pads_init(void)
+{
+       int i, j, min, max, gpio_amt;
+       u16 offset;
+       u16 *gpio_pad_map;
+
+       gpio_amt = 0;
+
+       gpio_pad_map = kzalloc(sizeof(u16) * OMAP34XX_GPIO_AMT, GFP_KERNEL);
+       if (gpio_pad_map == NULL) {
+               printk(KERN_ERR "FATAL: Failed to allocate gpio_pad_map\n");
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(gpio_pads_config); i++) {
+               min = gpio_pads_config[i].min;
+               max = gpio_pads_config[i].max;
+               offset = gpio_pads_config[i].offset;
+
+               for (j = min; j <= max; j++) {
+                       /*
+                        * Check if pad has been configured as GPIO.
+                        * First module (gpio 0...31) is ignored as it is
+                        * in wakeup domain and does not need special
+                        * handling during off mode.
+                        */
+                       if (j > 31 && (omap_ctrl_readw(offset) &
+                               OMAP34XX_MUX_MODE7) == OMAP34XX_MUX_MODE4) {
+                               gpio_pad_map[j] = offset;
+                               gpio_amt++;
+                       }
+                       offset += 2;
+               }
+       }
+       gpio_pads = kmalloc(sizeof(struct gpio_pad) * (gpio_amt + 1),
+               GFP_KERNEL);
+
+       if (gpio_pads == NULL) {
+               printk(KERN_ERR "FATAL: Failed to allocate gpio_pads\n");
+               kfree(gpio_pad_map);
+               return -ENOMEM;
+       }
+
+       gpio_amt = 0;
+       for (i = 0; i < OMAP34XX_GPIO_AMT; i++) {
+               if (gpio_pad_map[i] != 0) {
+                       gpio_pads[gpio_amt].gpio = i;
+                       gpio_pads[gpio_amt].offset = gpio_pad_map[i];
+                       gpio_amt++;
+               }
+       }
+       gpio_pads[gpio_amt].gpio = -1;
+       kfree(gpio_pad_map);
+       return 0;
+}
+early_initcall(omap3_gpio_pads_init);
 #endif
 
 /* This lock class tells lockdep that GPIO irqs are in a different
@@ -1310,9 +1446,7 @@ static int __init _omap_gpio_init(void)
        int i;
        int gpio = 0;
        struct gpio_bank *bank;
-#if defined(CONFIG_ARCH_OMAP3)
        char clk_name[11];
-#endif
 
        initialized = 1;
 
@@ -1367,12 +1501,6 @@ static int __init _omap_gpio_init(void)
                                printk(KERN_ERR "Could not get %s\n", clk_name);
                        else
                                clk_enable(gpio_iclks[i]);
-                       sprintf(clk_name, "gpio%d_fck", i + 1);
-                       gpio_fclks[i] = clk_get(NULL, clk_name);
-                       if (IS_ERR(gpio_fclks[i]))
-                               printk(KERN_ERR "Could not get %s\n", clk_name);
-                       else
-                               clk_enable(gpio_fclks[i]);
                }
        }
 #endif
@@ -1470,7 +1598,8 @@ static int __init _omap_gpio_init(void)
 
                        /* Initialize interface clock ungated, module enabled */
                        __raw_writel(0, bank->base + OMAP24XX_GPIO_CTRL);
-                       if (i < ARRAY_SIZE(non_wakeup_gpios))
+                       if (cpu_is_omap24xx() &&
+                           i < ARRAY_SIZE(non_wakeup_gpios))
                                bank->non_wakeup_gpios = non_wakeup_gpios[i];
                        gpio_count = 32;
                }
@@ -1479,10 +1608,13 @@ static int __init _omap_gpio_init(void)
                /* REVISIT eventually switch from OMAP-specific gpio structs
                 * over to the generic ones
                 */
+               bank->chip.request = omap_gpio_request;
+               bank->chip.free = omap_gpio_free;
                bank->chip.direction_input = gpio_input;
                bank->chip.get = gpio_get;
                bank->chip.direction_output = gpio_output;
                bank->chip.set = gpio_set;
+               bank->chip.to_irq = gpio_2irq;
                if (bank_is_mpuio(bank)) {
                        bank->chip.label = "mpuio";
 #ifdef CONFIG_ARCH_OMAP16XX
@@ -1511,6 +1643,13 @@ static int __init _omap_gpio_init(void)
                }
                set_irq_chained_handler(bank->irq, gpio_irq_handler);
                set_irq_data(bank->irq, bank);
+
+               if (cpu_is_omap34xx()) {
+                       sprintf(clk_name, "gpio%d_dbck", i + 1);
+                       bank->dbck = clk_get(NULL, clk_name);
+                       if (IS_ERR(bank->dbck))
+                               printk(KERN_ERR "Could not get %s\n", clk_name);
+               }
        }
 
        /* Enable system clock for GPIO module.
@@ -1627,16 +1766,27 @@ static struct sys_device omap_gpio_device = {
 
 static int workaround_enabled;
 
-void omap2_gpio_prepare_for_retention(void)
+void omap2_gpio_prepare_for_idle(int power_state)
 {
        int i, c = 0;
+       int min = 0;
 
-       /* Remove triggering for all non-wakeup GPIOs.  Otherwise spurious
-        * IRQs will be generated.  See OMAP2420 Errata item 1.101. */
-       for (i = 0; i < gpio_bank_count; i++) {
+       if (cpu_is_omap34xx())
+               min = 1;
+
+       for (i = min; i < gpio_bank_count; i++) {
                struct gpio_bank *bank = &gpio_bank[i];
                u32 l1, l2;
 
+               if (cpu_is_omap34xx() && bank->dbck_enable_mask)
+                       clk_disable(bank->dbck);
+
+               if (power_state > PWRDM_POWER_OFF)
+                       continue;
+
+               /* If going to OFF, remove triggering for all
+                * non-wakeup GPIOs.  Otherwise spurious IRQs will be
+                * generated.  See OMAP2420 Errata item 1.101. */
                if (!(bank->enabled_non_wakeup_gpios))
                        continue;
 #if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
@@ -1648,10 +1798,12 @@ void omap2_gpio_prepare_for_retention(void)
                bank->saved_risingdetect = l2;
                l1 &= ~bank->enabled_non_wakeup_gpios;
                l2 &= ~bank->enabled_non_wakeup_gpios;
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
-               __raw_writel(l1, bank->base + OMAP24XX_GPIO_FALLINGDETECT);
-               __raw_writel(l2, bank->base + OMAP24XX_GPIO_RISINGDETECT);
-#endif
+               if (cpu_is_omap24xx()) {
+                       __raw_writel(l1, bank->base +
+                                       OMAP24XX_GPIO_FALLINGDETECT);
+                       __raw_writel(l2, bank->base +
+                                       OMAP24XX_GPIO_RISINGDETECT);
+               }
                c++;
        }
        if (!c) {
@@ -1661,15 +1813,22 @@ void omap2_gpio_prepare_for_retention(void)
        workaround_enabled = 1;
 }
 
-void omap2_gpio_resume_after_retention(void)
+void omap2_gpio_resume_after_idle(void)
 {
        int i;
+       int min = 0;
 
-       if (!workaround_enabled)
-               return;
-       for (i = 0; i < gpio_bank_count; i++) {
+       if (cpu_is_omap34xx())
+               min = 1;
+       for (i = min; i < gpio_bank_count; i++) {
                struct gpio_bank *bank = &gpio_bank[i];
-               u32 l;
+               u32 l, gen, gen0, gen1;
+
+               if (cpu_is_omap34xx() && bank->dbck_enable_mask)
+                       clk_enable(bank->dbck);
+
+               if (!workaround_enabled)
+                       continue;
 
                if (!(bank->enabled_non_wakeup_gpios))
                        continue;
@@ -1687,14 +1846,33 @@ void omap2_gpio_resume_after_retention(void)
                l = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN);
 #endif
                l ^= bank->saved_datain;
-               l &= bank->non_wakeup_gpios;
-               if (l) {
+               l &= bank->enabled_non_wakeup_gpios;
+
+               /*
+                * No need to generate IRQs for the rising edge for gpio IRQs
+                * configured with falling edge only; and vice versa.
+                */
+               gen0 = l & bank->saved_fallingdetect;
+               gen0 &= bank->saved_datain;
+
+               gen1 = l & bank->saved_risingdetect;
+               gen1 &= ~(bank->saved_datain);
+
+               /* FIXME: Consider GPIO IRQs with level detections properly! */
+               gen = l & (~(bank->saved_fallingdetect) &
+                               ~(bank->saved_risingdetect));
+               /* Consider all GPIO IRQs needed to be updated */
+               gen |= gen0 | gen1;
+
+               if (gen) {
                        u32 old0, old1;
 #if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
                        old0 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0);
                        old1 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1);
-                       __raw_writel(old0 | l, bank->base + OMAP24XX_GPIO_LEVELDETECT0);
-                       __raw_writel(old1 | l, bank->base + OMAP24XX_GPIO_LEVELDETECT1);
+                       __raw_writel(old0 | gen, bank->base +
+                               OMAP24XX_GPIO_LEVELDETECT0);
+                       __raw_writel(old1 | gen, bank->base +
+                               OMAP24XX_GPIO_LEVELDETECT1);
                        __raw_writel(old0, bank->base + OMAP24XX_GPIO_LEVELDETECT0);
                        __raw_writel(old1, bank->base + OMAP24XX_GPIO_LEVELDETECT1);
 #endif
@@ -1705,6 +1883,145 @@ void omap2_gpio_resume_after_retention(void)
 
 #endif
 
+#ifdef CONFIG_ARCH_OMAP34XX
+/* save the registers of bank 2-6 */
+void omap3_gpio_save_context(void)
+{
+       int i;
+       struct gpio_bank *bank;
+       int n;
+       u16 offset, conf;
+       u32 out, pin;
+       struct gpio_pad *pad;
+       u32 tmp_oe[OMAP34XX_NR_GPIOS];
+       /* saving banks from 2-6 only */
+       for (i = 1; i < gpio_bank_count; i++) {
+               bank = &gpio_bank[i];
+               gpio_context[i].sysconfig =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_SYSCONFIG);
+               gpio_context[i].irqenable1 =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE1);
+               gpio_context[i].irqenable2 =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE2);
+               gpio_context[i].wake_en =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_WAKE_EN);
+               gpio_context[i].ctrl =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_CTRL);
+               gpio_context[i].oe =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_OE);
+               tmp_oe[i] = gpio_context[i].oe;
+               gpio_context[i].leveldetect0 =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0);
+               gpio_context[i].leveldetect1 =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1);
+               gpio_context[i].risingdetect =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT);
+               gpio_context[i].fallingdetect =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT);
+               gpio_context[i].dataout =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_DATAOUT);
+       }
+       pad = gpio_pads;
+
+       if (pad == NULL)
+               return;
+
+       while (pad->gpio >= 0) {
+               /* n = gpio number, 0..191 */
+               n = pad->gpio;
+               /* i = gpio bank, 0..5 */
+               i = n >> 5;
+               /* offset of padconf register */
+               offset = pad->offset;
+               bank = &gpio_bank[i];
+               /* bit position of gpio in the bank 0..31 */
+               pin = 1 << (n & 0x1f);
+
+               /* check if gpio is configured as output => need hack */
+               if (!(tmp_oe[i] & pin)) {
+                       /* save current padconf setting */
+                       pad->save = omap_ctrl_readw(offset);
+                       out = gpio_context[i].dataout;
+                       if (out & pin)
+                               /* High: PU + input */
+                               conf = OMAP34XX_PAD_IN_PU_GPIO;
+                       else
+                               /* Low: PD + input */
+                               conf = OMAP34XX_PAD_IN_PD_GPIO;
+                       /* Set PAD to GPIO + input */
+                       omap_ctrl_writew(conf, offset);
+                       /* Set GPIO to input */
+                       tmp_oe[i] |= pin;
+                       __raw_writel(tmp_oe[i],
+                                       bank->base + OMAP24XX_GPIO_OE);
+                       /* Set PAD to safe mode */
+                       omap_ctrl_writew(conf | OMAP34XX_PAD_SAFE_MODE, offset);
+               } else
+                       pad->save = 0;
+               pad++;
+       }
+}
+EXPORT_SYMBOL(omap3_gpio_save_context);
+
+/* restore the required registers of bank 2-6 */
+void omap3_gpio_restore_context(void)
+{
+       int i;
+       for (i = 1; i < gpio_bank_count; i++) {
+               struct gpio_bank *bank = &gpio_bank[i];
+               __raw_writel(gpio_context[i].sysconfig,
+                               bank->base + OMAP24XX_GPIO_SYSCONFIG);
+               __raw_writel(gpio_context[i].irqenable1,
+                               bank->base + OMAP24XX_GPIO_IRQENABLE1);
+               __raw_writel(gpio_context[i].irqenable2,
+                               bank->base + OMAP24XX_GPIO_IRQENABLE2);
+               __raw_writel(gpio_context[i].wake_en,
+                               bank->base + OMAP24XX_GPIO_WAKE_EN);
+               __raw_writel(gpio_context[i].ctrl,
+                               bank->base + OMAP24XX_GPIO_CTRL);
+               __raw_writel(gpio_context[i].leveldetect0,
+                               bank->base + OMAP24XX_GPIO_LEVELDETECT0);
+               __raw_writel(gpio_context[i].leveldetect1,
+                               bank->base + OMAP24XX_GPIO_LEVELDETECT1);
+               __raw_writel(gpio_context[i].risingdetect,
+                               bank->base + OMAP24XX_GPIO_RISINGDETECT);
+               __raw_writel(gpio_context[i].fallingdetect,
+                               bank->base + OMAP24XX_GPIO_FALLINGDETECT);
+               __raw_writel(gpio_context[i].dataout,
+                               bank->base + OMAP24XX_GPIO_DATAOUT);
+               __raw_writel(gpio_context[i].oe,
+                               bank->base + OMAP24XX_GPIO_OE);
+       }
+}
+EXPORT_SYMBOL(omap3_gpio_restore_context);
+
+void omap3_gpio_restore_pad_context(int restore_oe)
+{
+       struct gpio_pad *pad;
+       int i;
+
+       pad = gpio_pads;
+
+       if (restore_oe) {
+               for (i = 1; i < gpio_bank_count; i++) {
+                       struct gpio_bank *bank = &gpio_bank[i];
+                       __raw_writel(gpio_context[i].oe,
+                               bank->base + OMAP24XX_GPIO_OE);
+               }
+       }
+
+       if (pad == NULL)
+               return;
+
+       while (pad->gpio >= 0) {
+               if (pad->save)
+                       omap_ctrl_writew(pad->save, pad->offset);
+               pad++;
+       }
+}
+EXPORT_SYMBOL(omap3_gpio_restore_pad_context);
+#endif
+
 /*
  * This may get called early from board specific init
  * for boards that have interrupts routed via FPGA.
@@ -1739,12 +2056,6 @@ static int __init omap_gpio_sysinit(void)
        return ret;
 }
 
-EXPORT_SYMBOL(omap_request_gpio);
-EXPORT_SYMBOL(omap_free_gpio);
-EXPORT_SYMBOL(omap_set_gpio_direction);
-EXPORT_SYMBOL(omap_set_gpio_dataout);
-EXPORT_SYMBOL(omap_get_gpio_datain);
-
 arch_initcall(omap_gpio_sysinit);
 
 
@@ -1801,14 +2112,14 @@ static int dbg_gpio_show(struct seq_file *s, void *unused)
                                continue;
 
                        irq = bank->virtual_irq_start + j;
-                       value = omap_get_gpio_datain(gpio);
+                       value = gpio_get_value(gpio);
                        is_in = gpio_is_input(bank, mask);
 
                        if (bank_is_mpuio(bank))
                                seq_printf(s, "MPUIO %2d ", j);
                        else
                                seq_printf(s, "GPIO %3d ", gpio);
-                       seq_printf(s, "(%10s): %s %s",
+                       seq_printf(s, "(%-20.20s): %s %s",
                                        label,
                                        is_in ? "in " : "out",
                                        value ? "hi"  : "lo");