diff mbox

[RFC,06/14] SoundWire: Add register/unregister APIs

Message ID 1477053673-16021-7-git-send-email-hardik.t.shah@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Shah, Hardik T Oct. 21, 2016, 12:41 p.m. UTC
This patch adds following SoundWire bus driver APIs.

    1. Register SoundWire Master device and driver.
    2. Register SoundWire Slave driver.
    3. Register Slave device capabilities.

Signed-off-by: Hardik Shah <hardik.t.shah@intel.com>
Signed-off-by: Sanyog Kale <sanyog.r.kale@intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 sound/Kconfig        |    2 +
 sound/Makefile       |    1 +
 sound/sdw/Kconfig    |    6 +
 sound/sdw/Makefile   |    1 +
 sound/sdw/sdw.c      |  886 ++++++++++++++++++++++++++++++++++++++++++++++++++
 sound/sdw/sdw_priv.h |  102 ++++++
 6 files changed, 998 insertions(+)
 create mode 100644 sound/sdw/Kconfig
 create mode 100644 sound/sdw/Makefile
 create mode 100644 sound/sdw/sdw.c
 create mode 100644 sound/sdw/sdw_priv.h

Comments

Mark Brown Nov. 14, 2016, 1:37 p.m. UTC | #1
On Fri, Oct 21, 2016 at 06:11:04PM +0530, Hardik Shah wrote:

> +static void sdw_mstr_release(struct device *dev)
> +{
> +	struct sdw_master *mstr = to_sdw_master(dev);
> +
> +	complete(&mstr->slv_released_complete);
> +}

Other buses don't do this...  this is a big warning sign that you're
abusing the driver model.

> +/**
> + * sdw_slv_verify - return parameter as sdw_slave, or NULL
> + * @dev: device, probably from some driver model iterator
> + *
> + * When traversing the driver model tree, perhaps using driver model
> + * iterators like @device_for_each_child(), you can't assume very much
> + * about the nodes you find. Use this function to avoid oopses caused
> + * by wrongly treating some non-SDW device as an sdw_slave.
> + */

This is also *very* scary, especially given that there's no analysis
presented as to why there might be random other things on the bus.  Why
does SoundWire need this when other buses don't?

