diff options
-rw-r--r-- | arch/arm/mach-omap2/pm44xx.c | 4 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/gpio.h | 2 | ||||
-rw-r--r-- | drivers/gpio/gpio-omap.c | 47 |
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) { |