[PATCH 2/4] i2c: muxes: pca954x: free parent IRQ before dismantling IRQ domain

From: Pradhan, Sanman

Date: Wed Apr 15 2026 - 13:07:31 EST


From: Sanman Pradhan <psanman@xxxxxxxxxxx>

The parent IRQ is registered via devm_request_threaded_irq() in
probe, so it is not released until after .remove() returns via devm
cleanup. However, pca954x_cleanup() tears down the IRQ domain and
disposes the mappings during .remove().

The threaded IRQ handler reads the mux over SMBus and dispatches
nested child IRQs via handle_nested_irq(irq_find_mapping(data->irq, i)).
If the handler fires while child adapters are being removed or after
the domain has been torn down, it operates on stale state.

Call devm_free_irq() explicitly before removing child adapters and
tearing down the IRQ domain so the handler is fully quiesced first.

pca954x_cleanup() is also used as the probe error-unwind path. The
IRQ domain is created by pca954x_irq_setup() before the parent IRQ is
requested, so on mid-probe failures data->irq is non-NULL while no
managed IRQ resource exists yet. Track whether the parent IRQ was
successfully requested and only call devm_free_irq() when that is the
case.

Fixes: f2114795f721 ("i2c: mux: pca954x: Add interrupt controller support")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Sanman Pradhan <psanman@xxxxxxxxxxx>
---
drivers/i2c/muxes/i2c-mux-pca954x.c | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index f0b8879ae5fa..c20a161e6a5b 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -116,6 +116,7 @@ struct pca954x {
struct irq_domain *irq;
unsigned int irq_mask;
raw_spinlock_t lock;
+ bool irq_requested;
struct regulator *supply;

struct gpio_desc *reset_gpio;
@@ -464,8 +465,14 @@ static int pca954x_irq_setup(struct i2c_mux_core *muxc)
static void pca954x_cleanup(struct i2c_mux_core *muxc)
{
struct pca954x *data = i2c_mux_priv(muxc);
+ struct i2c_client *client = data->client;
int c, irq;

+ if (data->irq && data->irq_requested) {
+ devm_free_irq(&client->dev, client->irq, data);
+ data->irq_requested = false;
+ }
+
i2c_mux_del_adapters(muxc);

if (data->irq) {
@@ -656,6 +663,7 @@ static int pca954x_probe(struct i2c_client *client)
"pca954x", data);
if (ret)
goto fail_cleanup;
+ data->irq_requested = true;
}

/*
--
2.34.1