> +static struct sdw_slave *sdw_slv_verify(struct device *dev)
> +{
> +	return (dev->type == &sdw_slv_type)
> +			? to_sdw_slave(dev)
> +			: NULL;

This is needlessly obfuscated, if you want to write an if statement
write an if statement.

> +static int sdw_slv_match(struct device *dev, struct device_driver *driver)
> +{
> +	struct sdw_slave *sdw_slv;
> +	struct sdw_driver *sdw_drv = to_sdw_driver(driver);
> +	struct sdw_slave_driver *drv;
> +	int ret = 0;
> +
> +
> +	if (sdw_drv->driver_type != SDW_DRIVER_TYPE_SLAVE)
> +		return ret;

Why do we need a check like this?

> +static int sdw_mstr_probe(struct device *dev)
> +{
> +	const struct sdw_master_driver *sdrv =
> +					to_sdw_master_driver(dev->driver);
> +	struct sdw_master *mstr = to_sdw_master(dev);
> +	int ret;
> +
> +	ret = dev_pm_domain_attach(dev, true);
> +
> +	if (ret != -EPROBE_DEFER) {
> +		ret = sdrv->probe(mstr, sdw_match_mstr(sdrv->id_table, mstr));
> +		if (ret < 0)
> +			dev_pm_domain_detach(dev, true);
> +	}

This looks *very* broken.  Surely if we fail to attach a pm_domain for
any reason other than one not being there to attach we shouldn't be
trying to probe the device?

> +EXPORT_SYMBOL_GPL(snd_sdw_master_register_driver);

This is EXPORT_SYMBOL_GPL() but the bus itself is dual licensed GPL/BSD
- seems a bit inconsistent.

> +/**
> + * snd_sdw_master_add: Registers the SoundWire Master interface. This needs
> + *	to be called for each Master interface supported by SoC. This
> + *	represents One clock and data line (Optionally multiple data lanes)
> + *	of Master interface.
> + *
> + * @master: the Master to be added.
> + */
> +int snd_sdw_master_add(struct sdw_master *master)

This lies at the heart of the issues that seem to exist with the misuse
of the driver model in this code.  Normally what we see is that the
controller would instantiate as whatever bus type the controller is
attached by (typically a PCI or platform device) and then it wouild
register a bus with the bus subsystem which would then instantiate
slaves.  Instead we have this system where the bus is registered by
something in the system and then the master is a driver on the bus
parallel to the slaves but with a separate driver type that causes
confusion.  Without having seen a master driver it's not even clear how
this is going to work and allow the master to talk to its own hardware.
Vinod Koul Nov. 15, 2016, 1:55 p.m. UTC | #2
On Mon, Nov 14, 2016 at 01:37:51PM +0000, Mark Brown wrote:
> On Fri, Oct 21, 2016 at 06:11:04PM +0530, Hardik Shah wrote:
> 
> > +static void sdw_mstr_release(struct device *dev)
> > +{
> > +	struct sdw_master *mstr = to_sdw_master(dev);
> > +
> > +	complete(&mstr->slv_released_complete);
> > +}
> 
> Other buses don't do this...  this is a big warning sign that you're
> abusing the driver model.

The whole master enumeration stuff, as we discussed in LPC will go away now.
So it will be more like other buses :)

> > +/**
> > + * sdw_slv_verify - return parameter as sdw_slave, or NULL
> > + * @dev: device, probably from some driver model iterator
> > + *
> > + * When traversing the driver model tree, perhaps using driver model
> > + * iterators like @device_for_each_child(), you can't assume very much
> > + * about the nodes you find. Use this function to avoid oopses caused
> > + * by wrongly treating some non-SDW device as an sdw_slave.
> > + */
> 
> This is also *very* scary, especially given that there's no analysis
> presented as to why there might be random other things on the bus.  Why
> does SoundWire need this when other buses don't?

Sure I will double check on this one and sounds to me we cna remove this..

> 
> > +static struct sdw_slave *sdw_slv_verify(struct device *dev)
> > +{
> > +	return (dev->type == &sdw_slv_type)
> > +			? to_sdw_slave(dev)
> > +			: NULL;
> 
> This is needlessly obfuscated, if you want to write an if statement
> write an if statement.

Sure thing

> > +static int sdw_slv_match(struct device *dev, struct device_driver *driver)
> > +{
> > +	struct sdw_slave *sdw_slv;
> > +	struct sdw_driver *sdw_drv = to_sdw_driver(driver);
> > +	struct sdw_slave_driver *drv;
> > +	int ret = 0;
> > +
> > +
> > +	if (sdw_drv->driver_type != SDW_DRIVER_TYPE_SLAVE)
> > +		return ret;
> 
> Why do we need a check like this?

Since folks were doing both slave and master matches, this was done to be
double sure, but this will go away now.

> > +static int sdw_mstr_probe(struct device *dev)
> > +{
> > +	const struct sdw_master_driver *sdrv =
> > +					to_sdw_master_driver(dev->driver);
> > +	struct sdw_master *mstr = to_sdw_master(dev);
> > +	int ret;
> > +
> > +	ret = dev_pm_domain_attach(dev, true);
> > +
> > +	if (ret != -EPROBE_DEFER) {
> > +		ret = sdrv->probe(mstr, sdw_match_mstr(sdrv->id_table, mstr));
> > +		if (ret < 0)
> > +			dev_pm_domain_detach(dev, true);
> > +	}
> 
> This looks *very* broken.  Surely if we fail to attach a pm_domain for
> any reason other than one not being there to attach we shouldn't be
> trying to probe the device?

Yes I agree, we shouldnt be doing probing in that case. Will fix that up.

> 
> > +EXPORT_SYMBOL_GPL(snd_sdw_master_register_driver);
> 
> This is EXPORT_SYMBOL_GPL() but the bus itself is dual licensed GPL/BSD
> - seems a bit inconsistent.

Thanks for pointing this out. The symbols should use EXPORT_SYMBOL() only
and the ones which link to other kernel GPL ones would need to be GPL ones.

> > +/**
> > + * snd_sdw_master_add: Registers the SoundWire Master interface. This needs
> > + *	to be called for each Master interface supported by SoC. This
> > + *	represents One clock and data line (Optionally multiple data lanes)
> > + *	of Master interface.
> > + *
> > + * @master: the Master to be added.
> > + */
> > +int snd_sdw_master_add(struct sdw_master *master)
> 
> This lies at the heart of the issues that seem to exist with the misuse
> of the driver model in this code.  Normally what we see is that the
> controller would instantiate as whatever bus type the controller is
> attached by (typically a PCI or platform device) and then it wouild
> register a bus with the bus subsystem which would then instantiate
> slaves.  Instead we have this system where the bus is registered by
> something in the system and then the master is a driver on the bus
> parallel to the slaves but with a separate driver type that causes
> confusion.  Without having seen a master driver it's not even clear how
> this is going to work and allow the master to talk to its own hardware.

Yes as discussed the whole master stuff will eb redone so you wont see these
bits in next rev.
diff mbox

Patch

diff --git a/sound/Kconfig b/sound/Kconfig
index 5a240e0..9f67cf7 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -108,6 +108,8 @@  source "sound/parisc/Kconfig"
 
 source "sound/soc/Kconfig"
 
+source "sound/sdw/Kconfig"
+
 endif # SND
 
 menuconfig SOUND_PRIME
diff --git a/sound/Makefile b/sound/Makefile
index c41bdf5..914101e 100644
--- a/sound/Makefile
+++ b/sound/Makefile
@@ -3,6 +3,7 @@ 
 
 obj-$(CONFIG_SOUND) += soundcore.o
 obj-$(CONFIG_SOUND_PRIME) += oss/
+obj-$(CONFIG_SOUND_SDW) += sdw/
 obj-$(CONFIG_DMASOUND) += oss/
 obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \
 	firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/
diff --git a/sound/sdw/Kconfig b/sound/sdw/Kconfig
new file mode 100644
index 0000000..052079f
--- /dev/null
+++ b/sound/sdw/Kconfig
@@ -0,0 +1,6 @@ 
+config SOUND_SDW
+	tristate
+	help
+	  SoundWire interface is typically used for transporting data
+	  related to audio functions. Concerned drivers should "select"
+	  this.
diff --git a/sound/sdw/Makefile b/sound/sdw/Makefile
new file mode 100644
index 0000000..6ed1881
--- /dev/null
+++ b/sound/sdw/Makefile
@@ -0,0 +1 @@ 
+obj-$(CONFIG_SOUND_SDW)                       += sdw.o
diff --git a/sound/sdw/sdw.c b/sound/sdw/sdw.c
new file mode 100644
index 0000000..d4e79b8a
--- /dev/null
+++ b/sound/sdw/sdw.c
@@ -0,0 +1,886 @@ 
+/*
+ * sdw.c - SoundWire bus driver implementation.
+ *
+ * Author: Hardik Shah <hardik.t.shah@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2016 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_domain.h>
+#include <sound/sdw_bus.h>
+#include <sound/sdw_master.h>
+#include <sound/sdw_slave.h>
+
+#include "sdw_priv.h"
+
+/*
+ * Global SoundWire core instance contains list of Masters registered, core
+ *	lock and SoundWire stream tags.
+ */
+struct snd_sdw_core snd_sdw_core;
+
+static void sdw_slv_release(struct device *dev)
+{
+	kfree(to_sdw_slave(dev));
+}
+
+static void sdw_mstr_release(struct device *dev)
+{
+	struct sdw_master *mstr = to_sdw_master(dev);
+
+	complete(&mstr->slv_released_complete);
+}
+
+static struct device_type sdw_slv_type = {
+	.groups		= NULL,
+	.release	= sdw_slv_release,
+};
+
+static struct device_type sdw_mstr_type = {
+	.groups		= NULL,
+	.release	= sdw_mstr_release,
+};
+
+/**
+ * sdw_slv_verify - return parameter as sdw_slave, or NULL
+ * @dev: device, probably from some driver model iterator
+ *
+ * When traversing the driver model tree, perhaps using driver model
+ * iterators like @device_for_each_child(), you can't assume very much
+ * about the nodes you find. Use this function to avoid oopses caused
+ * by wrongly treating some non-SDW device as an sdw_slave.
+ */
+static struct sdw_slave *sdw_slv_verify(struct device *dev)
+{
+	return (dev->type == &sdw_slv_type)
+			? to_sdw_slave(dev)
+			: NULL;
+}
+
+/**
+ * sdw_mstr_verify: return parameter as sdw_master, or NULL
+ *
+ * @dev: device, probably from some driver model iterator
+ *
+ * When traversing the driver model tree, perhaps using driver model
+ * iterators like @device_for_each_child(), you can't assume very much
+ * about the nodes you find. Use this function to avoid oopses caused
+ * by wrongly treating some non-SDW device as an sdw_master.
+ */
+static struct sdw_master *sdw_mstr_verify(struct device *dev)
+{
+	return (dev->type == &sdw_mstr_type)
+			? to_sdw_master(dev)
+			: NULL;
+}
+
+static const struct sdw_slave_id *sdw_match_slv(const struct sdw_slave_id *id,
+					const struct sdw_slave *sdw_slv)
+{
+	const struct sdw_slave_priv *slv_priv = &sdw_slv->priv;
+
+	if (!id)
+		return NULL;
+
+	/*
+	 * IDs should be NULL terminated like the last ID in the list should
+	 * be null, as done for drivers like platform, i2c etc.
+	 */
+	while (id->name[0]) {
+		if (strncmp(slv_priv->name, id->name, SOUNDWIRE_NAME_SIZE) == 0)
+			return id;
+
+		id++;
+	}
+
+	return NULL;
+}
+
+static const struct sdw_master_id *sdw_match_mstr(
+			const struct sdw_master_id *id,
+			const struct sdw_master *sdw_mstr)
+{
+	if (!id)
+		return NULL;
+
+	/*
+	 * IDs should be NULL terminated like the last ID in the list should
+	 * be null, as done for drivers like platform, i2c etc.
+	 */
+	while (id->name[0]) {
+		if (strncmp(sdw_mstr->name, id->name, SOUNDWIRE_NAME_SIZE) == 0)
+			return id;
+		id++;
+	}
+	return NULL;
+}
+
+static int sdw_slv_match(struct device *dev, struct device_driver *driver)
+{
+	struct sdw_slave *sdw_slv;
+	struct sdw_driver *sdw_drv = to_sdw_driver(driver);
+	struct sdw_slave_driver *drv;
+	int ret = 0;
+
+
+	if (sdw_drv->driver_type != SDW_DRIVER_TYPE_SLAVE)
+		return ret;
+
+	drv = to_sdw_slave_driver(driver);
+	sdw_slv = to_sdw_slave(dev);
+
+	/*
+	 * We are matching based on the dev_id field, dev_id field is unique
+	 * based on part_id and manufacturer id. Device will be registered
+	 * based on dev_id and driver will also have same dev_id for device
+	 * its controlling.
+	 */
+	ret = (sdw_match_slv(drv->id_table, sdw_slv) != NULL);
+
+	if (ret < 0)
+		sdw_slv->priv.driver = drv;
+
+	return ret;
+}
+
+static int sdw_mstr_match(struct device *dev, struct device_driver *driver)
+{
+	struct sdw_master *sdw_mstr;
+	struct sdw_driver *sdw_drv = to_sdw_driver(driver);
+	struct sdw_master_driver *drv;
+	int ret = 0;
+
+	if (sdw_drv->driver_type != SDW_DRIVER_TYPE_MASTER)
+		return ret;
+
+	drv = to_sdw_master_driver(driver);
+	sdw_mstr = to_sdw_master(dev);
+
+	ret = (sdw_match_mstr(drv->id_table, sdw_mstr) != NULL);
+
+	if (driver->name && !ret)
+		ret = (strncmp(sdw_mstr->name, driver->name,
+			SOUNDWIRE_NAME_SIZE) == 0);
+
+	if (ret < 0)
+		sdw_mstr->driver = drv;
+
+	return ret;
+}
+
+static int sdw_mstr_probe(struct device *dev)
+{
+	const struct sdw_master_driver *sdrv =
+					to_sdw_master_driver(dev->driver);
+	struct sdw_master *mstr = to_sdw_master(dev);
+	int ret;
+
+	ret = dev_pm_domain_attach(dev, true);
+
+	if (ret != -EPROBE_DEFER) {
+		ret = sdrv->probe(mstr, sdw_match_mstr(sdrv->id_table, mstr));
+		if (ret < 0)
+			dev_pm_domain_detach(dev, true);
+	}
+
+	return ret;
+}
+
+static int sdw_slv_probe(struct device *dev)
+{
+	const struct sdw_slave_driver *sdrv = to_sdw_slave_driver(dev->driver);
+	struct sdw_slave *sdwslv = to_sdw_slave(dev);
+	int ret;
+
+	ret = dev_pm_domain_attach(dev, true);
+
+	if (ret != -EPROBE_DEFER) {
+		ret = sdrv->probe(sdwslv, sdw_match_slv(sdrv->id_table,
+							sdwslv));
+		if (ret < 0)
+			dev_pm_domain_detach(dev, true);
+	}
+
+	return ret;
+}
+
+static int sdw_mstr_remove(struct device *dev)
+{
+	const struct sdw_master_driver *sdrv =
+				to_sdw_master_driver(dev->driver);
+	int ret;
+
+	ret = sdrv->remove(to_sdw_master(dev));
+	dev_pm_domain_detach(dev, true);
+	return ret;
+
+}
+
+static int sdw_slv_remove(struct device *dev)
+{
+	const struct sdw_slave_driver *sdrv = to_sdw_slave_driver(dev->driver);
+	int ret;
+
+	ret = sdrv->remove(to_sdw_slave(dev));
+	dev_pm_domain_detach(dev, true);
+
+	return ret;
+}
+
+static void sdw_slv_shutdown(struct device *dev)
+{
+	const struct sdw_slave_driver *sdrv =
+				to_sdw_slave_driver(dev->driver);
+
+	sdrv->shutdown(to_sdw_slave(dev));
+}
+
+static void sdw_mstr_shutdown(struct device *dev)
+{
+	const struct sdw_master_driver *sdrv =
+				to_sdw_master_driver(dev->driver);
+
+	sdrv->shutdown(to_sdw_master(dev));
+}
+
+static int sdw_match(struct device *dev, struct device_driver *driver)
+{
+	struct sdw_slave *sdw_slv;
+	struct sdw_master *sdw_mstr;
+
+	sdw_slv = sdw_slv_verify(dev);
+	if (sdw_slv)
+		return sdw_slv_match(dev, driver);
+
+	sdw_mstr = sdw_mstr_verify(dev);
+	if (sdw_mstr)
+		return sdw_mstr_match(dev, driver);
+
+	/*
+	 * Returning 0 to calling function means match not found, so calling
+	 * function will not call probe
+	 */
+	return 0;
+
+}
+
+static const struct dev_pm_ops soundwire_pm = {
+	.suspend = pm_generic_suspend,
+	.resume = pm_generic_resume,
+	SET_RUNTIME_PM_OPS(
+		pm_generic_runtime_suspend,
+		pm_generic_runtime_resume,
+		NULL)
+};
+
+static struct bus_type sdw_bus_type = {
+	.name		= "soundwire",
+	.match		= sdw_match,
+	.pm		= &soundwire_pm,
+};
+
+/**
+ * snd_sdw_master_register_driver: SoundWire Master driver registration with
+ *	bus. This API will register the Master driver with the SoundWire
+ *	bus. It is typically called from the driver's module-init function.
+ *
+ * @driver: Master Driver to be associated with Master interface.
+ * @owner: Module owner, generally THIS module.
+ */
+int snd_sdw_master_register_driver(struct sdw_master_driver *driver,
+				struct module *owner)
+{
+	int ret;
+
+	if (!driver->probe)
+		return -EINVAL;
+
+	if (!driver->ops->xfer_msg || !driver->ops->reset_page_addr)
+		return -EINVAL;
+
+	if (!driver->port_ops->dpn_set_port_params ||
+		!driver->port_ops->dpn_set_port_transport_params ||
+		!driver->port_ops->dpn_port_enable_ch)
+		return -EINVAL;
+
+	driver->driver.probe = sdw_mstr_probe;
+
+	if (driver->remove)
+		driver->driver.remove = sdw_mstr_remove;
+	if (driver->shutdown)
+		driver->driver.shutdown = sdw_mstr_shutdown;
+
+	/* add the driver to the list of sdw drivers in the driver core */
+	driver->driver.owner = owner;
+	driver->driver.bus = &sdw_bus_type;
+
+	/*
+	 * When registration returns, the driver core will have called
+	 * probe() for all matching-but-unbound Slaves, devices which are
+	 * not bind to any driver still.
+	 */
+	ret = driver_register(&driver->driver);
+	if (ret)
+		return ret;
+
+	pr_debug("sdw-core: driver [%s] registered\n", driver->driver.name);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_sdw_master_register_driver);
+
+/**
+ * snd_sdw_slave_driver_register: SoundWire Slave driver registration with
+ *	bus. This API will register the Slave driver with the SoundWire bus.
+ *	It is typically called from the driver's module-init function.
+ *
+ * @driver: Driver to be associated with Slave.
+ * @owner: Module owner, generally THIS module.
+ */
+int snd_sdw_slave_driver_register(struct sdw_slave_driver *driver,
+				struct module *owner)
+{
+	int ret;
+
+	if (driver->probe)
+		driver->driver.probe = sdw_slv_probe;
+	if (driver->remove)
+		driver->driver.remove = sdw_slv_remove;
+	if (driver->shutdown)
+		driver->driver.shutdown = sdw_slv_shutdown;
+
+	/* Add the driver to the list of sdw drivers in the driver core */
+	driver->driver.owner = owner;
+	driver->driver.bus = &sdw_bus_type;
+
+	/*
+	 * When registration returns, the driver core will have called
+	 * probe() for all matching-but-unbound Slaves.
+	 */
+	ret = driver_register(&driver->driver);
+	if (ret)
+		return ret;
+
+	pr_debug("sdw-core: driver [%s] registered\n", driver->driver.name);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_sdw_slave_driver_register);
+
+static int sdw_copy_aud_mod_prop(struct sdw_port_aud_mode_prop *slv_prop,
+				struct sdw_port_aud_mode_prop *prop)
+{
+	/*
+	 * Currently goto is used in API to perform different
+	 * operations. TODO: Avoid usage of goto statement
+	 */
+	memcpy(slv_prop, prop, sizeof(*prop));
+
+	if (!prop->num_bus_freq_cfgs)
+		goto handle_sample_rate;
+
+	slv_prop->clk_freq_buf = kcalloc(prop->num_bus_freq_cfgs,
+					sizeof(unsigned int),
+					GFP_KERNEL);
+
+	if (!slv_prop->clk_freq_buf)
+		goto mem_error;
+
+	memcpy(slv_prop->clk_freq_buf, prop->clk_freq_buf,
+				(prop->num_bus_freq_cfgs *
+				sizeof(unsigned int)));
+
+handle_sample_rate:
+
+	if (!prop->num_sample_rate_cfgs)
+		return 0;
+
+	slv_prop->sample_rate_buf = kcalloc(prop->num_sample_rate_cfgs,
+					sizeof(unsigned int),
+					GFP_KERNEL);
+
+	if (!slv_prop->sample_rate_buf)
+		goto mem_error;
+
+	memcpy(slv_prop->sample_rate_buf, prop->sample_rate_buf,
+				(prop->num_sample_rate_cfgs *
+				sizeof(unsigned int)));
+
+	return 0;
+
+mem_error:
+	kfree(prop->clk_freq_buf);
+	kfree(slv_prop->sample_rate_buf);
+	return -ENOMEM;
+
+}
+
+static int sdw_update_dpn_caps(struct sdw_dpn_caps *slv_dpn_cap,
+					struct sdw_dpn_caps *dpn_cap)
+{
+	int j, ret = 0;
+	struct sdw_port_aud_mode_prop *slv_prop, *prop;
+
+	/*
+	 * Currently goto is used in API to perform different
+	 * operations. TODO: Avoid usage of goto statement
+	 */
+
+	/*
+	 * slv_prop and prop are using to make copy of mode properties.
+	 * prop holds mode properties received which needs to be updated to
+	 * slv_prop.
+	 */
+
+	memcpy(slv_dpn_cap, dpn_cap, sizeof(*dpn_cap));
+
+	/*
+	 * Copy bps (bits per sample) buffer as part of Slave capabilities
+	 */
+	if (!dpn_cap->num_bps)
+		goto handle_ch_cnt;
+
+	slv_dpn_cap->bps_buf = kcalloc(dpn_cap->num_bps, sizeof(u8),
+							GFP_KERNEL);
+
+	if (!slv_dpn_cap->bps_buf) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	memcpy(slv_dpn_cap->bps_buf, dpn_cap->bps_buf,
+			(dpn_cap->num_bps * sizeof(u8)));
+
+handle_ch_cnt:
+	if (!dpn_cap->num_ch_cnt)
+		goto handle_audio_mode_prop;
+
+	slv_dpn_cap->ch_cnt_buf = kcalloc(dpn_cap->num_ch_cnt, sizeof(u8),
+							GFP_KERNEL);
+	if (!dpn_cap->num_ch_cnt) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	/* Copy channel count buffer as part of Slave capabilities */
+	memcpy(slv_dpn_cap->ch_cnt_buf, dpn_cap->ch_cnt_buf,
+			(dpn_cap->num_ch_cnt * sizeof(u8)));
+
+handle_audio_mode_prop:
+
+	slv_dpn_cap->mode_properties = kzalloc((sizeof(*slv_prop) *
+				dpn_cap->num_audio_modes),
+				GFP_KERNEL);
+
+	if (!slv_dpn_cap->mode_properties) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	for (j = 0; j < dpn_cap->num_audio_modes; j++) {
+
+		prop = &dpn_cap->mode_properties[j];
+		slv_prop = &slv_dpn_cap->mode_properties[j];
+
+		/* Copy audio properties as part of Slave capabilities */
+		ret = sdw_copy_aud_mod_prop(slv_prop, prop);
+		if (ret < 0)
+			goto error;
+	}
+
+	return ret;
+
+error:
+	kfree(slv_dpn_cap->mode_properties);
+	kfree(slv_dpn_cap->ch_cnt_buf);
+	kfree(slv_dpn_cap->bps_buf);
+	return ret;
+
+}
+
+/* Free all the memory allocated for registering the capabilities */
+static void sdw_unregister_slv_caps(struct sdw_slave *sdw,
+		unsigned int num_port_direction)
+{
+	int i, j, k;
+	struct sdw_slave_caps *caps = &sdw->priv.caps;
+	struct sdw_dpn_caps *dpn_cap;
+	struct sdw_port_aud_mode_prop *mode_prop;
+	u8 ports;
+
+	for (i = 0; i < num_port_direction; i++) {
+
+		if (i == SDW_DATA_DIR_OUT)
+			ports = caps->num_src_ports;
+		else
+			ports = caps->num_sink_ports;
+		for (j = 0; j < ports; j++) {
+			dpn_cap = &caps->dpn_caps[i][j];
+			kfree(dpn_cap->bps_buf);
+			kfree(dpn_cap->ch_cnt_buf);
+
+			for (k = 0; k < dpn_cap->num_audio_modes; k++) {
+				mode_prop = dpn_cap->mode_properties;
+				kfree(mode_prop->clk_freq_buf);
+				kfree(mode_prop->sample_rate_buf);
+			}
+		}
+	}
+}
+
+static inline void sdw_copy_slv_caps(struct sdw_slave *sdw,
+				struct sdw_slave_caps *caps)
+{
+	struct sdw_slave_caps *slv_caps;
+
+	slv_caps = &sdw->priv.caps;
+
+	memcpy(slv_caps, caps, sizeof(*slv_caps));
+}
+
+/**
+ * snd_sdw_slave_register_caps: Register Slave device capabilities to the
+ *	bus driver. Since bus driver handles bunch of Slave register
+ *	programming it should be aware of Slave device capabilities. Slave
+ *	device is attached to bus based on enumeration. Once Slave driver is
+ *	attached to device and probe of Slave driver is called on device and
+ *	driver binding, Slave driver should call this function to register
+ *	its capabilities to bus. This should be the very first function to
+ *	bus driver from Slave driver once Slave driver is registered and
+ *	probed.
+ *
+ * @slave: SoundWire Slave handle.
+ * @cap: Slave caps to be registered to bus driver.
+ */
+int snd_sdw_slave_register_caps(struct sdw_slave *slave,
+					struct sdw_slave_caps *cap)
+{
+	struct sdw_slave_caps *caps;
+	struct sdw_dpn_caps *slv_dpn_cap, *dpn_cap;
+	int i, j, ret;
+	u8 ports;
+
+	caps = &slave->priv.caps;
+
+	sdw_copy_slv_caps(slave, cap);
+
+	for (i = 0; i < SDW_MAX_PORT_DIRECTIONS; i++) {
+		if (i == SDW_DATA_DIR_OUT)
+			ports = caps->num_src_ports;
+		else
+			ports = caps->num_sink_ports;
+
+		caps->dpn_caps[i] = kzalloc((sizeof(*slv_dpn_cap) *
+						ports), GFP_KERNEL);
+
+		if (caps->dpn_caps[i] == NULL) {
+			ret = -ENOMEM;
+			goto error;
+		}
+	}
+
+	for (i = 0; i < SDW_MAX_PORT_DIRECTIONS; i++) {
+
+		if (i == SDW_DATA_DIR_OUT)
+			ports = caps->num_src_ports;
+		else
+			ports = caps->num_sink_ports;
+
+		for (j = 0; j < ports; j++) {
+
+			dpn_cap = &cap->dpn_caps[i][j];
+			slv_dpn_cap = &caps->dpn_caps[i][j];
+
+			ret = sdw_update_dpn_caps(&caps->dpn_caps[i][j],
+						&cap->dpn_caps[i][j]);
+			if (ret < 0) {
+				dev_err(&slave->mstr->dev, "Failed to update Slave caps ret = %d\n", ret);
+				goto error;
+			}
+		}
+	}
+
+	slave->priv.slave_cap_updated = true;
+
+	return 0;
+
+error:
+	sdw_unregister_slv_caps(slave, i);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(snd_sdw_slave_register_caps);
+
+/**
+ * snd_sdw_master_add: Registers the SoundWire Master interface. This needs
+ *	to be called for each Master interface supported by SoC. This
+ *	represents One clock and data line (Optionally multiple data lanes)
+ *	of Master interface.
+ *
+ * @master: the Master to be added.
+ */
+int snd_sdw_master_add(struct sdw_master *master)
+{
+	int i, id, ret;
+	struct sdw_bus *sdw_bus = NULL;
+
+	/* Sanity checks */
+	if (unlikely(master->name[0] == '\0')) {
+		pr_err("sdw-core: Attempt to register a master with no name!\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&snd_sdw_core.core_mutex);
+
+	/* Always start bus with 0th Index */
+	id = idr_alloc(&snd_sdw_core.idr, master, 0, 0, GFP_KERNEL);
+
+	if (id < 0) {
+		mutex_unlock(&snd_sdw_core.core_mutex);
+		return id;
+	}
+
+	master->nr = id;
+
+	/*
+	 * Initialize the DeviceNumber in the Master structure. Each of
+	 * these is assigned to the Slaves enumerating on this Master
+	 * interface.
+	 */
+	for (i = 0; i <= SDW_MAX_DEVICES; i++)
+		master->sdw_addr[i].dev_num = i;
+
+	mutex_init(&master->lock);
+	mutex_init(&master->msg_lock);
+	INIT_LIST_HEAD(&master->slv_list);
+	INIT_LIST_HEAD(&master->mstr_rt_list);
+
+	sdw_bus = kzalloc(sizeof(*sdw_bus), GFP_KERNEL);
+	if (!sdw_bus) {
+		ret = -ENOMEM;
+		goto alloc_failed;
+	}
+
+	sdw_bus->mstr = master;
+	master->bus = sdw_bus;
+
+	dev_set_name(&master->dev, "sdw-%d", master->nr);
+	master->dev.bus = &sdw_bus_type;
+	master->dev.type = &sdw_mstr_type;
+
+	ret = device_register(&master->dev);
+	if (ret < 0)
+		goto dev_reg_failed;
+
+	dev_dbg(&master->dev, "master [%s] registered\n", master->name);
+
+	/*
+	 * Add bus to the list of buses inside core. This is list of Slave
+	 * devices enumerated on this bus. Adding new devices at end. It can
+	 * be added at any location in list.
+	 */
+	list_add_tail(&sdw_bus->bus_node, &snd_sdw_core.bus_list);
+	mutex_unlock(&snd_sdw_core.core_mutex);
+
+	return 0;
+
+dev_reg_failed:
+	kfree(sdw_bus);
+alloc_failed:
+	idr_remove(&snd_sdw_core.idr, master->nr);
+	mutex_unlock(&snd_sdw_core.core_mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(snd_sdw_master_add);
+
+static void sdw_unregister_slv(struct sdw_slave *sdw_slv)
+{
+	struct sdw_master *mstr;
+
+	mstr = sdw_slave_to_master(sdw_slv);
+
+	sdw_unregister_slv_caps(sdw_slv, SDW_MAX_PORT_DIRECTIONS);
+
+	mutex_lock(&mstr->lock);
+	list_del(&sdw_slv->priv.node);
+	mutex_unlock(&mstr->lock);
+
+	mstr->sdw_addr[sdw_slv->dev_num].assigned = false;
+
+	device_unregister(&sdw_slv->dev);
+	kfree(sdw_slv);
+}
+
+static int __unregister_slv(struct device *dev, void *dummy)
+{
+	struct sdw_slave *slave = sdw_slv_verify(dev);
+
+	if (slave)
+		sdw_unregister_slv(slave);
+
+	return 0;
+}
+
+/**
+ * snd_sdw_master_del - unregister SDW Master
+ *
+ * @master: the Master being unregistered
+ */
+void snd_sdw_master_del(struct sdw_master *master)
+{
+	struct sdw_master *found;
+
+	/* First make sure that this Master was ever added */
+	mutex_lock(&snd_sdw_core.core_mutex);
+	found = idr_find(&snd_sdw_core.idr, master->nr);
+
+	if (found != master) {
+		pr_debug("sdw-core: attempting to delete unregistered master [%s]\n",
+				master->name);
+		mutex_unlock(&snd_sdw_core.core_mutex);
+		return;
+	}
+	/*
+	 * Detach any active Slaves. This can't fail, thus we do not check
+	 * the returned value.
+	 */
+	device_for_each_child(&master->dev, NULL, __unregister_slv);
+
+	/* device name is gone after device_unregister */
+	dev_dbg(&master->dev, "master [%s] unregistered\n", master->name);
+
+	/* wait until all references to the device are gone */
+	init_completion(&master->slv_released_complete);
+	device_unregister(&master->dev);
+	wait_for_completion(&master->slv_released_complete);
+
+	/* free bus id */
+	idr_remove(&snd_sdw_core.idr, master->nr);
+	mutex_unlock(&snd_sdw_core.core_mutex);
+
+	/*
+	 * Clear the device structure in case this Master is ever going to
+	 * be added again
+	 */
+	memset(&master->dev, 0, sizeof(master->dev));
+}
+EXPORT_SYMBOL_GPL(snd_sdw_master_del);
+
+/**
+ * snd_sdw_master_get: Return the Master handle from Master number.
+ *	Increments the reference count of the module. Similar to
+ *	i2c_get_adapter.
+ *
+ * @nr: Master number.
+ *
+ * Returns Master handle on success, else NULL
+ */
+struct sdw_master *snd_sdw_master_get(int nr)
+{
+	struct sdw_master *master;
+
+	mutex_lock(&snd_sdw_core.core_mutex);
+
+	master = idr_find(&snd_sdw_core.idr, nr);
+	if (master && !try_module_get(master->driver->driver.owner))
+		master = NULL;
+
+	mutex_unlock(&snd_sdw_core.core_mutex);
+
+	return master;
+}
+EXPORT_SYMBOL_GPL(snd_sdw_master_get);
+
+/**
+ * snd_sdw_master_put: Reverses the effect of sdw_master_get
+ *
+ * @master: Master handle.
+ */
+void snd_sdw_master_put(struct sdw_master *master)
+{
+	if (master)
+		module_put(master->driver->driver.owner);
+}
+EXPORT_SYMBOL_GPL(snd_sdw_master_put);
+
+static void sdw_exit(void)
+{
+	bus_unregister(&sdw_bus_type);
+}
+
+static int sdw_init(void)
+{
+	int retval;
+
+	mutex_init(&snd_sdw_core.core_mutex);
+	INIT_LIST_HEAD(&snd_sdw_core.bus_list);
+	idr_init(&snd_sdw_core.idr);
+	retval = bus_register(&sdw_bus_type);
+
+	if (retval)
+		bus_unregister(&sdw_bus_type);
+	return retval;
+}
+
+subsys_initcall(sdw_init);
+module_exit(sdw_exit);
+
+MODULE_AUTHOR("Hardik Shah <hardik.t.shah@intel.com>");
+MODULE_AUTHOR("Sanyog Kale <sanyog.r.kale@intel.com>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("SoundWire bus driver");
+MODULE_ALIAS("platform:soundwire");
diff --git a/sound/sdw/sdw_priv.h b/sound/sdw/sdw_priv.h
new file mode 100644
index 0000000..5911aa6
--- /dev/null
+++ b/sound/sdw/sdw_priv.h
@@ -0,0 +1,102 @@ 
+/*
+ * sdw_priv.h - Private definition for SoundWire bus interface.
+ *
+ * Author: Hardik Shah <hardik.t.shah@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2016 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+
+#ifndef _LINUX_SDW_PRIV_H
+#define _LINUX_SDW_PRIV_H
+
+/**
+ * sdw_driver: Structure to typecast both Master and Slave driver to generic
+ *	SoundWire driver, to find out the driver type.
+ *
+ * @driver_type: Type of SoundWire driver, Master or Slave.
+ * @driver: Generic Linux driver.
+ */
+struct sdw_driver {
+	enum sdw_driver_type driver_type;
+	struct device_driver driver;
+};
+#define to_sdw_driver(d)			\
+		container_of(d, struct sdw_driver, driver)
+/**
+ * sdw_bus: Bus structure holding bus related information.
+ *
+ * @bus_node: Node to add the bus in the sdw_core list.
+ * @mstr: Master reference for the bus.
+ */
+
+struct sdw_bus {
+	struct list_head bus_node;
+	struct sdw_master *mstr;
+};
+
+/**
+ * snd_sdw_core: Global SoundWire structure. It handles all the streams
+ *	spawned across masters and has list of bus structure per every
+ *	Master registered.
+ *
+ * @bus_list: List of all the bus instance.
+ * @core_mutex: Global lock for all bus instances.
+ * @idr: For identifying the registered buses.
+ */
+struct snd_sdw_core {
+	struct list_head bus_list;
+	struct mutex core_mutex;
+	struct idr idr;
+};
+
+#endif /* _LINUX_SDW_PRIV_H */