Re: [PATCH] mfd: da9150: balance IRQ wake on teardown

From: Lee Jones

Date: Tue Sep 22 2026 - 08:20:34 EST


On Sat, 12 Sep 2026, Myeonghun Pak wrote:

> DA9150 enables IRQ wake after registering its regmap IRQ chip, but does not
> disable it on a later probe failure or driver removal. This leaves the wake
> depth elevated after the handler is removed, and repeated bind attempts can
> accumulate the imbalance.
>
> Remember whether enabling IRQ wake succeeded and balance only a successful
> call. Remove MFD children first so their nested IRQ users are gone, then
> disable wake before removing the regmap IRQ chip. Preserve the existing
> non-fatal behavior when IRQ wake cannot be enabled.
>
> This issue was identified during our ongoing static-analysis research while
> reviewing kernel code.
>
> Fixes: b8fce55c09d3 ("mfd: Add support for DA9150 combined charger & fuel-gauge device")
> Assisted-by: OpenAI:GPT-5.6
> Co-developed-by: Ijae Kim <ae878000@xxxxxxxxx>
> Signed-off-by: Ijae Kim <ae878000@xxxxxxxxx>
> Signed-off-by: Myeonghun Pak <mhun512@xxxxxxxxx>
> ---
> drivers/mfd/da9150-core.c | 9 +++++++--
> include/linux/mfd/da9150/core.h | 1 +
> 2 files changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/mfd/da9150-core.c b/drivers/mfd/da9150-core.c
> index 5c59cc869fb3e..d91d419fea663 100644
> --- a/drivers/mfd/da9150-core.c
> +++ b/drivers/mfd/da9150-core.c
> @@ -450,7 +450,8 @@ static int da9150_probe(struct i2c_client *client)
>
> da9150->irq_base = regmap_irq_chip_get_base(da9150->regmap_irq_data);
>
> - enable_irq_wake(da9150->irq);
> + if (!enable_irq_wake(da9150->irq))
> + da9150->irq_wake_enabled = true;

da9150->irq_wake_enabled = !enable_irq_wake(da9150->irq);

> ret = mfd_add_devices(da9150->dev, -1, da9150_devs,
> ARRAY_SIZE(da9150_devs), NULL,
> @@ -463,6 +464,8 @@ static int da9150_probe(struct i2c_client *client)
> return 0;
>
> mfd_fail:
> + if (da9150->irq_wake_enabled)
> + disable_irq_wake(da9150->irq);

Or drop all of the checks and just call disable_irq_wake() on the error path.

> regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
> regmap_irq_fail:
> i2c_unregister_device(da9150->core_qif);
> @@ -474,8 +477,10 @@ static void da9150_remove(struct i2c_client *client)
> {
> struct da9150 *da9150 = i2c_get_clientdata(client);
>
> - regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
> mfd_remove_devices(da9150->dev);
> + if (da9150->irq_wake_enabled)
> + disable_irq_wake(da9150->irq);
> + regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
> i2c_unregister_device(da9150->core_qif);
> }
>
> diff --git a/include/linux/mfd/da9150/core.h b/include/linux/mfd/da9150/core.h
> index d116d5f3ef561..369698036d1aa 100644
> --- a/include/linux/mfd/da9150/core.h
> +++ b/include/linux/mfd/da9150/core.h
> @@ -65,6 +65,7 @@ struct da9150 {
> struct regmap_irq_chip_data *regmap_irq_data;
> int irq;
> int irq_base;
> + bool irq_wake_enabled;
> };
>
> /* Device I/O - Query Interface for FG and standard register access */
> --
> 2.47.1
>

--
Lee Jones