2020-05-19 05:40:00

by Bard Liao

[permalink] [raw]
Subject: [PATCH v2 0/5] soundwire: bus_type: add sdw_master_device support

This series adds sdw master devices support.

changes in v2:
- Allocate sdw_master_device dynamically
- Use unique bus id as master id
- Keep checking parent devices
- Enable runtime_pm on Master device

Bard Liao (2):
soundwire: bus: add unique bus id
soundwire: master: add runtime pm support

Pierre-Louis Bossart (3):
soundwire: bus: rename sdw_bus_master_add/delete, add arguments
soundwire: bus_type: introduce sdw_slave_type and sdw_master_type
soundwire: bus_type: add sdw_master_device support

.../driver-api/soundwire/summary.rst | 7 +-
drivers/soundwire/Makefile | 2 +-
drivers/soundwire/bus.c | 47 ++++++++--
drivers/soundwire/bus.h | 3 +
drivers/soundwire/bus_type.c | 19 ++--
drivers/soundwire/intel.c | 9 +-
drivers/soundwire/master.c | 88 +++++++++++++++++++
drivers/soundwire/qcom.c | 7 +-
drivers/soundwire/slave.c | 8 +-
include/linux/soundwire/sdw.h | 24 ++++-
include/linux/soundwire/sdw_type.h | 9 +-
11 files changed, 191 insertions(+), 32 deletions(-)
create mode 100644 drivers/soundwire/master.c

--
2.17.1


2020-05-19 05:40:09

by Bard Liao

[permalink] [raw]
Subject: [PATCH v2 2/5] soundwire: bus_type: introduce sdw_slave_type and sdw_master_type

From: Pierre-Louis Bossart <[email protected]>

this is a preparatory patch before the introduction of the
sdw_master_type. The SoundWire slave support is slightly modified with
the use of a sdw_slave_type, and the uevent handling move to
slave.c (since it's not necessary for the master).

No functionality change other than moving code around.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
Signed-off-by: Bard Liao <[email protected]>
---
drivers/soundwire/bus_type.c | 19 +++++++++++++------
drivers/soundwire/slave.c | 8 +++++++-
include/linux/soundwire/sdw_type.h | 9 ++++++++-
3 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c
index 17f096dd6806..2c1a19caba51 100644
--- a/drivers/soundwire/bus_type.c
+++ b/drivers/soundwire/bus_type.c
@@ -33,13 +33,21 @@ sdw_get_device_id(struct sdw_slave *slave, struct sdw_driver *drv)

static int sdw_bus_match(struct device *dev, struct device_driver *ddrv)
{
- struct sdw_slave *slave = dev_to_sdw_dev(dev);
- struct sdw_driver *drv = drv_to_sdw_driver(ddrv);
+ struct sdw_slave *slave;
+ struct sdw_driver *drv;
+ int ret = 0;
+
+ if (is_sdw_slave(dev)) {
+ slave = dev_to_sdw_dev(dev);
+ drv = drv_to_sdw_driver(ddrv);

- return !!sdw_get_device_id(slave, drv);
+ ret = !!sdw_get_device_id(slave, drv);
+ }
+ return ret;
}

-int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size)
+static int sdw_slave_modalias(const struct sdw_slave *slave, char *buf,
+ size_t size)
{
/* modalias is sdw:m<mfg_id>p<part_id> */

@@ -47,7 +55,7 @@ int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size)
slave->id.mfg_id, slave->id.part_id);
}

-static int sdw_uevent(struct device *dev, struct kobj_uevent_env *env)
+int sdw_slave_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
char modalias[32];
@@ -63,7 +71,6 @@ static int sdw_uevent(struct device *dev, struct kobj_uevent_env *env)
struct bus_type sdw_bus_type = {
.name = "soundwire",
.match = sdw_bus_match,
- .uevent = sdw_uevent,
};
EXPORT_SYMBOL_GPL(sdw_bus_type);

diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c
index aace57fae7f8..ed068a004bd9 100644
--- a/drivers/soundwire/slave.c
+++ b/drivers/soundwire/slave.c
@@ -14,6 +14,12 @@ static void sdw_slave_release(struct device *dev)
kfree(slave);
}

+struct device_type sdw_slave_type = {
+ .name = "sdw_slave",
+ .release = sdw_slave_release,
+ .uevent = sdw_slave_uevent,
+};
+
static int sdw_slave_add(struct sdw_bus *bus,
struct sdw_slave_id *id, struct fwnode_handle *fwnode)
{
@@ -41,9 +47,9 @@ static int sdw_slave_add(struct sdw_bus *bus,
id->class_id, id->unique_id);
}

