summaryrefslogtreecommitdiff
path: root/drivers/pinctrl/pinctrl-ingenic.c
diff options
context:
space:
mode:
authorPaul Cercueil <paul@crapouillou.net>2020-06-23 00:45:47 +0300
committerLinus Walleij <linus.walleij@linaro.org>2020-07-07 15:21:02 +0300
commit1c95348ba327fe8621d3680890c2341523d3524a (patch)
tree9c578bc836d72fb39e0601ea9154ba673656e81b /drivers/pinctrl/pinctrl-ingenic.c
parentb77eab32c4492178adfb7ea81569c311120f5682 (diff)
downloadlinux-1c95348ba327fe8621d3680890c2341523d3524a.tar.xz
pinctrl: ingenic: Enhance support for IRQ_TYPE_EDGE_BOTH
Ingenic SoCs don't natively support registering an interrupt for both rising and falling edges. This has to be emulated in software. Until now, this was emulated by switching back and forth between IRQ_TYPE_EDGE_RISING and IRQ_TYPE_EDGE_FALLING according to the level of the GPIO. While this worked most of the time, when used with GPIOs that need debouncing, some events would be lost. For instance, between the time a falling-edge interrupt happens and the interrupt handler configures the hardware for rising-edge, the level of the pin may have already risen, and the rising-edge event is lost. To address that issue, instead of switching back and forth between IRQ_TYPE_EDGE_RISING and IRQ_TYPE_EDGE_FALLING, we now switch back and forth between IRQ_TYPE_LEVEL_LOW and IRQ_TYPE_LEVEL_HIGH. Since we always switch in the interrupt handler, they actually permit to detect level changes. In the example above, if the pin level rises before switching the IRQ type from IRQ_TYPE_LEVEL_LOW to IRQ_TYPE_LEVEL_HIGH, a new interrupt will raise as soon as the handler exits, and the rising-edge event will be properly detected. Fixes: e72394e2ea19 ("pinctrl: ingenic: Merge GPIO functionality") Reported-by: João Henrique <johnnyonflame@hotmail.com> Signed-off-by: Paul Cercueil <paul@crapouillou.net> Tested-by: João Henrique <johnnyonflame@hotmail.com> Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20200622214548.265417-1-paul@crapouillou.net Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl/pinctrl-ingenic.c')
-rw-r--r--drivers/pinctrl/pinctrl-ingenic.c6
1 files changed, 3 insertions, 3 deletions
diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-ingenic.c
index fc0d10411aa9..241e563d5814 100644
--- a/drivers/pinctrl/pinctrl-ingenic.c
+++ b/drivers/pinctrl/pinctrl-ingenic.c
@@ -1813,9 +1813,9 @@ static void ingenic_gpio_irq_ack(struct irq_data *irqd)
*/
high = ingenic_gpio_get_value(jzgc, irq);
if (high)
- irq_set_type(jzgc, irq, IRQ_TYPE_EDGE_FALLING);
+ irq_set_type(jzgc, irq, IRQ_TYPE_LEVEL_LOW);
else
- irq_set_type(jzgc, irq, IRQ_TYPE_EDGE_RISING);
+ irq_set_type(jzgc, irq, IRQ_TYPE_LEVEL_HIGH);
}
if (jzgc->jzpc->info->version >= ID_JZ4760)
@@ -1851,7 +1851,7 @@ static int ingenic_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
*/
bool high = ingenic_gpio_get_value(jzgc, irqd->hwirq);
- type = high ? IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING;
+ type = high ? IRQ_TYPE_LEVEL_LOW : IRQ_TYPE_LEVEL_HIGH;
}
irq_set_type(jzgc, irqd->hwirq, type);