aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-omap2/pm44xx.c4
-rw-r--r--arch/arm/plat-omap/include/plat/gpio.h2
-rw-r--r--drivers/gpio/gpio-omap.c47
3 files changed, 53 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 7e2b3c8..8ffc139 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -165,6 +165,8 @@ void omap4_enter_sleep(unsigned int cpu, unsigned int power_state, bool suspend)
}
}
+ omap2_gpio_set_edge_wakeup();
+
if (omap4_device_next_state_off()) {
omap2_gpio_prepare_for_idle(true);
omap_gpmc_save_context();
@@ -233,6 +235,8 @@ abort_device_off:
OMAP4430_PRM_DEVICE_INST, OMAP4_PRM_IO_PMCTRL_OFFSET);
}
+ omap2_gpio_restore_edge_wakeup();
+
if (mpu_next_state < PWRDM_POWER_INACTIVE) {
omap_vc_set_auto_trans(mpu_voltdm,
OMAP_VC_CHANNEL_AUTO_TRANSITION_DISABLE);
diff --git a/arch/arm/plat-omap/include/plat/gpio.h b/arch/arm/plat-omap/include/plat/gpio.h
index 24b61af..89af4ad 100644
--- a/arch/arm/plat-omap/include/plat/gpio.h
+++ b/arch/arm/plat-omap/include/plat/gpio.h
@@ -217,6 +217,8 @@ extern void omap2_gpio_prepare_for_idle(int off_mode);
extern void omap2_gpio_resume_after_idle(void);
extern void omap_set_gpio_debounce(int gpio, int enable);
extern void omap_set_gpio_debounce_time(int gpio, int enable);
+extern void omap2_gpio_set_edge_wakeup(void);
+extern void omap2_gpio_restore_edge_wakeup(void);
/*-------------------------------------------------------------------------*/
/* Wrappers for "new style" GPIO calls, using the new infrastructure
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index a06a054..312d45d 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -44,6 +44,8 @@ struct gpio_regs {
u32 dataout;
u32 debounce;
u32 debounce_en;
+ u32 edge_falling;
+ u32 edge_rising;
};
struct gpio_bank {
@@ -1383,6 +1385,51 @@ static int omap_gpio_pm_runtime_resume(struct device *dev)
}
#ifdef CONFIG_ARCH_OMAP2PLUS
+void omap2_gpio_set_edge_wakeup(void)
+{
+ struct gpio_bank *bank;
+
+ list_for_each_entry(bank, &omap_gpio_list, node) {
+ u32 level_low = 0;
+ u32 level_high = 0;
+ u32 wkup_status = 0;
+
+ level_low = __raw_readl(bank->base +
+ bank->regs->leveldetect0);
+ level_high = __raw_readl(bank->base +
+ bank->regs->leveldetect1);
+ wkup_status = __raw_readl(bank->base +
+ bank->regs->wkup_status);
+ bank->context.edge_falling = __raw_readl(bank->base +
+ bank->regs->fallingdetect);
+ bank->context.edge_rising = __raw_readl(bank->base +
+ bank->regs->risingdetect);
+
+ /*
+ * Set edge trigger for all gpio's that are
+ * expected to produce wakeup from low power.
+ * even if they are set for level detection only.
+ */
+ __raw_writel((bank->context.edge_falling | level_low) & wkup_status,
+ (bank->base + bank->regs->fallingdetect));
+ __raw_writel((bank->context.edge_rising | level_high) & wkup_status,
+ (bank->base + bank->regs->risingdetect));
+
+ }
+}
+
+void omap2_gpio_restore_edge_wakeup(void)
+{
+ struct gpio_bank *bank;
+
+ list_for_each_entry(bank, &omap_gpio_list, node) {
+ /* restore edge setting */
+ __raw_writel(bank->context.edge_falling,
+ (bank->base + bank->regs->fallingdetect));
+ __raw_writel(bank->context.edge_rising,
+ (bank->base + bank->regs->risingdetect));
+ }
+}
void omap2_gpio_prepare_for_idle(int off_mode)
{