summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/pinctrl/pinctrl-mcp23s08.c23
1 files changed, 20 insertions, 3 deletions
diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c
index f384c72d9554..70d7485ada36 100644
--- a/drivers/pinctrl/pinctrl-mcp23s08.c
+++ b/drivers/pinctrl/pinctrl-mcp23s08.c
@@ -382,6 +382,7 @@ static irqreturn_t mcp23s08_irq(int irq, void *data)
{
struct mcp23s08 *mcp = data;
int intcap, intcon, intf, i, gpio, gpio_orig, intcap_mask, defval, gpinten;
+ bool need_unmask = false;
unsigned long int enabled_interrupts;
unsigned int child_irq;
bool intf_set, intcap_changed, gpio_bit_changed,
@@ -396,9 +397,6 @@ static irqreturn_t mcp23s08_irq(int irq, void *data)
goto unlock;
}
- if (mcp_read(mcp, MCP_INTCAP, &intcap))
- goto unlock;
-
if (mcp_read(mcp, MCP_INTCON, &intcon))
goto unlock;
@@ -408,6 +406,16 @@ static irqreturn_t mcp23s08_irq(int irq, void *data)
if (mcp_read(mcp, MCP_DEFVAL, &defval))
goto unlock;
+ /* Mask level interrupts to avoid their immediate reactivation after clearing */
+ if (intcon) {
+ need_unmask = true;
+ if (mcp_write(mcp, MCP_GPINTEN, gpinten & ~intcon))
+ goto unlock;
+ }
+
+ if (mcp_read(mcp, MCP_INTCAP, &intcap))
+ goto unlock;
+
/* This clears the interrupt(configurable on S18) */
if (mcp_read(mcp, MCP_GPIO, &gpio))
goto unlock;
@@ -470,9 +478,18 @@ static irqreturn_t mcp23s08_irq(int irq, void *data)
}
}
+ if (need_unmask) {
+ mutex_lock(&mcp->lock);
+ goto unlock;
+ }
+
return IRQ_HANDLED;
unlock:
+ if (need_unmask)
+ if (mcp_write(mcp, MCP_GPINTEN, gpinten))
+ dev_err(mcp->chip.parent, "can't unmask GPINTEN\n");
+
mutex_unlock(&mcp->lock);
return IRQ_HANDLED;
}