[PATCH v3 2/3] soundwire: bus: Expose a helper to remove devices from the bus

From: Charles Keepax

Date: Mon Oct 12 2026 - 07:21:24 EST


Some SoundWire controllers may have features such as IRQs that are
needed to support peripheral operation, it is desirable to continue
to support these whilst peripheral drivers are removed. However,
the current sdw_bus_master_delete() monolithically removes the
peripherals and destroys the controller giving no chance for the
controller driver to perform clean up after the slaves are removed,
but before it is itself destroyed.

Split out a separate helper function that only removes the
peripherals, this will allow drivers that require this to sequence
things appropriately. The functionality of the current helper is
left as is, if the peripherals have already been removed the call
to do this is a no-op which allows drivers that don't need this
functionality to remain untouched.

Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@xxxxxxxxx>
Signed-off-by: Charles Keepax <ckeepax@xxxxxxxxxxxxxxxxxxxxx>
---

No change since v2.

drivers/soundwire/bus.c | 44 +++++++++++++++++++++++++----------
include/linux/soundwire/sdw.h | 1 +
2 files changed, 33 insertions(+), 12 deletions(-)

diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index eddff9a5fd35d..c97f6c27fa854 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -169,7 +169,6 @@ EXPORT_SYMBOL(sdw_bus_master_add);
static int sdw_delete_slave(struct device *dev, void *data)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
- struct sdw_bus *bus = slave->bus;

pm_runtime_disable(dev);

@@ -186,18 +185,38 @@ static int sdw_delete_slave(struct device *dev, void *data)
*/
device_del(dev);

- mutex_lock(&bus->bus_lock);
- if (slave->dev_num) { /* clear dev_num if assigned */
- clear_bit(slave->dev_num, bus->assigned);
- if (bus->ops && bus->ops->put_device_num)
- bus->ops->put_device_num(bus, slave);
- }
- list_del_init(&slave->node);
- mutex_unlock(&bus->bus_lock);
+ return 0;
+}

- put_device(dev);
+/**
+ * sdw_bus_slaves_delete() - delete all peripherals on a bus
+ * @bus: bus with peripherals to be deleted
+ *
+ * Delete the child devices.
+ */
+void sdw_bus_slaves_delete(struct sdw_bus *bus)
+{
+ device_for_each_child(bus->dev, NULL, sdw_delete_slave);
+}
+EXPORT_SYMBOL(sdw_bus_slaves_delete);

- return 0;
+static void sdw_bus_slaves_put(struct sdw_bus *bus)
+{
+ struct sdw_slave *slave, *tmp;
+
+ list_for_each_entry_safe(slave, tmp, &bus->slaves, node) {
+ mutex_lock(&bus->bus_lock);
+ if (slave->dev_num) { /* clear dev_num if assigned */
+ clear_bit(slave->dev_num, bus->assigned);
+ if (bus->ops && bus->ops->put_device_num)
+ bus->ops->put_device_num(bus, slave);
+ }
+ list_del_init(&slave->node);
+ mutex_unlock(&bus->bus_lock);
+
+ /* See comment in sdw_delete_slave() */
+ put_device(&slave->dev);
+ }
}

/**
@@ -208,7 +227,8 @@ static int sdw_delete_slave(struct device *dev, void *data)
*/
void sdw_bus_master_delete(struct sdw_bus *bus)
{
- device_for_each_child(bus->dev, NULL, sdw_delete_slave);
+ sdw_bus_slaves_delete(bus);
+ sdw_bus_slaves_put(bus);

sdw_irq_delete(bus);

diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index f710e5932b4b2..df9ee56493b17 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -899,6 +899,7 @@ struct sdw_master_ops {

int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
struct fwnode_handle *fwnode);
+void sdw_bus_slaves_delete(struct sdw_bus *bus);
void sdw_bus_master_delete(struct sdw_bus *bus);

void sdw_show_ping_status(struct sdw_bus *bus, bool sync_delay);
--
2.47.3