soundwire: bus_type: add sdw_master_device support
authorPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Mon, 18 May 2020 17:43:21 +0000 (01:43 +0800)
committerVinod Koul <vkoul@kernel.org>
Tue, 19 May 2020 07:14:35 +0000 (12:44 +0530)
In the existing SoundWire code, Master Devices are not explicitly
represented - only SoundWire Slave Devices are exposed (the use of
capital letters follows the SoundWire specification conventions).

With the existing code, the bus is handled without using a proper device,
and bus->dev typically points to a platform device. The right thing to
do as discussed in multiple reviews is use a device for each bus.

The sdw_master_device addition is done with minimal internal plumbing
and not exposed externally. The existing API based on
sdw_bus_master_add() and sdw_bus_master_delete() will deal with the
sdw_master_device life cycle, which minimizes changes to existing
drivers.

Note that the Intel code will be modified in follow-up patches (no
impact on any platform since the connection with ASoC is not supported
upstream so far).

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Acked-by: Jaroslav Kysela <perex@perex.cz>
Link: https://lore.kernel.org/r/20200518174322.31561-5-yung-chuan.liao@linux.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/soundwire/Makefile
drivers/soundwire/bus.c
drivers/soundwire/bus.h
drivers/soundwire/intel.c
drivers/soundwire/master.c [new file with mode: 0644]
drivers/soundwire/qcom.c
include/linux/soundwire/sdw.h

index e2cdff9..7319918 100644 (file)
@@ -4,7 +4,7 @@
 #
 
 #Bus Objs
-soundwire-bus-objs := bus_type.o bus.o slave.o mipi_disco.o stream.o
+soundwire-bus-objs := bus_type.o bus.o master.o slave.o mipi_disco.o stream.o
 obj-$(CONFIG_SOUNDWIRE) += soundwire-bus.o
 
 ifdef CONFIG_DEBUG_FS
index 03d72fa..11cfe43 100644 (file)
@@ -37,14 +37,21 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
        struct sdw_master_prop *prop = NULL;
        int ret;
 
