Message ID | 20180910200624.4494-1-tony@atomide.com |
---|---|
State | New |
Headers | show |
Series | gpio: omap: Add level wakeup handling for omap4 based SoCs | expand |
Hi Tony, On 09/10/2018 03:06 PM, Tony Lindgren wrote: > I noticed that unlike omap2 and 3 based SoCs, omap4 based SoCs keep > the GPIO clocks enabled for GPIO level interrupts with wakeup enabled. > This blocks deeper idle states as the whole domain will stay busy. > > The GPIO clock seems to stay enabled if the wakeup register is enabled > and a level interrupt is triggered. In that case the only way to have > the GPIO module idle is to reset it. It is possible this has gone > unnoticed with OSWR (Open SWitch Retention) and off mode during idle > resetting GPIO context most GPIO instances in the earlier Android trees > for example. > > Looks like the way to deal with this is to have omap4 based SoCs > only set wake for the duration of idle and clear level registers for > the idle. With level interrupts we can do this as the level interrupt > from device will be still there on resume. > > I've taken the long path to fixing this to avoid yet more hard to > read code. I've set up a quirks flag, and a struct for function > pointers so we can use these to clean up other quirk handling easier > in the later patches. The current level quirk handling is moved to > the new functions. I agree with patch in general as it seems will not break anything and change localized for omap4 only. But I'd be very appreciated if you can provide more information about issue which helps better understand it, so could you, if possible, collect dump of: - GPIO bank regs right before entering WFI state in Idle (or as close as possible) I'm interesting in sysc/s, ctrl, irq's regs (+wakupen) and GPIO_DEBOUNCEN first of all - GPIO bank CLKCTRL registers (is it "in transition" state). in non working case. > > Cc: Grygorii Strashko <grygorii.strashko@ti.com> > Cc: Keerthy <j-keerthy@ti.com> > Cc: Tero Kristo <t-kristo@ti.com> > Signed-off-by: Tony Lindgren <tony@atomide.com> > --- > drivers/gpio/gpio-omap.c | 145 ++++++++++++++++++------ > include/linux/platform_data/gpio-omap.h | 2 + > 2 files changed, 114 insertions(+), 33 deletions(-) >
* Grygorii Strashko <grygorii.strashko@ti.com> [180911 17:02]: > I agree with patch in general as it seems will not break anything and > change localized for omap4 only. OK cool. I'll be posting a related patch to get rid of the custom PM functions too. > But I'd be very appreciated if you can provide more information about issue > which helps better understand it, so could you, if possible, collect dump of: > - GPIO bank regs right before entering WFI state in Idle (or as close as possible) > I'm interesting in sysc/s, ctrl, irq's regs (+wakupen) and GPIO_DEBOUNCEN first of all > - GPIO bank CLKCTRL registers (is it "in transition" state). > in non working case. The thing is there is nothing special in the GPIO registers in the non-working vs working case. The GPIO_DEBOUNCEN was my first suspect too, but that's not enabled. The only difference is that the related CLKSTCTRL CLKACTIVITY bit for the 32K_GFCLK clock stays stuck showing busy after a level interrupt and wkup_en set. The 32K_GFCLK bit will only clear after reset of the GPIO module in question until a new level interrupt is seen. So with this patch we go from the following dump on omap4 gpio bank1 running before idle: GPIO_IRQSTATUS_RAW 0x4a310024 = 0000000000 GPIO_IRQSTATUS_RAW2 0x4a310028 = 0000000000 GPIO_IRQSTATUS_0 0x4a31002c = 0000000000 GPIO_IRQSTATUS_1 0x4a310030 = 0000000000 GPIO_IRQSTATUS_SET_0 0x4a310034 = 0x00000080 GPIO_IRQSTATUS_CLR_0 0x4a31003c = 0x00000080 GPIO_IRQWAKEN_0 0x4a310044 = 0x00000080 <- set GPIO_LEVELDETECT0 0x4a310140 = 0000000000 GPIO_LEVELDETECT1 0x4a310144 = 0x00000080 GPIO_RISINGDETECT 0x4a310148 = 0000000000 GPIO_FALLINGDETECT 0x4a31014c = 0000000000 GPIO_DEBOUNCENABLE 0x4a310150 = 0000000000 GPIO_DEBOUNCINGTIME 0x4a310154 = 0000000000 to the following dump where GPIO_IRQWAKEN_0 is not set until for idle: GPIO_IRQSTATUS_RAW 0x4a310024 = 0000000000 GPIO_IRQSTATUS_RAW2 0x4a310028 = 0000000000 GPIO_IRQSTATUS_0 0x4a31002c = 0000000000 GPIO_IRQSTATUS_1 0x4a310030 = 0000000000 GPIO_IRQSTATUS_SET_0 0x4a310034 = 0x00000080 GPIO_IRQSTATUS_CLR_0 0x4a31003c = 0x00000080 GPIO_IRQWAKEN_0 0x4a310044 = 0000000000 <- cleared GPIO_LEVELDETECT0 0x4a310140 = 0000000000 GPIO_LEVELDETECT1 0x4a310144 = 0x00000080 GPIO_RISINGDETECT 0x4a310148 = 0000000000 GPIO_FALLINGDETECT 0x4a31014c = 0000000000 GPIO_DEBOUNCENABLE 0x4a310150 = 0000000000 GPIO_DEBOUNCINGTIME 0x4a310154 = 0000000000 Regards, Tony
* Tony Lindgren <tony@atomide.com> [180910 20:10]: > I noticed that unlike omap2 and 3 based SoCs, omap4 based SoCs keep > the GPIO clocks enabled for GPIO level interrupts with wakeup enabled. > This blocks deeper idle states as the whole domain will stay busy. Linus, assuming people are OK with this one, I'd appreciate an immutable branch against v4.19-rc1 for this and a follow-up patch "[PATCH] gpio: omap: Remove custom PM calls and use cpu_pm instead". That's because of the arch/arm/mach-omap2 dependency that might conflict for v4.20 (although unlikely). Regards, Tony
On 09/11/2018 01:24 PM, Tony Lindgren wrote: > * Grygorii Strashko <grygorii.strashko@ti.com> [180911 17:02]: >> I agree with patch in general as it seems will not break anything and >> change localized for omap4 only. > > OK cool. I'll be posting a related patch to get rid of > the custom PM functions too. > >> But I'd be very appreciated if you can provide more information about issue >> which helps better understand it, so could you, if possible, collect dump of: >> - GPIO bank regs right before entering WFI state in Idle (or as close as possible) >> I'm interesting in sysc/s, ctrl, irq's regs (+wakupen) and GPIO_DEBOUNCEN first of all >> - GPIO bank CLKCTRL registers (is it "in transition" state). >> in non working case. > > The thing is there is nothing special in the GPIO registers in the > non-working vs working case. The GPIO_DEBOUNCEN was my first suspect > too, but that's not enabled. > > The only difference is that the related CLKSTCTRL CLKACTIVITY bit > for the 32K_GFCLK clock stays stuck showing busy after a level interrupt > and wkup_en set. The 32K_GFCLK bit will only clear after reset of the > GPIO module in question until a new level interrupt is seen. > > So with this patch we go from the following dump on omap4 gpio > bank1 running before idle: > > GPIO_IRQSTATUS_RAW 0x4a310024 = 0000000000 > GPIO_IRQSTATUS_RAW2 0x4a310028 = 0000000000 > GPIO_IRQSTATUS_0 0x4a31002c = 0000000000 > GPIO_IRQSTATUS_1 0x4a310030 = 0000000000 > GPIO_IRQSTATUS_SET_0 0x4a310034 = 0x00000080 > GPIO_IRQSTATUS_CLR_0 0x4a31003c = 0x00000080 > GPIO_IRQWAKEN_0 0x4a310044 = 0x00000080 <- set > GPIO_LEVELDETECT0 0x4a310140 = 0000000000 > GPIO_LEVELDETECT1 0x4a310144 = 0x00000080 > GPIO_RISINGDETECT 0x4a310148 = 0000000000 > GPIO_FALLINGDETECT 0x4a31014c = 0000000000 > GPIO_DEBOUNCENABLE 0x4a310150 = 0000000000 > GPIO_DEBOUNCINGTIME 0x4a310154 = 0000000000 > > to the following dump where GPIO_IRQWAKEN_0 is not set until > for idle: > > GPIO_IRQSTATUS_RAW 0x4a310024 = 0000000000 > GPIO_IRQSTATUS_RAW2 0x4a310028 = 0000000000 > GPIO_IRQSTATUS_0 0x4a31002c = 0000000000 > GPIO_IRQSTATUS_1 0x4a310030 = 0000000000 > GPIO_IRQSTATUS_SET_0 0x4a310034 = 0x00000080 > GPIO_IRQSTATUS_CLR_0 0x4a31003c = 0x00000080 > GPIO_IRQWAKEN_0 0x4a310044 = 0000000000 <- cleared > GPIO_LEVELDETECT0 0x4a310140 = 0000000000 > GPIO_LEVELDETECT1 0x4a310144 = 0x00000080 > GPIO_RISINGDETECT 0x4a310148 = 0000000000 > GPIO_FALLINGDETECT 0x4a31014c = 0000000000 > GPIO_DEBOUNCENABLE 0x4a310150 = 0000000000 > GPIO_DEBOUNCINGTIME 0x4a310154 = 0000000000 > Thanks Tony, but it's still not completely clear - it's important to see values of CLKSTCTRL before/after idle for not working case and GPIO SYSC/SYSS registers. There are some combinations which may affect on this. So, if you can, pls.
* Grygorii Strashko <grygorii.strashko@ti.com> [180912 00:27]: > Thanks Tony, but it's still not completely clear - > it's important to see values of CLKSTCTRL before/after idle for not working > case and GPIO SYSC/SYSS registers. There are some combinations which may > affect on this. So, if you can, pls. Sure I'll do some reg dumps for you tomorrow as I just started an overnight test with randomly pinging the wlan interface from outside to make sure it wakes up and keeps idling. Regards, Tony
On 09/11/2018 07:42 PM, Tony Lindgren wrote: > * Grygorii Strashko <grygorii.strashko@ti.com> [180912 00:27]: >> Thanks Tony, but it's still not completely clear - >> it's important to see values of CLKSTCTRL before/after idle for not working >> case and GPIO SYSC/SYSS registers. There are some combinations which may >> affect on this. So, if you can, pls. > > Sure I'll do some reg dumps for you tomorrow as I just started > an overnight test with randomly pinging the wlan interface > from outside to make sure it wakes up and keeps idling. Pls, postpone this until we finish our discussion/debugging
* Tony Lindgren <tony@atomide.com> [180910 20:10]: > +static void __maybe_unused > +omap4_gpio_disable_level_quirk(struct gpio_bank *bank) > +{ > + /* Restore level registers after idle */ > + writel_relaxed(bank->context.leveldetect0, > + bank->base + bank->regs->leveldetect0); > + writel_relaxed(bank->context.leveldetect1, > + bank->base + bank->regs->leveldetect1); > + > + /* Clear wake after idle */ > + writel_relaxed(0, bank->base + bank->regs->wkup_en); /* Reset saved wkup_en, it will be set for next idle again */ bank->context.wake_en = 0; > +} Clearing the saved wkup_en is needed above I noticed testing again with gpio4 which has pdata->loses_context set. Otherwise runtime_resume will write to wkup_en enabling it for runtime which will the next idle fail. Regards, Tony
* Grygorii Strashko <grygorii.strashko@ti.com> [180912 16:13]: > > > On 09/11/2018 07:42 PM, Tony Lindgren wrote: > > * Grygorii Strashko <grygorii.strashko@ti.com> [180912 00:27]: > > > Thanks Tony, but it's still not completely clear - > > > it's important to see values of CLKSTCTRL before/after idle for not working > > > case and GPIO SYSC/SYSS registers. There are some combinations which may > > > affect on this. So, if you can, pls. > > > > Sure I'll do some reg dumps for you tomorrow as I just started > > an overnight test with randomly pinging the wlan interface > > from outside to make sure it wakes up and keeps idling. > > Pls, postpone this until we finish our discussion/debugging Yeah I just sent you three gpio dump files privately to avoid spamming the list with them. Regards, Tony
On Mon, Sep 10, 2018 at 1:06 PM Tony Lindgren <tony@atomide.com> wrote: > I noticed that unlike omap2 and 3 based SoCs, omap4 based SoCs keep > the GPIO clocks enabled for GPIO level interrupts with wakeup enabled. > This blocks deeper idle states as the whole domain will stay busy. > > The GPIO clock seems to stay enabled if the wakeup register is enabled > and a level interrupt is triggered. In that case the only way to have > the GPIO module idle is to reset it. It is possible this has gone > unnoticed with OSWR (Open SWitch Retention) and off mode during idle > resetting GPIO context most GPIO instances in the earlier Android trees > for example. > > Looks like the way to deal with this is to have omap4 based SoCs > only set wake for the duration of idle and clear level registers for > the idle. With level interrupts we can do this as the level interrupt > from device will be still there on resume. > > I've taken the long path to fixing this to avoid yet more hard to > read code. I've set up a quirks flag, and a struct for function > pointers so we can use these to clean up other quirk handling easier > in the later patches. The current level quirk handling is moved to > the new functions. > > Cc: Grygorii Strashko <grygorii.strashko@ti.com> > Cc: Keerthy <j-keerthy@ti.com> > Cc: Tero Kristo <t-kristo@ti.com> > Signed-off-by: Tony Lindgren <tony@atomide.com> Do we have a conclusion on this? Shall I apply the patch on an immutable branch and pull into next, or do you folks need more time? Yours, Linus Walleij
* Linus Walleij <linus.walleij@linaro.org> [180918 23:33]: > On Mon, Sep 10, 2018 at 1:06 PM Tony Lindgren <tony@atomide.com> wrote: > > > I noticed that unlike omap2 and 3 based SoCs, omap4 based SoCs keep > > the GPIO clocks enabled for GPIO level interrupts with wakeup enabled. > > This blocks deeper idle states as the whole domain will stay busy. > > > > The GPIO clock seems to stay enabled if the wakeup register is enabled > > and a level interrupt is triggered. In that case the only way to have > > the GPIO module idle is to reset it. It is possible this has gone > > unnoticed with OSWR (Open SWitch Retention) and off mode during idle > > resetting GPIO context most GPIO instances in the earlier Android trees > > for example. > > > > Looks like the way to deal with this is to have omap4 based SoCs > > only set wake for the duration of idle and clear level registers for > > the idle. With level interrupts we can do this as the level interrupt > > from device will be still there on resume. > > > > I've taken the long path to fixing this to avoid yet more hard to > > read code. I've set up a quirks flag, and a struct for function > > pointers so we can use these to clean up other quirk handling easier > > in the later patches. The current level quirk handling is moved to > > the new functions. > > > > Cc: Grygorii Strashko <grygorii.strashko@ti.com> > > Cc: Keerthy <j-keerthy@ti.com> > > Cc: Tero Kristo <t-kristo@ti.com> > > Signed-off-by: Tony Lindgren <tony@atomide.com> > > Do we have a conclusion on this? Shall I apply the patch on > an immutable branch and pull into next, or do you folks need > more time? Thanks for checking, let's wait on this. There are few more things I still need to check and test before reposting. Regards, Tony
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -31,6 +31,8 @@ #define OFF_MODE 1 #define OMAP4_GPIO_DEBOUNCINGTIME_MASK 0xFF +#define OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN BIT(1) + static LIST_HEAD(omap_gpio_list); struct gpio_regs { @@ -48,6 +50,13 @@ struct gpio_regs { u32 debounce_en; }; +struct gpio_bank; + +struct gpio_omap_funcs { + void (*idle_enable_level_quirk)(struct gpio_bank *bank); + void (*idle_disable_level_quirk)(struct gpio_bank *bank); +}; + struct gpio_bank { struct list_head node; void __iomem *base; @@ -55,6 +64,7 @@ struct gpio_bank { u32 non_wakeup_gpios; u32 enabled_non_wakeup_gpios; struct gpio_regs context; + struct gpio_omap_funcs funcs; u32 saved_datain; u32 level_mask; u32 toggle_mask; @@ -75,6 +85,7 @@ struct gpio_bank { int context_loss_count; int power_mode; bool workaround_enabled; + u32 quirks; void (*set_dataout)(struct gpio_bank *bank, unsigned gpio, int enable); void (*set_dataout_multiple)(struct gpio_bank *bank, @@ -368,9 +379,18 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio, readl_relaxed(bank->base + bank->regs->fallingdetect); if (likely(!(bank->non_wakeup_gpios & gpio_bit))) { - omap_gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0); - bank->context.wake_en = - readl_relaxed(bank->base + bank->regs->wkup_en); + /* Defer wkup_en register write until we idle? */ + if (bank->quirks & OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN) { + if (trigger) + bank->context.wake_en |= gpio_bit; + else + bank->context.wake_en &= ~gpio_bit; + } else { + omap_gpio_rmw(base, bank->regs->wkup_en, gpio_bit, + trigger != 0); + bank->context.wake_en = + readl_relaxed(bank->base + bank->regs->wkup_en); + } } /* This part needs to be executed always for OMAP{34xx, 44xx} */ @@ -899,6 +919,76 @@ static void omap_gpio_unmask_irq(struct irq_data *d) raw_spin_unlock_irqrestore(&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. + */ +static void __maybe_unused +omap2_gpio_enable_level_quirk(struct gpio_bank *bank) +{ + u32 wake_low, wake_hi; + + /* Enable additional edge detection for level gpios for idle */ + wake_low = bank->context.leveldetect0 & bank->context.wake_en; + if (wake_low) + writel_relaxed(wake_low | bank->context.fallingdetect, + bank->base + bank->regs->fallingdetect); + + wake_hi = bank->context.leveldetect1 & bank->context.wake_en; + if (wake_hi) + writel_relaxed(wake_hi | bank->context.risingdetect, + bank->base + bank->regs->risingdetect); +} + +static void __maybe_unused +omap2_gpio_disable_level_quirk(struct gpio_bank *bank) +{ + /* Disable edge detection for level gpios after idle */ + writel_relaxed(bank->context.fallingdetect, + bank->base + bank->regs->fallingdetect); + writel_relaxed(bank->context.risingdetect, + bank->base + bank->regs->risingdetect); +} + +/* + * On omap4 and later SoC variants a level interrupt with wkup_en + * enabled blocks the GPIO clocks from idling until the GPIO + * instance been reset. To avoid that, we must set wkup_en only for + * idle and clear level registers for the duration of idle. The level + * interrupt will be still there on wakeup by it's nature. + */ +static void __maybe_unused +omap4_gpio_enable_level_quirk(struct gpio_bank *bank) +{ + /* Set wake only for idle */ + writel_relaxed(bank->context.wake_en, + bank->base + bank->regs->wkup_en); + + /* Clear level registers for idle */ + writel_relaxed(0, bank->base + bank->regs->leveldetect0); + writel_relaxed(0, bank->base + bank->regs->leveldetect1); +} + +static void __maybe_unused +omap4_gpio_disable_level_quirk(struct gpio_bank *bank) +{ + /* Restore level registers after idle */ + writel_relaxed(bank->context.leveldetect0, + bank->base + bank->regs->leveldetect0); + writel_relaxed(bank->context.leveldetect1, + bank->base + bank->regs->leveldetect1); + + /* Clear wake after idle */ + writel_relaxed(0, bank->base + bank->regs->wkup_en); +} + /*---------------------------------------------------------------------*/ static int omap_mpuio_suspend_noirq(struct device *dev) @@ -1270,6 +1360,7 @@ static int omap_gpio_probe(struct platform_device *pdev) bank->chip.parent = dev; bank->chip.owner = THIS_MODULE; bank->dbck_flag = pdata->dbck_flag; + bank->quirks = pdata->quirks; bank->stride = pdata->bank_stride; bank->width = pdata->bank_width; bank->is_mpuio = pdata->is_mpuio; @@ -1278,6 +1369,7 @@ static int omap_gpio_probe(struct platform_device *pdev) #ifdef CONFIG_OF_GPIO bank->chip.of_node = of_node_get(node); #endif + if (node) { if (!of_property_read_bool(node, "ti,gpio-always-on")) bank->loses_context = true; @@ -1298,6 +1390,18 @@ static int omap_gpio_probe(struct platform_device *pdev) omap_set_gpio_dataout_mask_multiple; } + if (bank->quirks & OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN) { + bank->funcs.idle_enable_level_quirk = + omap4_gpio_enable_level_quirk; + bank->funcs.idle_disable_level_quirk = + omap4_gpio_disable_level_quirk; + } else { + bank->funcs.idle_enable_level_quirk = + omap2_gpio_enable_level_quirk; + bank->funcs.idle_disable_level_quirk = + omap2_gpio_disable_level_quirk; + } + raw_spin_lock_init(&bank->lock); raw_spin_lock_init(&bank->wa_lock); @@ -1372,29 +1476,11 @@ 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; raw_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) - writel_relaxed(wake_low | bank->context.fallingdetect, - bank->base + bank->regs->fallingdetect); - wake_hi = bank->context.leveldetect1 & bank->context.wake_en; - if (wake_hi) - writel_relaxed(wake_hi | bank->context.risingdetect, - bank->base + bank->regs->risingdetect); + if (bank->funcs.idle_enable_level_quirk) + bank->funcs.idle_enable_level_quirk(bank); if (!bank->enabled_non_wakeup_gpios) goto update_gpio_context_count; @@ -1459,16 +1545,8 @@ static int omap_gpio_runtime_resume(struct device *dev) omap_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. - */ - writel_relaxed(bank->context.fallingdetect, - bank->base + bank->regs->fallingdetect); - writel_relaxed(bank->context.risingdetect, - bank->base + bank->regs->risingdetect); + if (bank->funcs.idle_disable_level_quirk) + bank->funcs.idle_disable_level_quirk(bank); if (bank->loses_context) { if (!bank->get_context_loss_count) { @@ -1706,6 +1784,7 @@ static const struct omap_gpio_platform_data omap4_pdata = { .regs = &omap4_gpio_regs, .bank_width = 32, .dbck_flag = true, + .quirks = OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN, }; static const struct of_device_id omap_gpio_match[] = { diff --git a/include/linux/platform_data/gpio-omap.h b/include/linux/platform_data/gpio-omap.h --- a/include/linux/platform_data/gpio-omap.h +++ b/include/linux/platform_data/gpio-omap.h @@ -197,6 +197,8 @@ struct omap_gpio_platform_data { bool is_mpuio; /* whether the bank is of type MPUIO */ u32 non_wakeup_gpios; + u32 quirks; /* Version specific quirks mask */ + struct omap_gpio_reg_offs *regs; /* Return context loss count due to PM states changing */
I noticed that unlike omap2 and 3 based SoCs, omap4 based SoCs keep the GPIO clocks enabled for GPIO level interrupts with wakeup enabled. This blocks deeper idle states as the whole domain will stay busy. The GPIO clock seems to stay enabled if the wakeup register is enabled and a level interrupt is triggered. In that case the only way to have the GPIO module idle is to reset it. It is possible this has gone unnoticed with OSWR (Open SWitch Retention) and off mode during idle resetting GPIO context most GPIO instances in the earlier Android trees for example. Looks like the way to deal with this is to have omap4 based SoCs only set wake for the duration of idle and clear level registers for the idle. With level interrupts we can do this as the level interrupt from device will be still there on resume. I've taken the long path to fixing this to avoid yet more hard to read code. I've set up a quirks flag, and a struct for function pointers so we can use these to clean up other quirk handling easier in the later patches. The current level quirk handling is moved to the new functions. Cc: Grygorii Strashko <grygorii.strashko@ti.com> Cc: Keerthy <j-keerthy@ti.com> Cc: Tero Kristo <t-kristo@ti.com> Signed-off-by: Tony Lindgren <tony@atomide.com> --- drivers/gpio/gpio-omap.c | 145 ++++++++++++++++++------ include/linux/platform_data/gpio-omap.h | 2 + 2 files changed, 114 insertions(+), 33 deletions(-)