mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-05 16:37:50 +00:00
pinctrl: ocelot: Fix incorrect trigger of the interrupt.
[ Upstream commite9945b2633
] The interrupt controller can detect only link changes. So in case an external device generated a level based interrupt, then the interrupt controller detected correctly the first edge. But the problem was that the interrupt controller was detecting also the edge when the interrupt was cleared. So it would generate another interrupt. The fix for this is to clear the second interrupt but still check the interrupt line status. Fixes:c297561bc9
("pinctrl: ocelot: Fix interrupt controller") Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com> Tested-by: Michael Walle <michael@walle.cc> Link: https://lore.kernel.org/r/20221018070959.1322606-1-horatiu.vultur@microchip.com Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
cb9aa46bba
commit
06e84176dd
1 changed files with 13 additions and 4 deletions
|
@ -1863,19 +1863,28 @@ static void ocelot_irq_unmask_level(struct irq_data *data)
|
|||
if (val & bit)
|
||||
ack = true;
|
||||
|
||||
/* Try to clear any rising edges */
|
||||
if (!active && ack)
|
||||
regmap_write_bits(info->map, REG(OCELOT_GPIO_INTR, info, gpio),
|
||||
bit, bit);
|
||||
|
||||
/* Enable the interrupt now */
|
||||
gpiochip_enable_irq(chip, gpio);
|
||||
regmap_update_bits(info->map, REG(OCELOT_GPIO_INTR_ENA, info, gpio),
|
||||
bit, bit);
|
||||
|
||||
/*
|
||||
* In case the interrupt line is still active and the interrupt
|
||||
* controller has not seen any changes in the interrupt line, then it
|
||||
* means that there happen another interrupt while the line was active.
|
||||
* In case the interrupt line is still active then it means that
|
||||
* there happen another interrupt while the line was active.
|
||||
* So we missed that one, so we need to kick the interrupt again
|
||||
* handler.
|
||||
*/
|
||||
if (active && !ack) {
|
||||
regmap_read(info->map, REG(OCELOT_GPIO_IN, info, gpio), &val);
|
||||
if ((!(val & bit) && trigger_level == IRQ_TYPE_LEVEL_LOW) ||
|
||||
(val & bit && trigger_level == IRQ_TYPE_LEVEL_HIGH))
|
||||
active = true;
|
||||
|
||||
if (active) {
|
||||
struct ocelot_irq_work *work;
|
||||
|
||||
work = kmalloc(sizeof(*work), GFP_ATOMIC);
|
||||
|
|
Loading…
Reference in a new issue