| From: Mika Westerberg <mika.westerberg@linux.intel.com> |
| Date: Mon, 23 Feb 2015 14:53:11 +0200 |
| Subject: pinctrl: baytrail: Clear interrupt triggering from pins that are in |
| GPIO mode |
| |
| commit 95f0972c7e4cbf3fc68160131c5ac2f033481d00 upstream. |
| |
| If the pin is already configured as GPIO and it has any of the triggering |
| flags set, we may get spurious interrupts depending on the state of the |
| pin. |
| |
| Prevent this by clearing the triggering flags on such pins. However, if the |
| pin is also configured as "direct IRQ" we leave the flags as is. Otherwise |
| it will prevent interrupts that are routed directly to IO-APIC. |
| |
| Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> |
| Signed-off-by: Linus Walleij <linus.walleij@linaro.org> |
| [bwh: Backported to 3.16: |
| - Add definition of BYT_DIRECT_IRQ_EN |
| - Adjust filename] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| --- a/drivers/pinctrl/pinctrl-baytrail.c |
| +++ b/drivers/pinctrl/pinctrl-baytrail.c |
| @@ -44,6 +44,7 @@ |
| |
| /* BYT_CONF0_REG register bits */ |
| #define BYT_IODEN BIT(31) |
| +#define BYT_DIRECT_IRQ_EN BIT(27) |
| #define BYT_TRIG_NEG BIT(26) |
| #define BYT_TRIG_POS BIT(25) |
| #define BYT_TRIG_LVL BIT(24) |
| @@ -160,6 +161,19 @@ static void __iomem *byt_gpio_reg(struct |
| return vg->reg_base + reg_offset + reg; |
| } |
| |
| +static void byt_gpio_clear_triggering(struct byt_gpio *vg, unsigned offset) |
| +{ |
| + void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG); |
| + unsigned long flags; |
| + u32 value; |
| + |
| + spin_lock_irqsave(&vg->lock, flags); |
| + value = readl(reg); |
| + value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL); |
| + writel(value, reg); |
| + spin_unlock_irqrestore(&vg->lock, flags); |
| +} |
| + |
| static u32 byt_get_gpio_mux(struct byt_gpio *vg, unsigned offset) |
| { |
| /* SCORE pin 92-93 */ |
| @@ -213,14 +227,8 @@ static int byt_gpio_request(struct gpio_ |
| static void byt_gpio_free(struct gpio_chip *chip, unsigned offset) |
| { |
| struct byt_gpio *vg = to_byt_gpio(chip); |
| - void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG); |
| - u32 value; |
| - |
| - /* clear interrupt triggering */ |
| - value = readl(reg); |
| - value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL); |
| - writel(value, reg); |
| |
| + byt_gpio_clear_triggering(vg, offset); |
| pm_runtime_put(&vg->pdev->dev); |
| } |
| |
| @@ -496,6 +504,21 @@ static void byt_gpio_irq_init_hw(struct |
| { |
| void __iomem *reg; |
| u32 base, value; |
| + int i; |
| + |
| + /* |
| + * Clear interrupt triggers for all pins that are GPIOs and |
| + * do not use direct IRQ mode. This will prevent spurious |
| + * interrupts from misconfigured pins. |
| + */ |
| + for (i = 0; i < vg->chip.ngpio; i++) { |
| + value = readl(byt_gpio_reg(&vg->chip, i, BYT_CONF0_REG)); |
| + if ((value & BYT_PIN_MUX) == byt_get_gpio_mux(vg, i) && |
| + !(value & BYT_DIRECT_IRQ_EN)) { |
| + byt_gpio_clear_triggering(vg, i); |
| + dev_dbg(&vg->pdev->dev, "disabling GPIO %d\n", i); |
| + } |
| + } |
| |
| /* clear interrupt status trigger registers */ |
| for (base = 0; base < vg->chip.ngpio; base += 32) { |