[PATCH] gpio/omap: fix wakeups on level-triggered GPIOs

DebBarma, Tarun Kanti tarun.kanti at ti.com
Wed Feb 22 12:17:35 EST 2012


On Wed, Feb 22, 2012 at 12:31 AM, Kevin Hilman <khilman at ti.com> wrote:
> 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 at atomide.com>
> Signed-off-by: Kevin Hilman <khilman at ti.com>

I have tested on OMAP3430 by making modification to touchscreen GPIO.
(I had similar change in my next planned cleanup/fix series.)
If needed you can add my Tested-by:
--
Tarun

> ---
> This applies on top of the GPIO cleanup and runtime PM conversion series
> which has been submitted for v3.4 and also available here:
> git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-omap-pm.git for_3.4/gpio/runtime-pm-cleanup
>
>  drivers/gpio/gpio-omap.c |   34 ++++++++++++++++++++++++++++++++++
>  1 files changed, 34 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
> index f49bd6f..752ae9b 100644
> --- a/drivers/gpio/gpio-omap.c
> +++ b/drivers/gpio/gpio-omap.c
> @@ -1196,8 +1196,30 @@ static int omap_gpio_runtime_suspend(struct device *dev)
>        struct gpio_bank *bank = platform_get_drvdata(pdev);
>        u32 l1 = 0, l2 = 0;
>        unsigned long flags;
> +       u32 wake_low, wake_hi;
>
>        spin_lock_irqsave(&bank->lock, flags);
> +
> +       /*
> +        * Only edges can generate a wakeup event to the PRCM.
> +        *
> +        * Therefore, ensure any wake-up capable GPIOs have
> +        * edge-detection enabled before going idle to ensure a wakeup
> +        * to the PRCM is generated on a GPIO transition. (c.f. 34xx
> +        * NDA TRM 25.5.3.1)
> +        *
> +        * The normal values will be restored upon ->runtime_resume()
> +        * by writing back the values saved in bank->context.
> +        */
> +       wake_low = bank->context.leveldetect0 & bank->context.wake_en;
> +       if (wake_low)
> +               __raw_writel(wake_low | bank->context.fallingdetect,
> +                            bank->base + bank->regs->fallingdetect);
> +       wake_hi = bank->context.leveldetect1 & bank->context.wake_en;
> +       if (wake_hi)
> +               __raw_writel(wake_hi | bank->context.risingdetect,
> +                            bank->base + bank->regs->risingdetect);
> +
>        if (bank->power_mode != OFF_MODE) {
>                bank->power_mode = 0;
>                goto update_gpio_context_count;
> @@ -1246,6 +1268,18 @@ static int omap_gpio_runtime_resume(struct device *dev)
>
>        spin_lock_irqsave(&bank->lock, flags);
>        _gpio_dbck_enable(bank);
> +
> +       /*
> +        * In ->runtime_suspend(), level-triggered, wakeup-enabled
> +        * GPIOs were set to edge trigger also in order to be able to
> +        * generate a PRCM wakeup.  Here we restore the
> +        * pre-runtime_suspend() values for edge triggering.
> +        */
> +       __raw_writel(bank->context.fallingdetect,
> +                    bank->base + bank->regs->fallingdetect);
> +       __raw_writel(bank->context.risingdetect,
> +                    bank->base + bank->regs->risingdetect);
> +
>        if (!bank->enabled_non_wakeup_gpios || !bank->workaround_enabled) {
>                spin_unlock_irqrestore(&bank->lock, flags);
>                return 0;
> --
> 1.7.9
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



More information about the linux-arm-kernel mailing list