diff options
author | Colin Cross <ccross@android.com> | 2011-11-10 13:27:35 -0800 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2011-11-14 14:16:10 -0800 |
commit | 2d03048f3b7f5dcb05950104671cdfc0fb71bb4b (patch) | |
tree | 8db59bee109d58430e7f6db9efacfd182ab7027e /drivers/gpio | |
parent | 9d0c08e33acd82871d6b1ee7bfa19801d8306aa2 (diff) | |
download | kernel_samsung_tuna-2d03048f3b7f5dcb05950104671cdfc0fb71bb4b.zip kernel_samsung_tuna-2d03048f3b7f5dcb05950104671cdfc0fb71bb4b.tar.gz kernel_samsung_tuna-2d03048f3b7f5dcb05950104671cdfc0fb71bb4b.tar.bz2 |
gpio: omap: fix gpio transitions to off mode
When transitioning to off mode, it is possible that the powerdomain
that contains the gpio block does not transition due to another
clock domain being on. In this case, we must do the same
configuration on the gpios as in the non-off mode case.
Modify omap2_gpio_set_edge_wakeup to use different variables
to save context vs. omap_save_context, and both set the edge
wakeups and call pm_runtime_put_sync when going to off mode.
Change-Id: I2890f7f3dd2c3dfe493cf748a523004a76e560c2
Signed-off-by: Colin Cross <ccross@android.com>
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/gpio-omap.c | 53 |
1 files changed, 27 insertions, 26 deletions
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 5b45bc1..a5ca770 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -49,6 +49,10 @@ struct gpio_regs { u32 debounce_en; u32 edge_falling; u32 edge_rising; + + u32 ew_leveldetect0; + u32 ew_leveldetect1; + u32 pad_set_wakeupenable; }; @@ -1440,9 +1444,9 @@ static int omap2_gpio_set_edge_wakeup(struct gpio_bank *bank) return -EINVAL; } - bank->context.leveldetect0 = __raw_readl(bank->base + + bank->context.ew_leveldetect0 = __raw_readl(bank->base + bank->regs->leveldetect0); - bank->context.leveldetect1 = __raw_readl(bank->base + + bank->context.ew_leveldetect1 = __raw_readl(bank->base + bank->regs->leveldetect1); wkup_status = __raw_readl(bank->base + bank->regs->wkup_status); @@ -1457,10 +1461,10 @@ static int omap2_gpio_set_edge_wakeup(struct gpio_bank *bank) * even if they are set for level detection only. */ __raw_writel(bank->context.edge_falling | - (bank->context.leveldetect0 & wkup_status), + (bank->context.ew_leveldetect0 & wkup_status), (bank->base + bank->regs->fallingdetect)); __raw_writel(bank->context.edge_rising | - (bank->context.leveldetect1 & wkup_status), + (bank->context.ew_leveldetect1 & wkup_status), (bank->base + bank->regs->risingdetect)); __raw_writel(0, bank->base + bank->regs->leveldetect0); __raw_writel(0, bank->base + bank->regs->leveldetect1); @@ -1473,8 +1477,8 @@ 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.leveldetect1) || - (~datain & bank->context.leveldetect0)) + if ((datain & bank->context.ew_leveldetect1) || + (~datain & bank->context.ew_leveldetect0)) ret = -EBUSY; if (pm_runtime_put_sync_suspend(bank->dev) < 0) { @@ -1498,9 +1502,9 @@ static void omap2_gpio_restore_edge_wakeup(struct gpio_bank *bank) (bank->base + bank->regs->fallingdetect)); __raw_writel(bank->context.edge_rising, (bank->base + bank->regs->risingdetect)); - __raw_writel(bank->context.leveldetect0, + __raw_writel(bank->context.ew_leveldetect0, (bank->base + bank->regs->leveldetect0)); - __raw_writel(bank->context.leveldetect1, + __raw_writel(bank->context.ew_leveldetect1, (bank->base + bank->regs->leveldetect1)); if (pm_runtime_put_sync_suspend(bank->dev) < 0) { @@ -1518,16 +1522,14 @@ int omap2_gpio_prepare_for_idle(int off_mode) list_for_each_entry(bank, &omap_gpio_list, node) { omap2_gpio_set_wakeupenables(bank); - if (!bank->mod_usage || !bank->loses_context || !off_mode) { - if (omap2_gpio_set_edge_wakeup(bank)) - ret = -EBUSY; - continue; - } + if (omap2_gpio_set_edge_wakeup(bank)) + ret = -EBUSY; - if (pm_runtime_put_sync_suspend(bank->dev) < 0) - dev_err(bank->dev, "%s: GPIO bank %d " - "pm_runtime_put_sync failed\n", - __func__, bank->id); + if (bank->mod_usage && bank->loses_context && off_mode) + if (pm_runtime_put_sync_suspend(bank->dev) < 0) + dev_err(bank->dev, "%s: GPIO bank %d " + "pm_runtime_put_sync failed\n", + __func__, bank->id); } if (ret) @@ -1541,18 +1543,17 @@ void omap2_gpio_resume_after_idle(int off_mode) struct gpio_bank *bank; list_for_each_entry(bank, &omap_gpio_list, node) { - omap2_gpio_clear_wakeupenables(bank); + if (bank->mod_usage && bank->loses_context && off_mode) + if (pm_runtime_get_sync(bank->dev) < 0) + dev_err(bank->dev, "%s: GPIO bank %d " + "pm_runtime_get_sync failed\n", + __func__, bank->id); - if (!bank->mod_usage || !bank->loses_context || !off_mode) { - omap2_gpio_restore_edge_wakeup(bank); - continue; - } + omap2_gpio_restore_edge_wakeup(bank); - if (pm_runtime_get_sync(bank->dev) < 0) - dev_err(bank->dev, "%s: GPIO bank %d " - "pm_runtime_get_sync failed\n", - __func__, bank->id); + omap2_gpio_clear_wakeupenables(bank); } + } void omap_gpio_save_context(struct gpio_bank *bank) { |