diff --git a/sound/soc/sdca/sdca_class.c b/sound/soc/sdca/sdca_class.c index 918b638acb57..5def6ae2d99f 100644 --- a/sound/soc/sdca/sdca_class.c +++ b/sound/soc/sdca/sdca_class.c @@ -137,6 +137,13 @@ static const struct regmap_config class_dev_regmap_config = { .unlock = class_regmap_unlock, }; +static void class_remove_functions(void *data) +{ + struct sdca_class_drv *drv = data; + + sdca_dev_unregister_functions(drv->sdw); +} + static void class_boot_work(struct work_struct *work) { struct sdca_class_drv *drv = container_of(work, @@ -157,6 +164,11 @@ static void class_boot_work(struct work_struct *work) if (ret) goto err; + /* Ensure function drivers are removed before the IRQ is destroyed */ + ret = devm_add_action_or_reset(drv->dev, class_remove_functions, drv); + if (ret) + goto err; + dev_dbg(drv->dev, "boot work complete\n"); pm_runtime_mark_last_busy(drv->dev); @@ -168,15 +180,6 @@ static void class_boot_work(struct work_struct *work) pm_runtime_put_sync(drv->dev); } -static void class_dev_remove(void *data) -{ - struct sdca_class_drv *drv = data; - - cancel_work_sync(&drv->boot_work); - - sdca_dev_unregister_functions(drv->sdw); -} - static int class_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *id) { struct device *dev = &sdw->dev; @@ -230,15 +233,19 @@ static int class_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *id if (ret) return ret; - ret = devm_add_action_or_reset(dev, class_dev_remove, drv); - if (ret) - return ret; - queue_work(system_long_wq, &drv->boot_work); return 0; } +static void class_sdw_remove(struct sdw_slave *sdw) +{ + struct device *dev = &sdw->dev; + struct sdca_class_drv *drv = dev_get_drvdata(dev); + + cancel_work_sync(&drv->boot_work); +} + static int class_suspend(struct device *dev) { struct sdca_class_drv *drv = dev_get_drvdata(dev); @@ -328,6 +335,7 @@ static struct sdw_driver class_sdw_driver = { }, .probe = class_sdw_probe, + .remove = class_sdw_remove, .id_table = class_sdw_id, .ops = &class_sdw_ops, };