diff options
author | Qi Zheng <qi.zheng@intel.com> | 2016-03-16 14:15:26 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2016-03-30 04:57:52 -0400 |
commit | a939bb57cd4716fdae213f6cb60a626fa6d5a60a (patch) | |
tree | e89b8e75965cf3664c1b842ea894e1e3c2b21bf8 | |
parent | bf380cfa60db1f44d4884dbea0372dac5d9db633 (diff) |
pinctrl: intel: implement gpio_irq_enable
There is unexpected gpio interrupt after irq_enable. If not
implemeted gpio_irq_enable callback, irq_enable calls irq_unmask
instead. But if there was interrupt set before the irq_enable,
unmask it may trigger the unexpected interrupt. By implementing
the gpio_irq_enable callback, do interrupt status ack, the issue
has gone.
Signed-off-by: Qi Zheng <qi.zheng@intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Qipeng Zha <qipeng.zha@intel.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r-- | drivers/pinctrl/intel/pinctrl-intel.c | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index c216cb3bef2f..6c2c816f8e5f 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c | |||
@@ -665,6 +665,35 @@ static void intel_gpio_irq_ack(struct irq_data *d) | |||
665 | spin_unlock(&pctrl->lock); | 665 | spin_unlock(&pctrl->lock); |
666 | } | 666 | } |
667 | 667 | ||
668 | static void intel_gpio_irq_enable(struct irq_data *d) | ||
669 | { | ||
670 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | ||
671 | struct intel_pinctrl *pctrl = gpiochip_get_data(gc); | ||
672 | const struct intel_community *community; | ||
673 | unsigned pin = irqd_to_hwirq(d); | ||
674 | unsigned long flags; | ||
675 | |||
676 | spin_lock_irqsave(&pctrl->lock, flags); | ||
677 | |||
678 | community = intel_get_community(pctrl, pin); | ||
679 | if (community) { | ||
680 | unsigned padno = pin_to_padno(community, pin); | ||
681 | unsigned gpp_size = community->gpp_size; | ||
682 | unsigned gpp_offset = padno % gpp_size; | ||
683 | unsigned gpp = padno / gpp_size; | ||
684 | u32 value; | ||
685 | |||
686 | /* Clear interrupt status first to avoid unexpected interrupt */ | ||
687 | writel(BIT(gpp_offset), community->regs + GPI_IS + gpp * 4); | ||
688 | |||
689 | value = readl(community->regs + community->ie_offset + gpp * 4); | ||
690 | value |= BIT(gpp_offset); | ||
691 | writel(value, community->regs + community->ie_offset + gpp * 4); | ||
692 | } | ||
693 | |||
694 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
695 | } | ||
696 | |||
668 | static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask) | 697 | static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask) |
669 | { | 698 | { |
670 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | 699 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
@@ -853,6 +882,7 @@ static irqreturn_t intel_gpio_irq(int irq, void *data) | |||
853 | 882 | ||
854 | static struct irq_chip intel_gpio_irqchip = { | 883 | static struct irq_chip intel_gpio_irqchip = { |
855 | .name = "intel-gpio", | 884 | .name = "intel-gpio", |
885 | .irq_enable = intel_gpio_irq_enable, | ||
856 | .irq_ack = intel_gpio_irq_ack, | 886 | .irq_ack = intel_gpio_irq_ack, |
857 | .irq_mask = intel_gpio_irq_mask, | 887 | .irq_mask = intel_gpio_irq_mask, |
858 | .irq_unmask = intel_gpio_irq_unmask, | 888 | .irq_unmask = intel_gpio_irq_unmask, |