diff options
-rw-r--r-- | arch/arm/mach-omap2/pm44xx.c | 2 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/gpio.h | 2 | ||||
-rw-r--r-- | drivers/gpio/gpio-omap.c | 44 |
3 files changed, 41 insertions, 7 deletions
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c index 4d0efab..302997e 100644 --- a/arch/arm/mach-omap2/pm44xx.c +++ b/arch/arm/mach-omap2/pm44xx.c @@ -137,7 +137,7 @@ void omap4_enter_sleep(unsigned int cpu, unsigned int power_state, bool suspend) core_next_state = pwrdm_read_next_pwrst(core_pwrdm); mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); - ret = omap2_gpio_prepare_for_idle(omap4_device_next_state_off()); + ret = omap2_gpio_prepare_for_idle(omap4_device_next_state_off(), suspend); if (ret) goto abort_gpio; diff --git a/arch/arm/plat-omap/include/plat/gpio.h b/arch/arm/plat-omap/include/plat/gpio.h index 0b1f7c5..90eae5c 100644 --- a/arch/arm/plat-omap/include/plat/gpio.h +++ b/arch/arm/plat-omap/include/plat/gpio.h @@ -213,7 +213,7 @@ struct omap_gpio_platform_data { struct omap_gpio_reg_offs *regs; }; -extern int omap2_gpio_prepare_for_idle(int off_mode); +extern int omap2_gpio_prepare_for_idle(int off_mode, bool suspend); extern void omap2_gpio_resume_after_idle(int off_mode); extern void omap_set_gpio_debounce(int gpio, int enable); extern void omap_set_gpio_debounce_time(int gpio, int enable); diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index a5ca770..159b3d9 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -87,6 +87,11 @@ struct gpio_bank { u32 width; u16 id; + u32 type_leveldetect0; + u32 type_leveldetect1; + u32 type_risingedge; + u32 type_fallingedge; + void (*set_dataout)(struct gpio_bank *bank, int gpio, int enable); struct omap_gpio_reg_offs *regs; @@ -378,7 +383,23 @@ static int gpio_irq_type(struct irq_data *d, unsigned type) return -EINVAL; spin_lock_irqsave(&bank->lock, flags); + retval = _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), type); + + bank->type_leveldetect0 &= ~GPIO_BIT(bank, gpio); + bank->type_leveldetect1 &= ~GPIO_BIT(bank, gpio); + bank->type_fallingedge &= ~GPIO_BIT(bank, gpio); + bank->type_risingedge &= ~GPIO_BIT(bank, gpio); + + if (type & IRQ_TYPE_LEVEL_LOW) + bank->type_leveldetect0 |= GPIO_BIT(bank, gpio); + if (type & IRQ_TYPE_LEVEL_HIGH) + bank->type_leveldetect1 |= GPIO_BIT(bank, gpio); + if (type & IRQ_TYPE_EDGE_FALLING) + bank->type_fallingedge |= GPIO_BIT(bank, gpio); + if (type & IRQ_TYPE_EDGE_RISING) + bank->type_risingedge |= GPIO_BIT(bank, gpio); + spin_unlock_irqrestore(&bank->lock, flags); if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) @@ -1432,11 +1453,13 @@ static int omap_gpio_pm_runtime_resume(struct device *dev) } #ifdef CONFIG_ARCH_OMAP2PLUS -static int omap2_gpio_set_edge_wakeup(struct gpio_bank *bank) +static int omap2_gpio_set_edge_wakeup(struct gpio_bank *bank, bool suspend) { int ret = 0; u32 wkup_status = 0; u32 datain; + u32 mask; + u32 active; if (pm_runtime_get_sync(bank->dev) < 0) { dev_err(bank->dev, "%s: GPIO bank %d pm_runtime_get_sync " @@ -1477,9 +1500,20 @@ static int omap2_gpio_set_edge_wakeup(struct gpio_bank *bank) * interrupt mask. */ datain = __raw_readl(bank->base + bank->regs->datain); - if ((datain & bank->context.ew_leveldetect1) || - (~datain & bank->context.ew_leveldetect0)) + if (suspend) + mask = bank->suspend_wakeup; + else + mask = wkup_status; + + active = (datain & bank->type_leveldetect1 & mask) | + (~datain & bank->type_leveldetect0 & mask); + + if (active) { + if (suspend) + pr_info("%s: aborted suspend due to gpio %d\n", + __func__, bank->id * bank->width + __ffs(active)); ret = -EBUSY; + } if (pm_runtime_put_sync_suspend(bank->dev) < 0) { dev_err(bank->dev, "%s: GPIO bank %d pm_runtime_put_sync " @@ -1514,7 +1548,7 @@ static void omap2_gpio_restore_edge_wakeup(struct gpio_bank *bank) } } -int omap2_gpio_prepare_for_idle(int off_mode) +int omap2_gpio_prepare_for_idle(int off_mode, bool suspend) { int ret = 0; struct gpio_bank *bank; @@ -1522,7 +1556,7 @@ int omap2_gpio_prepare_for_idle(int off_mode) list_for_each_entry(bank, &omap_gpio_list, node) { omap2_gpio_set_wakeupenables(bank); - if (omap2_gpio_set_edge_wakeup(bank)) + if (omap2_gpio_set_edge_wakeup(bank, suspend)) ret = -EBUSY; if (bank->mod_usage && bank->loses_context && off_mode) |