From: Doug Anderson Date: Mon, 17 Jun 2013 16:50:43 +0000 (-0700) Subject: pinctrl: exynos: ack level-triggered interrupts before unmasking X-Git-Tag: submit/tizen/20141121.110247~2838 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=cc058172846da3108207f8169763c9e56216112e;p=platform%2Fkernel%2Flinux-3.10.git pinctrl: exynos: ack level-triggered interrupts before unmasking A level-triggered interrupt should be acked after the interrupt line becomes inactive and before it is unmasked, or else another interrupt will be immediately triggered. Acking before or after calling the handler is not enough. Change-Id: I553444ce552df5722e606d71bea8bf7b862cce25 Signed-off-by: Luigi Semenzato Signed-off-by: Doug Anderson Acked-by: Tomasz Figa Signed-off-by: Linus Walleij --- diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c index c0729a3..ef75321 100644 --- a/drivers/pinctrl/pinctrl-exynos.c +++ b/drivers/pinctrl/pinctrl-exynos.c @@ -84,6 +84,17 @@ static void exynos_gpio_irq_unmask(struct irq_data *irqd) unsigned long mask; unsigned long flags; + /* + * Ack level interrupts right before unmask + * + * If we don't do this we'll get a double-interrupt. Level triggered + * interrupts must not fire an interrupt if the level is not + * _currently_ active, even if it was active while the interrupt was + * masked. + */ + if (irqd_get_trigger_type(irqd) & IRQ_TYPE_LEVEL_MASK) + exynos_gpio_irq_ack(irqd); + spin_lock_irqsave(&bank->slock, flags); mask = readl(d->virt_base + reg_mask); @@ -302,6 +313,17 @@ static void exynos_wkup_irq_unmask(struct irq_data *irqd) unsigned long mask; unsigned long flags; + /* + * Ack level interrupts right before unmask + * + * If we don't do this we'll get a double-interrupt. Level triggered + * interrupts must not fire an interrupt if the level is not + * _currently_ active, even if it was active while the interrupt was + * masked. + */ + if (irqd_get_trigger_type(irqd) & IRQ_TYPE_LEVEL_MASK) + exynos_wkup_irq_ack(irqd); + spin_lock_irqsave(&b->slock, flags); mask = readl(d->virt_base + reg_mask);