soundwire: bus_type: add sdw_master_device support
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>
This commit is contained in:
parent
dbb50c7a99
commit
7ceaa40b93
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue