aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2011-11-10 13:27:35 -0800
committerColin Cross <ccross@android.com>2011-11-14 14:16:10 -0800
commit2d03048f3b7f5dcb05950104671cdfc0fb71bb4b (patch)
tree8db59bee109d58430e7f6db9efacfd182ab7027e /drivers/gpio
parent9d0c08e33acd82871d6b1ee7bfa19801d8306aa2 (diff)
downloadkernel_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.c53
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)
{