gpio: omap: ensure irq is enabled before wakeup [Linux 4.9.187]

This Linux kernel change "gpio: omap: ensure irq is enabled before wakeup" is included in the Linux 4.9.187 release. This change is authored by Russell King <rmk+kernel [at] armlinux.org.uk> on Mon Jun 10 20:10:44 2019 +0300. The commit for this change in Linux stable tree is f7fa002 (patch) which is from upstream commit c859e0d. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream c859e0d.

gpio: omap: ensure irq is enabled before wakeup

[ Upstream commit c859e0d479b3b4f6132fc12637c51e01492f31f6 ]

Documentation states:

  NOTE: There must be a correlation between the wake-up enable and
  interrupt-enable registers. If a GPIO pin has a wake-up configured
  on it, it must also have the corresponding interrupt enabled (on
  one of the two interrupt lines).

Ensure that this condition is always satisfied by enabling the detection
events after enabling the interrupt, and disabling the detection before
disabling the interrupt.  This ensures interrupt/wakeup events can not
happen until both the wakeup and interrupt enables correlate.

If we do any clearing, clear between the interrupt enable/disable and
trigger setting.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
Tested-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>

There are 15 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/gpio/gpio-omap.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index bd12b43..fc841ce 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -786,9 +786,9 @@ static void omap_gpio_irq_shutdown(struct irq_data *d)

    raw_spin_lock_irqsave(&bank->lock, flags);
    bank->irq_usage &= ~(BIT(offset));
-   omap_set_gpio_irqenable(bank, offset, 0);
-   omap_clear_gpio_irqstatus(bank, offset);
    omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
+   omap_clear_gpio_irqstatus(bank, offset);
+   omap_set_gpio_irqenable(bank, offset, 0);
    if (!LINE_USED(bank->mod_usage, offset))
        omap_clear_gpio_debounce(bank, offset);
    omap_disable_gpio_module(bank, offset);
@@ -830,8 +830,8 @@ static void omap_gpio_mask_irq(struct irq_data *d)
    unsigned long flags;

    raw_spin_lock_irqsave(&bank->lock, flags);
-   omap_set_gpio_irqenable(bank, offset, 0);
    omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
+   omap_set_gpio_irqenable(bank, offset, 0);
    raw_spin_unlock_irqrestore(&bank->lock, flags);
 }

@@ -843,9 +843,6 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
    unsigned long flags;

    raw_spin_lock_irqsave(&bank->lock, flags);
-   if (trigger)
-       omap_set_gpio_triggering(bank, offset, trigger);
-
    omap_set_gpio_irqenable(bank, offset, 1);

    /*
@@ -853,9 +850,13 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
     * is cleared, thus after the handler has run. OMAP4 needs this done
     * after enabing the interrupt to clear the wakeup status.
     */
-   if (bank->level_mask & BIT(offset))
+   if (bank->regs->leveldetect0 && bank->regs->wkup_en &&
+       trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
        omap_clear_gpio_irqstatus(bank, offset);

+   if (trigger)
+       omap_set_gpio_triggering(bank, offset, trigger);
+
    raw_spin_unlock_irqrestore(&bank->lock, flags);
 }

Leave a Reply

Your email address will not be published. Required fields are marked *