- slave->dev.release = sdw_slave_release;
slave->dev.bus = &sdw_bus_type;
slave->dev.of_node = of_node_get(to_of_node(fwnode));
+ slave->dev.type = &sdw_slave_type;
slave->bus = bus;
slave->status = SDW_SLAVE_UNATTACHED;
init_completion(&slave->enumeration_complete);
diff --git a/include/linux/soundwire/sdw_type.h b/include/linux/soundwire/sdw_type.h
index aaa7f4267c14..52eb66cd11bc 100644
--- a/include/linux/soundwire/sdw_type.h
+++ b/include/linux/soundwire/sdw_type.h
@@ -5,6 +5,13 @@
#define __SOUNDWIRE_TYPES_H

extern struct bus_type sdw_bus_type;
+extern struct device_type sdw_slave_type;
+extern struct device_type sdw_master_type;
+
+static inline int is_sdw_slave(const struct device *dev)
+{
+ return dev->type == &sdw_slave_type;
+}

#define drv_to_sdw_driver(_drv) container_of(_drv, struct sdw_driver, driver)

@@ -14,7 +21,7 @@ extern struct bus_type sdw_bus_type;
int __sdw_register_driver(struct sdw_driver *drv, struct module *owner);
void sdw_unregister_driver(struct sdw_driver *drv);

-int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size);
+int sdw_slave_uevent(struct device *dev, struct kobj_uevent_env *env);

