aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQi Zheng <qi.zheng@intel.com>2016-03-16 14:15:26 -0400
committerLinus Walleij <linus.walleij@linaro.org>2016-03-30 04:57:52 -0400
commita939bb57cd4716fdae213f6cb60a626fa6d5a60a (patch)
treee89b8e75965cf3664c1b842ea894e1e3c2b21bf8
parentbf380cfa60db1f44d4884dbea0372dac5d9db633 (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.c30
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
668static 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
668static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask) 697static 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
854static struct irq_chip intel_gpio_irqchip = { 883static 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,