aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpio-omap.c
diff options
context:
space:
mode:
authorKevin Hilman <khilman@ti.com>2012-03-05 18:10:04 -0500
committerGrant Likely <grant.likely@secretlab.ca>2012-03-12 12:16:11 -0400
commit68942edb09f69b6e09522d1d346665eb3aadde49 (patch)
treed274bac19fdd5c0c46a67e8410960a16bf0c205a /drivers/gpio/gpio-omap.c
parente2aa4177264c1a459779d6e35fae22adf17a9232 (diff)
gpio/omap: fix wakeups on level-triggered GPIOs
While both level- and edge-triggered GPIOs are capable of generating interrupts, only edge-triggered GPIOs are capable of generating a module-level wakeup to the PRCM (c.f. 34xx NDA TRM section 25.5.3.2.) In order to ensure that devices using level-triggered GPIOs as interrupts can also cause wakeups (e.g. from idle), this patch enables edge-triggering for wakeup-enabled, level-triggered GPIOs when a GPIO bank is runtime-suspended (which also happens during idle.) This fixes a problem found in GPMC-connected network cards with GPIO interrupts (e.g. smsc911x on Zoom3, Overo, ...) where network booting with NFSroot was very slow since the GPIO IRQs used by the NIC were not generating PRCM wakeups, and thus not waking the system from idle. NOTE: until v3.3, this boot-time problem was somewhat masked because the UART init prevented WFI during boot until the full serial driver was available. Preventing WFI allowed regular GPIO interrupts to fire and this problem was not seen. After the UART runtime PM cleanups, we no longer avoid WFI during boot, so GPIO IRQs that were not causing wakeups resulted in very slow IRQ response times. Tested on platforms using level-triggered GPIOs for network IRQs using the SMSC911x NIC: 3530/Overo and 3630/Zoom3. Reported-by: Tony Lindgren <tony@atomide.com> Tested-by: Tarun Kanti DebBarma <tarun.kanti@ti.com> Tested-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Kevin Hilman <khilman@ti.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/gpio/gpio-omap.c')
-rw-r--r--drivers/gpio/gpio-omap.c34
1 files changed, 34 insertions, 0 deletions
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index afef0f7c8adf..c48de8ffe9ef 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -1206,8 +1206,30 @@ static int omap_gpio_runtime_suspend(struct device *dev)
1206 struct gpio_bank *bank = platform_get_drvdata(pdev); 1206 struct gpio_bank *bank = platform_get_drvdata(pdev);
1207 u32 l1 = 0, l2 = 0; 1207 u32 l1 = 0, l2 = 0;
1208 unsigned long flags; 1208 unsigned long flags;
1209 u32 wake_low, wake_hi;
1209 1210
1210 spin_lock_irqsave(&bank->lock, flags); 1211 spin_lock_irqsave(&bank->lock, flags);
1212
1213 /*
1214 * Only edges can generate a wakeup event to the PRCM.
1215 *
1216 * Therefore, ensure any wake-up capable GPIOs have
1217 * edge-detection enabled before going idle to ensure a wakeup
1218 * to the PRCM is generated on a GPIO transition. (c.f. 34xx
1219 * NDA TRM 25.5.3.1)
1220 *
1221 * The normal values will be restored upon ->runtime_resume()
1222 * by writing back the values saved in bank->context.
1223 */
1224 wake_low = bank->context.leveldetect0 & bank->context.wake_en;
1225 if (wake_low)
1226 __raw_writel(wake_low | bank->context.fallingdetect,
1227 bank->base + bank->regs->fallingdetect);
1228 wake_hi = bank->context.leveldetect1 & bank->context.wake_en;
1229 if (wake_hi)
1230 __raw_writel(wake_hi | bank->context.risingdetect,
1231 bank->base + bank->regs->risingdetect);
1232
1211 if (bank->power_mode != OFF_MODE) { 1233 if (bank->power_mode != OFF_MODE) {
1212 bank->power_mode = 0; 1234 bank->power_mode = 0;
1213 goto update_gpio_context_count; 1235 goto update_gpio_context_count;
@@ -1256,6 +1278,18 @@ static int omap_gpio_runtime_resume(struct device *dev)
1256 1278
1257 spin_lock_irqsave(&bank->lock, flags); 1279 spin_lock_irqsave(&bank->lock, flags);
1258 _gpio_dbck_enable(bank); 1280 _gpio_dbck_enable(bank);
1281
1282 /*
1283 * In ->runtime_suspend(), level-triggered, wakeup-enabled
1284 * GPIOs were set to edge trigger also in order to be able to
1285 * generate a PRCM wakeup. Here we restore the
1286 * pre-runtime_suspend() values for edge triggering.
1287 */
1288 __raw_writel(bank->context.fallingdetect,
1289 bank->base + bank->regs->fallingdetect);
1290 __raw_writel(bank->context.risingdetect,
1291 bank->base + bank->regs->risingdetect);
1292
1259 if (!bank->enabled_non_wakeup_gpios || !bank->workaround_enabled) { 1293 if (!bank->enabled_non_wakeup_gpios || !bank->workaround_enabled) {
1260 spin_unlock_irqrestore(&bank->lock, flags); 1294 spin_unlock_irqrestore(&bank->lock, flags);
1261 return 0; 1295 return 0;