aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-omap2/pm44xx.c2
-rw-r--r--arch/arm/plat-omap/include/plat/gpio.h2
-rw-r--r--drivers/gpio/gpio-omap.c44
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)