-       if (!bus->dev) {
-               pr_err("SoundWire bus has no device\n");
+       if (!parent) {
+               pr_err("SoundWire parent device is not set\n");
                return -ENODEV;
        }
 
        ret = sdw_get_id(bus);
        if (ret) {
-               dev_err(bus->dev, "Failed to get bus id\n");
+               dev_err(parent, "Failed to get bus id\n");
+               return ret;
+       }
+
+       ret = sdw_master_device_add(bus, parent, fwnode);
+       if (ret) {
+               dev_err(parent, "Failed to add master device at link %d\n",
+                       bus->link_id);
                return ret;
        }
 
@@ -161,6 +168,7 @@ 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_master_device_del(bus);
 
        sdw_bus_debugfs_exit(bus);
        ida_free(&sdw_ida, bus->id);
index 204204a..93ab023 100644 (file)
@@ -19,6 +19,9 @@ static inline int sdw_acpi_find_slaves(struct sdw_bus *bus)
 int sdw_of_find_slaves(struct sdw_bus *bus);
 void sdw_extract_slave_id(struct sdw_bus *bus,
                          u64 addr, struct sdw_slave_id *id);
+int sdw_master_device_add(struct sdw_bus *bus, struct device *parent,
+                         struct fwnode_handle *fwnode);
+int sdw_master_device_del(struct sdw_bus *bus);
 
 #ifdef CONFIG_DEBUG_FS
 void sdw_bus_debugfs_init(struct sdw_bus *bus);
index 430f8ad..4cfdd07 100644 (file)
@@ -1099,7 +1099,6 @@ static int intel_probe(struct platform_device *pdev)
        sdw->cdns.registers = sdw->link_res->registers;
        sdw->cdns.instance = sdw->instance;
        sdw->cdns.msg_count = 0;
-       sdw->cdns.bus.dev = &pdev->dev;
        sdw->cdns.bus.link_id = pdev->id;
 
        sdw_cdns_probe(&sdw->cdns);
diff --git a/drivers/soundwire/master.c b/drivers/soundwire/master.c
new file mode 100644 (file)
index 0000000..6be0a02
--- /dev/null
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright(c) 2019-2020 Intel Corporation.
+
+#include <linux/device.h>
+#include <linux/acpi.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include "bus.h"
+
+static void sdw_master_device_release(struct device *dev)
+{
+       struct sdw_master_device *md = dev_to_sdw_master_device(dev);
+
+       kfree(md);
+}
+
+struct device_type sdw_master_type = {
+       .name =         "soundwire_master",
+       .release =      sdw_master_device_release,
+};
+
+/**
+ * sdw_master_device_add() - create a Linux Master Device representation.
+ * @bus: SDW bus instance
+ * @parent: parent device
+ * @fwnode: firmware node handle
+ */
+int sdw_master_device_add(struct sdw_bus *bus, struct device *parent,
+                         struct fwnode_handle *fwnode)
+{
+       struct sdw_master_device *md;
+       int ret;
+
+       if (!parent)
+               return -EINVAL;
+
+       md = kzalloc(sizeof(*md), GFP_KERNEL);
+       if (!md)
+               return -ENOMEM;
+
+       md->dev.bus = &sdw_bus_type;
+       md->dev.type = &sdw_master_type;
+       md->dev.parent = parent;
+       md->dev.of_node = parent->of_node;
+       md->dev.fwnode = fwnode;
+       md->dev.dma_mask = parent->dma_mask;
+
+       dev_set_name(&md->dev, "sdw-master-%d", bus->id);
+
+       ret = device_register(&md->dev);
+       if (ret) {
+               dev_err(parent, "Failed to add master: ret %d\n", ret);
+               /*
+                * On err, don't free but drop ref as this will be freed
+                * when release method is invoked.
+                */
+               put_device(&md->dev);
+               goto device_register_err;
+       }
+
+       /* add shortcuts to improve code readability/compactness */
+       md->bus = bus;
+       bus->dev = &md->dev;
+       bus->md = md;
+
+device_register_err:
+       return ret;
+}
+
+/**
+ * sdw_master_device_del() - delete a Linux Master Device representation.
+ * @bus: bus handle
+ *
+ * This function is the dual of sdw_master_device_add()
+ */
+int sdw_master_device_del(struct sdw_bus *bus)
+{
+       device_unregister(bus->dev);
+
+       return 0;
+}
index ea03bb9..a1c2a44 100644 (file)
@@ -784,7 +784,6 @@ static int qcom_swrm_probe(struct platform_device *pdev)
        mutex_init(&ctrl->port_lock);
        INIT_WORK(&ctrl->slave_work, qcom_swrm_slave_wq);
 
-       ctrl->bus.dev = dev;
        ctrl->bus.ops = &qcom_swrm_ops;
        ctrl->bus.port_ops = &qcom_swrm_port_ops;
        ctrl->bus.compute_params = &qcom_swrm_compute_params;
index a32cb26..7658d96 100644 (file)
@@ -632,6 +632,19 @@ struct sdw_slave {
 
 #define dev_to_sdw_dev(_dev) container_of(_dev, struct sdw_slave, dev)
 
+/**
+ * struct sdw_master_device - SoundWire 'Master Device' representation
+ * @dev: Linux device for this Master
+ * @bus: Bus handle shortcut
+ */
+struct sdw_master_device {
+       struct device dev;
+       struct sdw_bus *bus;
+};
+
+#define dev_to_sdw_master_device(d)    \
+       container_of(d, struct sdw_master_device, dev)
+
 struct sdw_driver {
        const char *name;
 
@@ -787,7 +800,8 @@ struct sdw_master_ops {
 
 /**
  * struct sdw_bus - SoundWire bus
- * @dev: Master linux device
+ * @dev: Shortcut to &bus->md->dev to avoid changing the entire code.
+ * @md: Master device
  * @link_id: Link id number, can be 0 to N, unique for each Master
  * @id: bus system-wide unique id
  * @slaves: list of Slaves on this bus
@@ -813,6 +827,7 @@ struct sdw_master_ops {
  */
 struct sdw_bus {
        struct device *dev;
+       struct sdw_master_device *md;
        unsigned int link_id;
        int id;
        struct list_head slaves;