#include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/ptrace.h>
+#include <linux/sysdev.h>
+#include <linux/err.h>
 
 #include <asm/hardware.h>
+#include <asm/hardware/clock.h>
 #include <asm/irq.h>
 #include <asm/arch/irqs.h>
 #include <asm/arch/gpio.h>
 #define OMAP1610_GPIO_SYSSTATUS                0x0014
 #define OMAP1610_GPIO_IRQSTATUS1       0x0018
 #define OMAP1610_GPIO_IRQENABLE1       0x001c
+#define OMAP1610_GPIO_WAKEUPENABLE     0x0028
 #define OMAP1610_GPIO_DATAIN           0x002c
 #define OMAP1610_GPIO_DATAOUT          0x0030
 #define OMAP1610_GPIO_DIRECTION                0x0034
 #define OMAP1610_GPIO_EDGE_CTRL1       0x0038
 #define OMAP1610_GPIO_EDGE_CTRL2       0x003c
 #define OMAP1610_GPIO_CLEAR_IRQENABLE1 0x009c
+#define OMAP1610_GPIO_CLEAR_WAKEUPENA  0x00a8
 #define OMAP1610_GPIO_CLEAR_DATAOUT    0x00b0
 #define OMAP1610_GPIO_SET_IRQENABLE1   0x00dc
+#define OMAP1610_GPIO_SET_WAKEUPENA    0x00e8
 #define OMAP1610_GPIO_SET_DATAOUT      0x00f0
 
 /*
        u16 virtual_irq_start;
        u8 method;
        u32 reserved_map;
+       u32 suspend_wakeup;
+       u32 saved_wakeup;
        spinlock_t lock;
 };
 
        _enable_gpio_irqbank(bank, 1 << get_gpio_index(gpio), enable);
 }
 
+/*
+ * Note that ENAWAKEUP needs to be enabled in GPIO_SYSCONFIG register.
+ * 1510 does not seem to have a wake-up register. If JTAG is connected
+ * to the target, system will wake up always on GPIO events. While
+ * system is running all registered GPIO interrupts need to have wake-up
+ * enabled. When system is suspended, only selected GPIO interrupts need
+ * to have wake-up enabled.
+ */
+static void _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
+{
+       switch (bank->method) {
+       case METHOD_GPIO_1610:
+               spin_lock(&bank->lock);
+               if (enable)
+                       bank->suspend_wakeup |= (1 << gpio);
+               else
+                       bank->suspend_wakeup &= ~(1 << gpio);
+               spin_unlock(&bank->lock);
+               break;
+       default:
+               printk(KERN_ERR "Can't enable GPIO wakeup for method %i\n",
+                      bank->method);
+               return;
+       }
+}
+
+/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
+static int gpio_wake_enable(unsigned int irq, unsigned int enable)
+{
+       unsigned int gpio = irq - IH_GPIO_BASE;
+       struct gpio_bank *bank;
+
+       if (check_gpio(gpio) < 0)
+               return -ENODEV;
+       bank = get_gpio_bank(gpio);
+       spin_lock(&bank->lock);
+       _set_gpio_wakeup(bank, get_gpio_index(gpio), enable);
+       spin_unlock(&bank->lock);
+
+       return 0;
+}
+
 int omap_request_gpio(int gpio)
 {
        struct gpio_bank *bank;
                reg = bank->base + OMAP1510_GPIO_PIN_CONTROL;
                __raw_writel(__raw_readl(reg) | (1 << get_gpio_index(gpio)), reg);
        }
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
+       if (bank->method == METHOD_GPIO_1610) {
+               /* Enable wake-up during idle for dynamic tick */
+               u32 reg = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
+               __raw_writel(1 << get_gpio_index(gpio), reg);
+       }
 #endif
        spin_unlock(&bank->lock);
 
                spin_unlock(&bank->lock);
                return;
        }
+#ifdef CONFIG_ARCH_OMAP16XX
+       if (bank->method == METHOD_GPIO_1610) {
+               /* Disable wake-up during idle for dynamic tick */
+               u32 reg = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
+               __raw_writel(1 << get_gpio_index(gpio), reg);
+       }
+#endif
        bank->reserved_map &= ~(1 << get_gpio_index(gpio));
        _set_gpio_direction(bank, get_gpio_index(gpio), 1);
        _set_gpio_irqenable(bank, gpio, 0);
        .ack    = gpio_ack_irq,
        .mask   = gpio_mask_irq,
        .unmask = gpio_unmask_irq,
