From 86bcfdc6f1e1f8943fbe12256b3c89a66ebbad03 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 4 Sep 2026 14:12:43 +0100 Subject: [PATCH] mfd: cs42l43: Move cancel_work_sync() into remove The cs42l43 driver kicks off a work item waiting for the device to appear on the SoundWire bus, once the device appears the MFD children are added and the clean up is then done through devres. As the work is synchronised in from the devres clean up this could lead to new devres items being added after the clean up has started, if the driver is removed before the work has fully completed. The work should be synchronised before any devres clean up is started. Fixes: 0f35dc4bd50d ("mfd: cs42l43: Use devres for remove as well") Signed-off-by: Charles Keepax Link: https://patch.msgid.link/20260904131243.755201-1-ckeepax@opensource.cirrus.com Signed-off-by: Lee Jones --- drivers/mfd/cs42l43-i2c.c | 8 ++++++++ drivers/mfd/cs42l43-sdw.c | 8 ++++++++ drivers/mfd/cs42l43.c | 12 ++++++++---- drivers/mfd/cs42l43.h | 1 + 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/drivers/mfd/cs42l43-i2c.c b/drivers/mfd/cs42l43-i2c.c index dcc167f78d8a..2f1862199618 100644 --- a/drivers/mfd/cs42l43-i2c.c +++ b/drivers/mfd/cs42l43-i2c.c @@ -54,6 +54,13 @@ static int cs42l43_i2c_probe(struct i2c_client *i2c) return cs42l43_dev_probe(cs42l43); } +static void cs42l43_i2c_remove(struct i2c_client *i2c) +{ + struct cs42l43 *cs42l43 = dev_get_drvdata(&i2c->dev); + + cs42l43_dev_remove(cs42l43); +} + #if IS_ENABLED(CONFIG_OF) static const struct of_device_id cs42l43_of_match[] = { { .compatible = "cirrus,cs42l43", .data = (void *)CS42L43_DEVID_VAL }, @@ -83,6 +90,7 @@ static struct i2c_driver cs42l43_i2c_driver = { }, .probe = cs42l43_i2c_probe, + .remove = cs42l43_i2c_remove, }; module_i2c_driver(cs42l43_i2c_driver); diff --git a/drivers/mfd/cs42l43-sdw.c b/drivers/mfd/cs42l43-sdw.c index 2d4a192dcc01..22e4c1fe9298 100644 --- a/drivers/mfd/cs42l43-sdw.c +++ b/drivers/mfd/cs42l43-sdw.c @@ -180,6 +180,13 @@ static int cs42l43_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id * return cs42l43_dev_probe(cs42l43); } +static void cs42l43_sdw_remove(struct sdw_slave *sdw) +{ + struct cs42l43 *cs42l43 = dev_get_drvdata(&sdw->dev); + + cs42l43_dev_remove(cs42l43); +} + static const struct sdw_device_id cs42l43_sdw_id[] = { SDW_SLAVE_ENTRY(0x01FA, 0x4243, (void *)CS42L43_DEVID_VAL), SDW_SLAVE_ENTRY(0x01FA, 0x2A3B, (void *)CS42L43B_DEVID_VAL), @@ -195,6 +202,7 @@ static struct sdw_driver cs42l43_sdw_driver = { }, .probe = cs42l43_sdw_probe, + .remove = cs42l43_sdw_remove, .id_table = cs42l43_sdw_id, .ops = &cs42l43_sdw_ops, }; diff --git a/drivers/mfd/cs42l43.c b/drivers/mfd/cs42l43.c index 592677e1db41..a83b62064dae 100644 --- a/drivers/mfd/cs42l43.c +++ b/drivers/mfd/cs42l43.c @@ -1105,15 +1105,19 @@ static int cs42l43_power_down(struct cs42l43 *cs42l43) return 0; } -static void cs42l43_dev_remove(void *data) +static void cs42l43_dev_power_down(void *data) { struct cs42l43 *cs42l43 = data; - cancel_work_sync(&cs42l43->boot_work); - cs42l43_power_down(cs42l43); } +void cs42l43_dev_remove(struct cs42l43 *cs42l43) +{ + flush_work(&cs42l43->boot_work); +} +EXPORT_SYMBOL_NS_GPL(cs42l43_dev_remove, "MFD_CS42L43"); + int cs42l43_dev_probe(struct cs42l43 *cs42l43) { int i, ret; @@ -1159,7 +1163,7 @@ int cs42l43_dev_probe(struct cs42l43 *cs42l43) if (ret) return ret; - ret = devm_add_action_or_reset(cs42l43->dev, cs42l43_dev_remove, cs42l43); + ret = devm_add_action_or_reset(cs42l43->dev, cs42l43_dev_power_down, cs42l43); if (ret) return ret; diff --git a/drivers/mfd/cs42l43.h b/drivers/mfd/cs42l43.h index a0068f6572e2..862bc6fb68cb 100644 --- a/drivers/mfd/cs42l43.h +++ b/drivers/mfd/cs42l43.h @@ -25,5 +25,6 @@ bool cs42l43_precious_register(struct device *dev, unsigned int reg); bool cs42l43_volatile_register(struct device *dev, unsigned int reg); int cs42l43_dev_probe(struct cs42l43 *cs42l43); +void cs42l43_dev_remove(struct cs42l43 *cs42l43); #endif /* CS42L43_CORE_INT_H */