adp5520_probe() registers up to four platform devices (keys, GPIO, LED and backlight) as children of the I2C client, but the driver no longer has a remove callback. The callback was dropped when the driver was made explicitly non-modular, on the assumption that a built-in driver is never removed. That assumption does not hold when the I2C adapter the client sits on goes away: the driver core still calls the driver's remove callback, and without one the child platform devices are never unregistered. They stay registered, keep a reference on the I2C client device and leak the memory they were allocated from. adp5520_remove_subdevs() already exists and is used by the probe error path, but it is not reachable on the removal path. Add a remove callback that unregisters the subdevices and drops the interrupt, in the same order as the probe error path. Fixes: 6b09274bacc7 ("mfd: adp5520: Make it explicitly non-modular") Cc: stable@vger.kernel.org Assisted-by: DeepSeek-V4.1-Flash and OpenAI Codex Signed-off-by: Wentao Liang --- drivers/mfd/adp5520.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c index bd6f4965ebc8..6b53b00efe52 100644 --- a/drivers/mfd/adp5520.c +++ b/drivers/mfd/adp5520.c @@ -305,6 +305,16 @@ static int adp5520_probe(struct i2c_client *client) return ret; } +static void adp5520_remove(struct i2c_client *client) +{ + struct adp5520_chip *chip = i2c_get_clientdata(client); + + adp5520_remove_subdevs(chip); + + if (chip->irq) + free_irq(chip->irq, chip); +} + static int adp5520_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -341,6 +351,7 @@ static struct i2c_driver adp5520_driver = { .suppress_bind_attrs = true, }, .probe = adp5520_probe, + .remove = adp5520_remove, .id_table = adp5520_id, }; builtin_i2c_driver(adp5520_driver); -- 2.34.1