==== LOG FROM CONSOLE ====

[root@OMAP3EVM /]# echo 1 > /sys/power/enable_off_mode
[root@OMAP3EVM /]#
[root@OMAP3EVM /]#
[root@OMAP3EVM /]# echo mem > /sys/power/state
PM: Syncing filesystems ... done.
Freezing user space processes ... (elapsed 0.00 seconds) done.
Freezing remaining freezable tasks ... (elapsed 0.05 seconds) done.
Suspending console(s) (use no_console_suspend to debug)
twl4030_keypad twl4030_keypad: suspending...
Successfully put all powerdomains to target state
twl4030_keypad twl4030_keypad: resuming...
------------[ cut here ]------------
WARNING: at kernel/irq/manage.c:356 set_irq_wake+0x78/0xdc()
Unbalanced IRQ 369 wake disable
Modules linked in:
[<c002f408>] (unwind_backtrace+0x0/0xdc) from [<c0053f6c>] (warn_slowpath_common+0x48/0x60)
[<c0053f6c>] (warn_slowpath_common+0x48/0x60) from [<c0053fbc>] (warn_slowpath_fmt+0x24/0x30)
[<c0053fbc>] (warn_slowpath_fmt+0x24/0x30) from [<c00798a8>] (set_irq_wake+0x78/0xdc)
[<c00798a8>] (set_irq_wake+0x78/0xdc) from [<c01f1ef4>] (twl4030_kp_resume+0x44/0x98)
[<c01f1ef4>] (twl4030_kp_resume+0x44/0x98) from [<c01bb474>] (platform_pm_resume+0x48/0x54)
[<c01bb474>] (platform_pm_resume+0x48/0x54) from [<c01bd07c>] (pm_op+0x4c/0x74)
[<c01bd07c>] (pm_op+0x4c/0x74) from [<c01bd6f0>] (dpm_resume_end+0x80/0x328)
[<c01bd6f0>] (dpm_resume_end+0x80/0x328) from [<c0077ca8>] (suspend_devices_and_enter+0x150/0x18c)
[<c0077ca8>] (suspend_devices_and_enter+0x150/0x18c) from [<c0077d90>] (enter_state+0xac/0xec)
[<c0077d90>] (enter_state+0xac/0xec) from [<c0077518>] (state_store+0x94/0xbc)
[<c0077518>] (state_store+0x94/0xbc) from [<c0176050>] (kobj_attr_store+0x18/0x1c)
[<c0176050>] (kobj_attr_store+0x18/0x1c) from [<c00e5124>] (sysfs_write_file+0x108/0x13c)
[<c00e5124>] (sysfs_write_file+0x108/0x13c) from [<c00a2468>] (vfs_write+0xac/0x154)
[<c00a2468>] (vfs_write+0xac/0x154) from [<c00a25bc>] (sys_write+0x3c/0x68)
[<c00a25bc>] (sys_write+0x3c/0x68) from [<c0029dc0>] (ret_fast_syscall+0x0/0x2c)
---[ end trace 54f593fa7172d35d ]---
Restarting tasks ... done.
[root@OMAP3EVM /]#
[root@OMAP3EVM /]#
[root@OMAP3EVM /]#

==== PATCH ====

diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index 8283215..d485f23 100755
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -55,7 +55,9 @@
 
 #include "sdram-micron-mt46h32m32lf-6.h"
 #include "mmc-twl4030.h"
+#include "prm.h"
 #include "pm.h"
+#include "prm-regbits-34xx.h"
 #include "omap3-opp.h"
 #include "board-omap3evm-camera.h"
 
@@ -742,6 +744,13 @@ static void __init omap3_evm_init(void)
 
 	omap35x_pmic_init();
 
+#ifdef CONFIG_PM
+	omap3evm_kp_data.wk_st		= OMAP34XX_PRM_REGADDR(WKUP_MOD, PM_WKEN1);
+	omap3evm_kp_data.wk_en		= OMAP34XX_PRM_REGADDR(WKUP_MOD, PM_WKST1);
+	omap3evm_kp_data.wk_mask	= (1 << 3);
+	omap3evm_kp_data.padconf	= 0x1e0 ;
+#endif
+
 	omap3_evm_i2c_init();
 
 	platform_add_devices(omap3_evm_devices, ARRAY_SIZE(omap3_evm_devices));
diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c
index 9a60979..d16a1cf 100644
--- a/drivers/input/keyboard/twl4030_keypad.c
+++ b/drivers/input/keyboard/twl4030_keypad.c
@@ -32,7 +32,9 @@
 #include <linux/input.h>
 #include <linux/platform_device.h>
 #include <linux/i2c/twl4030.h>
+#include <linux/io.h>
 #include <mach/keypad.h>
+#include <mach/control.h>
 
 /*
  * The TWL4030 family chips include a keypad controller that supports
@@ -315,6 +317,7 @@ static int __devinit twl4030_kp_probe(struct platform_device *pdev)
 	if (!kp)
 		return -ENOMEM;
 
+	device_init_wakeup(&pdev->dev, 1);
 	platform_set_drvdata(pdev, kp);
 
 	/* Get the debug Device */
@@ -458,6 +461,68 @@ static int __devexit twl4030_kp_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int twl4030_kp_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct twl4030_keypad *kp = platform_get_drvdata(pdev);
+	struct twl4030_keypad_data *pdata = pdev->dev.platform_data;
+
+	/* JUST FOR DEBUG */
+	dev_err(&pdev->dev, "suspending...");
+
+	/* Set wake-enable bit */
+	if (pdata->wk_en && pdata->wk_mask) {
+		u32 v = __raw_readl(pdata->wk_en);
+		v |= pdata->wk_mask;
+		__raw_writel(v, pdata->wk_en);
+	}
+
+	/* Ensure IOPAD wake-enables are set */
+	if (cpu_is_omap34xx() && pdata->padconf) {
+		u16 v = omap_ctrl_readw(pdata->padconf);
+		v |= OMAP3_PADCONF_WAKEUPENABLE0;
+		omap_ctrl_writew(v, pdata->padconf);
+	}
+
+	if (device_may_wakeup(&pdev->dev))
+		enable_irq_wake(kp->irq);
+
+	return 0;
+}
+
+static int twl4030_kp_resume(struct platform_device *pdev)
+{
+	struct twl4030_keypad *kp = platform_get_drvdata(pdev);
+	struct twl4030_keypad_data *pdata = pdev->dev.platform_data;
+
+	/* JUST FOR DEBUG */
+	dev_err(&pdev->dev, "resuming...");
+
+	if (device_may_wakeup(&pdev->dev))
+		disable_irq_wake(kp->irq);
+
+	/* Clear wake-enable bit */
+	if (pdata->wk_en && pdata->wk_mask) {
+		u32 v = __raw_readl(pdata->wk_en);
+		v &= ~pdata->wk_mask;
+		__raw_writel(v, pdata->wk_en);
+	}
+
+	/* Ensure IOPAD wake-enables are cleared */
+	if (cpu_is_omap34xx() && pdata->padconf) {
+		u16 v = omap_ctrl_readw(pdata->padconf);
+		v &= ~OMAP3_PADCONF_WAKEUPENABLE0;
+		omap_ctrl_writew(v, pdata->padconf);
+	}
+
+	return 0;
+}
+#else
+#define twl4030_kp_suspend	NULL
+#define twl4030_kp_resume	NULL
+#endif
+
+
 /*
  * NOTE: twl4030 are multi-function devices connected via I2C.
  * So this device is a child of an I2C parent, thus it needs to
@@ -469,6 +534,8 @@ MODULE_ALIAS("platform:twl4030_keypad");
 static struct platform_driver twl4030_kp_driver = {
 	.probe		= twl4030_kp_probe,
 	.remove		= __devexit_p(twl4030_kp_remove),
+	.suspend        = twl4030_kp_suspend,
+	.resume         = twl4030_kp_resume,
 	.driver		= {
 		.name	= "twl4030_keypad",
 		.owner	= THIS_MODULE,
diff --git a/include/linux/i2c/twl4030.h b/include/linux/i2c/twl4030.h
index 9633be2..03925df 100644
--- a/include/linux/i2c/twl4030.h
+++ b/include/linux/i2c/twl4030.h
@@ -352,6 +352,12 @@ struct twl4030_keypad_data {
 	int irq;
 	unsigned int keymapsize;
 	unsigned int rep:1;
+#ifdef CONFIG_PM
+	void __iomem *wk_st;
+	void __iomem *wk_en;
+	u32 wk_mask;
+	u32 padconf;
+#endif
 };
 
 enum twl4030_usb_mode {
