[PATCH v2 2/3] soundwire: bus: Expose a helper to remove devices from the bus
From: Charles Keepax
Date: Fri Sep 25 2026 - 11:43:12 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.
Signed-off-by: Charles Keepax <ckeepax@xxxxxxxxxxxxxxxxxxxxx>
---
New since v1.
drivers/soundwire/bus.c | 43 +++++++++++++++++++++++++----------
include/linux/soundwire/sdw.h | 1 +
2 files changed, 32 insertions(+), 12 deletions(-)
diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index 1488b6540844c..4c4e69a58fbef 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);
@@ -177,18 +176,37 @@ 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);
+
+ put_device(&slave->dev);
+ }
}
/**
@@ -199,7 +217,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