+       .wake   = gpio_wake_enable,
 };
 
 static struct irqchip mpuio_irq_chip = {
 };
 
 static int initialized = 0;
+static struct clk * gpio_ck = 0;
 
 static int __init _omap_gpio_init(void)
 {
 
        initialized = 1;
 
+       if (cpu_is_omap1510()) {
+               gpio_ck = clk_get(0, "arm_gpio_ck");
+               if (IS_ERR(gpio_ck))
+                       printk("Could not get arm_gpio_ck\n");
+               else
+                       clk_use(gpio_ck);
+       }
+
 #ifdef CONFIG_ARCH_OMAP1510
        if (cpu_is_omap1510()) {
                printk(KERN_INFO "OMAP1510 GPIO hardware\n");
                if (bank->method == METHOD_GPIO_1610) {
                        __raw_writew(0x0000, bank->base + OMAP1610_GPIO_IRQENABLE1);
                        __raw_writew(0xffff, bank->base + OMAP1610_GPIO_IRQSTATUS1);
+                       __raw_writew(0x0014, bank->base + OMAP1610_GPIO_SYSCONFIG);
                }
 #endif
 #ifdef CONFIG_ARCH_OMAP730
        return 0;
 }
 
+#ifdef CONFIG_ARCH_OMAP16XX
+static int omap_gpio_suspend(struct sys_device *dev, u32 state)
+{
+       int i;
+
+       if (cpu_is_omap1510())
+               return 0;
+
+       for (i = 0; i < gpio_bank_count; i++) {
+               struct gpio_bank *bank = &gpio_bank[i];
+               u32 wake_status = bank->base + OMAP1610_GPIO_WAKEUPENABLE;
+               u32 wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
+               u32 wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
+
+               if (bank->method != METHOD_GPIO_1610)
+                       continue;
+
+               spin_lock(&bank->lock);
+               bank->saved_wakeup = __raw_readl(wake_status);
+               __raw_writel(0xffffffff, wake_clear);
+               __raw_writel(bank->suspend_wakeup, wake_set);
+               spin_unlock(&bank->lock);
+       }
+
+       return 0;
+}
+
+static int omap_gpio_resume(struct sys_device *dev)
+{
+       int i;
+
+       if (cpu_is_omap1510())
+               return 0;
+
+       for (i = 0; i < gpio_bank_count; i++) {
+               struct gpio_bank *bank = &gpio_bank[i];
+               u32 wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
+               u32 wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
+
+               if (bank->method != METHOD_GPIO_1610)
+                       continue;
+
+               spin_lock(&bank->lock);
+               __raw_writel(0xffffffff, wake_clear);
+               __raw_writel(bank->saved_wakeup, wake_set);
+               spin_unlock(&bank->lock);
+       }
+
+       return 0;
+}
+
+static struct sysdev_class omap_gpio_sysclass = {
+       set_kset_name("gpio"),
+       .suspend        = omap_gpio_suspend,
+       .resume         = omap_gpio_resume,
+};
+
+static struct sys_device omap_gpio_device = {
+       .id             = 0,
+       .cls            = &omap_gpio_sysclass,
+};
+#endif
+
 /*
  * This may get called early from board specific init
  */
                return 0;
 }
 
+static int __init omap_gpio_sysinit(void)
+{
+       int ret = 0;
+
+       if (!initialized)
+               ret = _omap_gpio_init();
+
+#ifdef CONFIG_ARCH_OMAP16XX
+       if (cpu_is_omap16xx()) {
+               if (ret == 0) {
+                       ret = sysdev_class_register(&omap_gpio_sysclass);
+                       if (ret == 0)
+                               ret = sysdev_register(&omap_gpio_device);
+               }
+       }
+#endif
+
+       return ret;
+}
+
 EXPORT_SYMBOL(omap_request_gpio);
 EXPORT_SYMBOL(omap_free_gpio);
 EXPORT_SYMBOL(omap_set_gpio_direction);
 EXPORT_SYMBOL(omap_get_gpio_datain);
 EXPORT_SYMBOL(omap_set_gpio_edge_ctrl);
 
-arch_initcall(omap_gpio_init);
+arch_initcall(omap_gpio_sysinit);