/**
* module_sdw_driver() - Helper macro for registering a Soundwire driver
--
2.17.1

2020-05-19 05:40:13

by Bard Liao

[permalink] [raw]
Subject: [PATCH v2 3/5] soundwire: bus: add unique bus id

Adding an unique id for each bus.

Suggested-by: Vinod Koul <[email protected]>
Signed-off-by: Bard Liao <[email protected]>
---
drivers/soundwire/bus.c | 20 ++++++++++++++++++++
include/linux/soundwire/sdw.h | 2 ++
2 files changed, 22 insertions(+)

diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index 24064dbd74fa..2d24f183061d 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -9,6 +9,19 @@
#include <linux/soundwire/sdw.h>
#include "bus.h"

+static DEFINE_IDA(sdw_ida);
+
+static int sdw_get_id(struct sdw_bus *bus)
+{
+ int rc = ida_alloc(&sdw_ida, GFP_KERNEL);
+
+ if (rc < 0)
+ return rc;
+
+ bus->id = rc;
+ return 0;
+}
+
/**
* sdw_bus_master_add() - add a bus Master instance
* @bus: bus instance
@@ -29,6 +42,12 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
return -ENODEV;
}

+ ret = sdw_get_id(bus);
+ if (ret) {
+ dev_err(bus->dev, "Failed to get bus id\n");
+ return ret;
+ }
+
if (!bus->ops) {
dev_err(bus->dev, "SoundWire Bus ops are not set\n");
return -EINVAL;
@@ -144,6 +163,7 @@ void sdw_bus_master_delete(struct sdw_bus *bus)
device_for_each_child(bus->dev, NULL, sdw_delete_slave);

sdw_bus_debugfs_exit(bus);
+ ida_free(&sdw_ida, bus->id);
}
EXPORT_SYMBOL(sdw_bus_master_delete);

diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index 2003e8c55538..a32cb26f1815 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -789,6 +789,7 @@ struct sdw_master_ops {
* struct sdw_bus - SoundWire bus
* @dev: Master linux 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
* @assigned: Bitmap for Slave device numbers.
* Bit set implies used number, bit clear implies unused number.
@@ -813,6 +814,7 @@ struct sdw_master_ops {
struct sdw_bus {
struct device *dev;
unsigned int link_id;
+ int id;
struct list_head slaves;
DECLARE_BITMAP(assigned, SDW_MAX_DEVICES);
struct mutex bus_lock;
--
2.17.1

2020-05-19 05:40:23

by Bard Liao

[permalink] [raw]
Subject: [PATCH v2 4/5] soundwire: bus_type: add sdw_master_device support

From: Pierre-Louis Bossart <[email protected]>

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 <[email protected]>
Signed-off-by: Bard Liao <[email protected]>
---
drivers/soundwire/Makefile | 2 +-
drivers/soundwire/bus.c | 14 ++++--
drivers/soundwire/bus.h | 3 ++
drivers/soundwire/intel.c | 1 -
drivers/soundwire/master.c | 81 +++++++++++++++++++++++++++++++++++
drivers/soundwire/qcom.c | 1 -
include/linux/soundwire/sdw.h | 17 +++++++-
7 files changed, 112 insertions(+), 7 deletions(-)
create mode 100644 drivers/soundwire/master.c

diff --git a/drivers/soundwire/Makefile b/drivers/soundwire/Makefile
index e2cdff990e9f..7319918e0aec 100644
--- a/drivers/soundwire/Makefile
+++ b/drivers/soundwire/Makefile
@@ -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
diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index 2d24f183061d..c31a1c2788a9 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -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);
diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h
index 204204a26db8..93ab0234a491 100644
--- a/drivers/soundwire/bus.h
+++ b/drivers/soundwire/bus.h
@@ -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);
diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index 210459390046..3562f2106e30 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -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
index 000000000000..6be0a027def7
--- /dev/null
+++ b/drivers/soundwire/master.c
@@ -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;
+}
diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 401811d6627e..1c335ab1cd3f 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -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;
diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index a32cb26f1815..7658d9698dd5 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -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;
--
2.17.1

2020-05-19 05:41:46

by Bard Liao

[permalink] [raw]
Subject: [PATCH v2 5/5] soundwire: master: add runtime pm support

We need to enable runtime_pm on master device with generic helpers,
so that a Slave-initiated wake is propagated to the bus parent.

Signed-off-by: Bard Liao <[email protected]>
---
drivers/soundwire/master.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/drivers/soundwire/master.c b/drivers/soundwire/master.c
index 6be0a027def7..5411791e6aff 100644
--- a/drivers/soundwire/master.c
+++ b/drivers/soundwire/master.c
@@ -3,6 +3,7 @@

#include <linux/device.h>
#include <linux/acpi.h>
+#include <linux/pm_runtime.h>
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_type.h>
#include "bus.h"
@@ -14,9 +15,15 @@ static void sdw_master_device_release(struct device *dev)
kfree(md);
}

+static const struct dev_pm_ops master_dev_pm = {
+ SET_RUNTIME_PM_OPS(pm_generic_runtime_suspend,
+ pm_generic_runtime_resume, NULL)
+};
+
struct device_type sdw_master_type = {
.name = "soundwire_master",
.release = sdw_master_device_release,
+ .pm = &master_dev_pm,
};

/**
--
2.17.1

2020-05-19 06:51:49

by Jaroslav Kysela

[permalink] [raw]
Subject: Re: [PATCH v2 0/5] soundwire: bus_type: add sdw_master_device support

Dne 18. 05. 20 v 19:43 Bard Liao napsal(a):
> This series adds sdw master devices support.
>
> changes in v2:
> - Allocate sdw_master_device dynamically
> - Use unique bus id as master id
> - Keep checking parent devices
> - Enable runtime_pm on Master device
>
> Bard Liao (2):
> soundwire: bus: add unique bus id
> soundwire: master: add runtime pm support
>
> Pierre-Louis Bossart (3):
> soundwire: bus: rename sdw_bus_master_add/delete, add arguments
> soundwire: bus_type: introduce sdw_slave_type and sdw_master_type
> soundwire: bus_type: add sdw_master_device support
>
> .../driver-api/soundwire/summary.rst | 7 +-
> drivers/soundwire/Makefile | 2 +-
> drivers/soundwire/bus.c | 47 ++++++++--
> drivers/soundwire/bus.h | 3 +
> drivers/soundwire/bus_type.c | 19 ++--
> drivers/soundwire/intel.c | 9 +-
> drivers/soundwire/master.c | 88 +++++++++++++++++++
> drivers/soundwire/qcom.c | 7 +-
> drivers/soundwire/slave.c | 8 +-
> include/linux/soundwire/sdw.h | 24 ++++-
> include/linux/soundwire/sdw_type.h | 9 +-
> 11 files changed, 191 insertions(+), 32 deletions(-)
> create mode 100644 drivers/soundwire/master.c
>

The code looks really clean now. Thank you for your work.

Acked-by: Jaroslav Kysela <[email protected]>


Jaroslav

--
Jaroslav Kysela <[email protected]>
Linux Sound Maintainer; ALSA Project; Red Hat, Inc.

2020-05-19 07:24:21

by Vinod Koul

[permalink] [raw]
Subject: Re: [PATCH v2 0/5] soundwire: bus_type: add sdw_master_device support

On 19-05-20, 01:43, Bard Liao wrote:
> This series adds sdw master devices support.
>
> changes in v2:
> - Allocate sdw_master_device dynamically
> - Use unique bus id as master id
> - Keep checking parent devices
> - Enable runtime_pm on Master device

I tested on RB3 board and it looks good to me, Applied all now.

Thanks for the good cleanup :)

--
~Vinod