lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Fri, 21 Oct 2016 18:11:11 +0530
From:   Hardik Shah <hardik.t.shah@...el.com>
To:     alsa-devel@...a-project.org, linux-kernel@...r.kernel.org
Cc:     tiwai@...e.de, pierre-louis.bossart@...ux.intel.com,
        broonie@...nel.org, lgirdwood@...il.com, plai@...eaurora.org,
        patches.audio@...el.com, Sanyog Kale <sanyog.r.kale@...el.com>,
        Hardik Shah <hardik.t.shah@...el.com>
Subject: [RFC 13/14] SoundWire: Add stream and port configuration

From: Sanyog Kale <sanyog.r.kale@...el.com>

This patch adds APIs for stream and port configurations for SoundWire
bus driver.

Signed-off-by: Hardik Shah <hardik.t.shah@...el.com>
Signed-off-by: Sanyog Kale <sanyog.r.kale@...el.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@...ux.intel.com>
---
 sound/sdw/sdw.c      |  774 ++++++++++++++++++++++++++++++++++++++++++++++++++
 sound/sdw/sdw_priv.h |  449 +++++++++++++++++++++++++++++
 2 files changed, 1223 insertions(+)

diff --git a/sound/sdw/sdw.c b/sound/sdw/sdw.c
index 71d2550..ffbec9e 100644
--- a/sound/sdw/sdw.c
+++ b/sound/sdw/sdw.c
@@ -2358,6 +2358,780 @@ static enum sdw_clk_stop_mode sdw_slv_get_clk_stp_mode(struct sdw_slave *slave)
 }
 
 /**
+ * snd_sdw_release_stream_tag: Free the already assigned stream tag.
+ *	Reverses effect of "sdw_alloc_stream_tag"
+ *
+ * @stream_tag: Stream tag to be freed.
+ */
+void snd_sdw_release_stream_tag(unsigned int stream_tag)
+{
+	int i;
+	struct sdw_stream_tag *stream_tags = snd_sdw_core.stream_tags;
+
+	/* Acquire core lock */
+	mutex_lock(&snd_sdw_core.core_mutex);
+
+	/* Get stream tag data structure */
+	for (i = 0; i < SDW_NUM_STREAM_TAGS; i++) {
+		if (stream_tag == stream_tags[i].stream_tag) {
+
+			/* Reference count update */
+			sdw_dec_ref_count(&stream_tags[i].ref_count);
+
+			if (stream_tags[i].ref_count == 0)
+				/* Free up resources */
+				kfree(stream_tags[i].sdw_rt);
+		}
+	}
+
+	/* Release core lock */
+	mutex_unlock(&snd_sdw_core.core_mutex);
+}
+EXPORT_SYMBOL_GPL(snd_sdw_release_stream_tag);
+
+/**
+ * snd_sdw_alloc_stream_tag: Allocates unique stream_tag. Stream tag is
+ *	a unique identifier for each SoundWire stream across all SoundWire
+ *	bus instances. Stream tag is a software concept defined by bus
+ *	driver for stream management and not by MIPI SoundWire Spec. Each
+ *	SoundWire Stream is individually configured and controlled using the
+ *	stream tag. Multiple Master(s) and Slave(s) associated with the
+ *	stream, uses stream tag as an identifier. All the operations on the
+ *	stream e.g. stream configuration, port configuration, prepare and
+ *	enable of the ports are done based on stream tag. This API shall be
+ *	called once per SoundWire stream either by the Master or Slave
+ *	associated with the stream.
+ *
+ * @stream_tag: Stream tag returned by bus driver.
+ */
+int snd_sdw_alloc_stream_tag(unsigned int *stream_tag)
+{
+	int i;
+	int ret = -EINVAL;
+	struct sdw_runtime *sdw_rt;
+	struct sdw_stream_tag *stream_tags = snd_sdw_core.stream_tags;
+
+	/* Acquire core lock */
+	mutex_lock(&snd_sdw_core.core_mutex);
+
+	/* Allocate new stream tag and initialize resources */
+	for (i = 0; i < SDW_NUM_STREAM_TAGS; i++) {
+		if (!stream_tags[i].ref_count) {
+
+			*stream_tag = stream_tags[i].stream_tag;
+
+			/* Initialize stream lock */
+			mutex_init(&stream_tags[i].stream_lock);
+
+			/* Allocate resources for stream runtime handle */
+			sdw_rt = kzalloc(sizeof(*sdw_rt), GFP_KERNEL);
+			if (!sdw_rt) {
+				ret = -ENOMEM;
+				goto out;
+			}
+
+			/* Reference count update */
+			sdw_inc_ref_count(&stream_tags[i].ref_count);
+
+			/* Initialize Master and Slave list */
+			INIT_LIST_HEAD(&sdw_rt->slv_rt_list);
+			INIT_LIST_HEAD(&sdw_rt->mstr_rt_list);
+
+			/* Change stream state to ALLOC */
+			sdw_rt->stream_state = SDW_STATE_STRM_ALLOC;
+
+			stream_tags[i].sdw_rt = sdw_rt;
+
+			ret = 0;
+			break;
+		}
+	}
+out:
+	/* Release core lock */
+	mutex_unlock(&snd_sdw_core.core_mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(snd_sdw_alloc_stream_tag);
+
+/**
+ * sdw_config_mstr_stream: Checks if master runtime handle already
+ *	available, if not allocates and initialize Master runtime handle.
+ *
+ * @mstr: Master handle
+ * @stream_config: Stream configuration for the SoundWire audio stream.
+ * @sdw_rt: Stream runtime handle.
+ *
+ * Returns Master runtime handle.
+ */
+static struct sdw_mstr_runtime *sdw_config_mstr_stream(struct sdw_master *mstr,
+				struct sdw_stream_config *stream_config,
+				struct sdw_runtime *sdw_rt)
+{
+	struct sdw_mstr_runtime *mstr_rt = NULL;
+	struct sdw_stream_params *str_p;
+
+	/* Retrieve Master handle if already available */
+	list_for_each_entry(mstr_rt, &sdw_rt->mstr_rt_list, mstr_strm_node) {
+		if (mstr_rt->mstr == mstr)
+			return mstr_rt;
+	}
+
+	/* Allocate resources for Master runtime handle */
+	mstr_rt = kzalloc(sizeof(*mstr_rt), GFP_KERNEL);
+	if (!mstr_rt)
+		goto out;
+
+	/* Initialization of Master runtime handle */
+	INIT_LIST_HEAD(&mstr_rt->port_rt_list);
+	INIT_LIST_HEAD(&mstr_rt->slv_rt_list);
+	list_add_tail(&mstr_rt->mstr_strm_node, &sdw_rt->mstr_rt_list);
+	list_add_tail(&mstr_rt->mstr_node, &mstr->mstr_rt_list);
+
+	/* Update PCM parameters for Master */
+	mstr_rt->direction = stream_config->direction;
+	str_p = &mstr_rt->stream_params;
+	str_p->rate = stream_config->frame_rate;
+	str_p->channel_count = stream_config->channel_count;
+	str_p->bps = stream_config->bps;
+
+	/* Add reference for Master device handle */
+	mstr_rt->mstr = mstr;
+
+	/* Add reference for stream runtime handle */
+	mstr_rt->sdw_rt = sdw_rt;
+
+out:
+	return mstr_rt;
+}
+
+/**
+ * sdw_config_slave_stream: Allocate and initialize slave runtime handle.
+ *
+ * @slave: Slave handle
+ * @stream_config: Stream configuration for the SoundWire audio stream.
+ * @sdw_rt: Stream runtime handle.
+ *
+ * Returns Slave runtime handle.
+ */
+static struct sdw_slv_runtime *sdw_config_slv_stream(
+				struct sdw_slave *slave,
+				struct sdw_stream_config *stream_config,
+				struct sdw_runtime *sdw_rt)
+{
+	struct sdw_slv_runtime *slv_rt = NULL;
+	struct sdw_stream_params *str_p;
+
+	/* Allocate resources for Slave runtime handle */
+	slv_rt = kzalloc(sizeof(*slv_rt), GFP_KERNEL);
+	if (!slv_rt)
+		goto out;
+
+	/* Initialization of Slave runtime handle */
+	INIT_LIST_HEAD(&slv_rt->port_rt_list);
+
+	/* Update PCM parameters for Slave */
+	slv_rt->direction = stream_config->direction;
+	str_p = &slv_rt->stream_params;
+	str_p->rate = stream_config->frame_rate;
+	str_p->channel_count = stream_config->channel_count;
+	str_p->bps = stream_config->bps;
+
+	/* Add reference for Slave device handle */
+	slv_rt->slv = slave;
+
+	/* Add reference for stream runtime handle */
+	slv_rt->sdw_rt = sdw_rt;
+
+out:
+	return slv_rt;
+}
+
+/**
+ * sdw_release_mstr_stream: Removes entry from master runtime list and free
+ *	up resources.
+ *
+ * @mstr: Master handle.
+ * @sdw_rt: Master runtime handle.
+ */
+static void sdw_release_mstr_stream(struct sdw_master *mstr,
+			struct sdw_runtime *sdw_rt)
+{
+	struct sdw_mstr_runtime *mstr_rt, *__mstr_rt;
+
+	/* Retrieve Master runtime handle */
+	list_for_each_entry_safe(mstr_rt, __mstr_rt, &sdw_rt->mstr_rt_list,
+			mstr_strm_node) {
+
+		if (mstr_rt->mstr == mstr) {
+
+			if (mstr_rt->direction == SDW_DATA_DIR_OUT)
+				/* Reference count update */
+				sdw_dec_ref_count(&sdw_rt->tx_ref_count);
+			else
+				/* Reference count update */
+				sdw_dec_ref_count(&sdw_rt->rx_ref_count);
+
+			/* Remove node from the list */
+			list_del(&mstr_rt->mstr_strm_node);
+			list_del(&mstr_rt->mstr_node);
+
+			pm_runtime_mark_last_busy(&mstr->dev);
+			pm_runtime_put_sync_autosuspend(&mstr->dev);
+
+			/* Free up Master runtime handle resources */
+			kfree(mstr_rt);
+		}
+	}
+}
+
+/**
+ * sdw_release_slv_stream: Removes entry from slave runtime list and free up
+ *	resources.
+ *
+ * @slave: Slave handle.
+ * @sdw_rt: Stream runtime handle.
+ */
+static void sdw_release_slv_stream(struct sdw_slave *slave,
+			struct sdw_runtime *sdw_rt)
+{
+	struct sdw_slv_runtime *slv_rt, *__slv_rt;
+
+	/* Retrieve Slave runtime handle */
+	list_for_each_entry_safe(slv_rt, __slv_rt, &sdw_rt->slv_rt_list,
+			slave_strm_node) {
+
+		if (slv_rt->slv == slave) {
+
+			if (slv_rt->direction == SDW_DATA_DIR_OUT)
+				/* Reference count update */
+				sdw_dec_ref_count(&sdw_rt->tx_ref_count);
+			else
+				/* Reference count update */
+				sdw_dec_ref_count(&sdw_rt->rx_ref_count);
+
+			/* Remove node from the list */
+			list_del(&slv_rt->slave_strm_node);
+
+			pm_runtime_mark_last_busy(&slave->dev);
+			pm_runtime_put_sync_autosuspend(&slave->dev);
+
+			/* Free up Slave runtime handle resources */
+			kfree(slv_rt);
+		}
+	}
+}
+
+/**
+ * snd_sdw_release_stream: De-associates Master(s) and Slave(s) from stream.
+ *	Reverse effect of the sdw_config_stream. Master calls this with
+ *	Slave handle as NULL, Slave calls this with Master handle as NULL.
+ *
+ * @mstr: Master handle,
+ * @slave: SoundWire Slave handle, Null if stream configuration is called by
+ *	Master driver.
+ *
+ * @stream_tag: Stream_tag representing the audio stream. All Masters and
+ *	Slaves part of the same stream has same stream tag. So Bus driver
+ *	holds information of all Masters and Slaves associated with stream
+ *	tag.
+ */
+int snd_sdw_release_stream(struct sdw_master *mstr,
+		struct sdw_slave *slave,
+		unsigned int stream_tag)
+{
+	int i;
+	struct sdw_runtime *sdw_rt = NULL;
+	struct sdw_stream_tag *stream_tags = snd_sdw_core.stream_tags;
+
+	/* Retrieve master handle if called by Slave */
+	if (!mstr)
+		mstr = slave->mstr;
+
+	/* Retrieve stream runtime handle */
+	for (i = 0; i < SDW_NUM_STREAM_TAGS; i++) {
+		if (stream_tags[i].stream_tag == stream_tag) {
+			sdw_rt = stream_tags[i].sdw_rt;
+			break;
+		}
+	}
+
+	if (!sdw_rt) {
+		dev_err(&mstr->dev, "Invalid stream tag\n");
+		return -EINVAL;
+	}
+
+	/* Call release API of Master/Slave */
+	if (!slave)
+		sdw_release_mstr_stream(mstr, sdw_rt);
+	else
+		sdw_release_slv_stream(slave, sdw_rt);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_sdw_release_stream);
+
+/**
+ * snd_sdw_config_stream: Configures the SoundWire stream. All the Master(s)
+ *	and Slave(s) associated with the stream calls this API with
+ *	"sdw_stream_config". This API configures SoundWire stream based on
+ *	"sdw_stream_config" provided by each Master(s) and Slave(s)
+ *	associated with the stream. Master calls this function with Slave
+ *	handle as NULL, Slave calls this with Master handle as NULL.
+ *
+ * @mstr: Master handle.
+ * @slave: SoundWire Slave handle, Null if stream configuration is called by
+ *	Master driver.
+ *
+ * @stream_config: Stream configuration for the SoundWire audio stream.
+ * @stream_tag: Stream_tag representing the audio stream. All Masters and
+ *	Slaves part of the same stream has same stream tag. So Bus driver
+ *	holds information of all Masters and Slaves associated with stream
+ *	tag.
+ */
+int snd_sdw_config_stream(struct sdw_master *mstr,
+		struct sdw_slave *slave,
+		struct sdw_stream_config *stream_config,
+		unsigned int stream_tag)
+{
+	int i;
+	int ret = 0;
+	struct sdw_runtime *sdw_rt = NULL;
+	struct sdw_mstr_runtime *mstr_rt = NULL;
+	struct sdw_slv_runtime *slv_rt = NULL;
+	struct sdw_stream_tag *stream_tags = snd_sdw_core.stream_tags;
+	struct sdw_stream_tag *stream = NULL;
+
+	/* Retrieve master handle if called by Slave */
+	if (!mstr)
+		mstr = slave->mstr;
+
+	/* Retrieve stream runtime handle */
+	for (i = 0; i < SDW_NUM_STREAM_TAGS; i++) {
+		if (stream_tags[i].stream_tag == stream_tag) {
+			sdw_rt = stream_tags[i].sdw_rt;
+			stream = &stream_tags[i];
+			break;
+		}
+	}
+
+	if (!sdw_rt) {
+		dev_err(&mstr->dev, "Valid stream tag not found\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* Acquire stream lock */
+	mutex_lock(&stream->stream_lock);
+
+	/* Get and Initialize Master runtime handle */
+	mstr_rt = sdw_config_mstr_stream(mstr, stream_config, sdw_rt);
+	if (!mstr_rt) {
+		dev_err(&mstr->dev, "Master runtime configuration failed\n");
+		ret = -EINVAL;
+		goto error;
+	}
+
+	/* Initialize Slave runtime handle */
+	if (slave) {
+		slv_rt = sdw_config_slv_stream(slave, stream_config, sdw_rt);
+		if (!slv_rt) {
+			dev_err(&mstr->dev, "Slave runtime configuration failed\n");
+			ret = -EINVAL;
+			goto error;
+		}
+	}
+
+	/*
+	 * Stream params will be stored based on Tx only, since there can be
+	 * only one Tx and multiple Rx, There can be multiple Tx if there is
+	 * aggregation on Tx. That is handled by adding the channels to
+	 * stream_params for each aggregated Tx slaves
+	 */
+	if (!sdw_rt->tx_ref_count && stream_config->direction ==
+					SDW_DATA_DIR_OUT) {
+		sdw_rt->stream_params.rate = stream_config->frame_rate;
+		sdw_rt->stream_params.channel_count =
+						stream_config->channel_count;
+		sdw_rt->stream_params.bps = stream_config->bps;
+		/* Reference count update */
+		sdw_inc_ref_count(&sdw_rt->tx_ref_count);
+	}
+
+	/*
+	 * Normally there will be only one Tx in system, multiple Tx can
+	 * only be there if we support aggregation. In that case there may
+	 * be multiple slave or masters handing different channels of same
+	 * Tx stream.
+	 */
+	else if (sdw_rt->tx_ref_count && stream_config->direction ==
+						SDW_DATA_DIR_OUT) {
+		if (sdw_rt->stream_params.rate !=
+			stream_config->frame_rate) {
+			dev_err(&mstr->dev, "Frame rate for aggregated devices not matching\n");
+			ret = -EINVAL;
+			goto error;
+		}
+
+		if (sdw_rt->stream_params.bps != stream_config->bps) {
+			dev_err(&mstr->dev, "bps for aggregated devices not matching\n");
+			ret = -EINVAL;
+			goto error;
+		}
+
+		/*
+		 * Number of channels gets added, since both devices will be
+		 * supporting different channels. Like one Codec supporting
+		 * L and other supporting R channel.
+		 */
+		sdw_rt->stream_params.channel_count +=
+			stream_config->channel_count;
+
+		/* Reference count update */
+		sdw_inc_ref_count(&sdw_rt->tx_ref_count);
+	} else
+		/* Reference count update */
+		sdw_inc_ref_count(&sdw_rt->rx_ref_count);
+
+	sdw_rt->type = stream_config->type;
+
+	/* Change stream state to CONFIG */
+	sdw_rt->stream_state = SDW_STATE_STRM_CONFIG;
+
+	/*
+	 * Slaves are added to two list, This is because bandwidth is
+	 * calculated for two masters individually, while Ports are enabled
+	 * of all the aggregated masters and slaves part of the same stream
+	 * tag simultaneously.
+	 */
+	if (slave) {
+		list_add_tail(&slv_rt->slave_strm_node, &sdw_rt->slv_rt_list);
+		list_add_tail(&slv_rt->slave_mstr_node, &mstr_rt->slv_rt_list);
+	}
+
+	/* Release stream lock */
+	mutex_unlock(&stream->stream_lock);
+
+	if (slave)
+		pm_runtime_get_sync(&slave->dev);
+	else
+		pm_runtime_get_sync(&mstr->dev);
+
+	return ret;
+
+error:
+	mutex_unlock(&stream->stream_lock);
+	kfree(mstr_rt);
+	kfree(slv_rt);
+out:
+	return ret;
+
+}
+EXPORT_SYMBOL_GPL(snd_sdw_config_stream);
+
+/**
+ * sdw_check_dpn_caps: Check Master and Slave port capabilities. This performs
+ *			PCM parameter check based on PCM
+ *			parameters received in stream.
+ * @dpn_cap: Capabilities of Master or Slave port.
+ * @strm_params: Stream PCM parameters.
+ */
+static int sdw_check_dpn_caps(struct sdw_dpn_caps *dpn_cap,
+		struct sdw_stream_params *strm_prms)
+{
+	struct sdw_port_aud_mode_prop *mode_prop =
+		dpn_cap->mode_properties;
+	int i, value;
+
+	/* Check for sampling frequency */
+	if (mode_prop->num_sample_rate_cfgs) {
+		for (i = 0; i < mode_prop->num_sample_rate_cfgs; i++) {
+			value = mode_prop->sample_rate_buf[i];
+			if (strm_prms->rate == value)
+				break;
+		}
+
+		if (i == mode_prop->num_sample_rate_cfgs)
+			return -EINVAL;
+	} else {
+
+		if ((strm_prms->rate < mode_prop->min_sample_rate)
+				|| (strm_prms->rate >
+				mode_prop->max_sample_rate)) {
+			return -EINVAL;
+		}
+	}
+
+	/* Check for bit rate */
+	if (dpn_cap->num_bps) {
+		for (i = 0; i < dpn_cap->num_bps; i++) {
+			value = dpn_cap->bps_buf[i];
+			if (strm_prms->bps == value)
+				break;
+		}
+
+		if (i == dpn_cap->num_bps)
+			return -EINVAL;
+
+	} else {
+
+		if ((strm_prms->bps < dpn_cap->min_bps)
+				|| (strm_prms->bps > dpn_cap->max_bps))
+			return -EINVAL;
+	}
+
+	/* Check for number of channels */
+	if (dpn_cap->num_ch_cnt) {
+		for (i = 0; i < dpn_cap->num_ch_cnt; i++) {
+			value = dpn_cap->ch_cnt_buf[i];
+			if (strm_prms->bps == value)
+				break;
+		}
+
+		if (i == dpn_cap->num_ch_cnt)
+			return -EINVAL;
+
+	} else {
+
+		if ((strm_prms->channel_count < dpn_cap->min_ch_cnt) ||
+			(strm_prms->channel_count > dpn_cap->max_ch_cnt))
+			return -EINVAL;
+
+	}
+
+	return 0;
+}
+
+/**
+ * sdw_mstr_port_configuration: Master Port configuration. This performs
+ *	all the port related configuration including allocation port
+ *	structure memory, assign PCM parameters and add port node in master
+ *	runtime list.
+ *
+ * @mstr: Master handle.
+ * @sdw_rt: Stream runtime information.
+ * @ports_config: Port configuration for Slave.
+ */
+static int sdw_mstr_port_configuration(struct sdw_master *mstr,
+			struct sdw_runtime *sdw_rt,
+			struct sdw_ports_config *ports_config)
+{
+	struct sdw_mstr_runtime *mstr_rt = NULL;
+	struct sdw_port_runtime *port_rt;
+	int found = 0;
+	int i;
+	int ret = 0, pn = 0;
+	struct sdw_dpn_caps *dpn_cap = mstr->caps.sdw_dpn_caps;
+
+	/* Get Master device handle */
+	list_for_each_entry(mstr_rt, &sdw_rt->mstr_rt_list, mstr_strm_node) {
+		if (mstr_rt->mstr == mstr) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		dev_err(&mstr->dev, "Master not found for this port\n");
+		return -EINVAL;
+	}
+
+	/* Allocate resources for port runtime handle */
+	port_rt = kzalloc((sizeof(*port_rt) * ports_config->num_ports),
+				GFP_KERNEL);
+	if (!port_rt)
+		return -ENOMEM;
+
+	/* Check master capabilities */
+	if (!dpn_cap)
+		return -EINVAL;
+
+	/* Iterate for number of ports to perform initialization */
+	for (i = 0; i < ports_config->num_ports; i++) {
+		port_rt[i].channel_mask = ports_config->port_config[i].ch_mask;
+		port_rt[i].port_num = pn = ports_config->port_config[i].num;
+
+		/* Perform capability check for master port */
+		ret = sdw_check_dpn_caps(&dpn_cap[pn], &mstr_rt->stream_params);
+		if (ret < 0) {
+			dev_err(&mstr->dev, "Master capabilities check failed ret = %d\n", ret);
+			goto error;
+		}
+
+		/* Add node to port runtime list */
+		list_add_tail(&port_rt[i].port_node, &mstr_rt->port_rt_list);
+	}
+
+	return ret;
+
+error:
+	kfree(port_rt);
+	return ret;
+}
+
+struct sdw_dpn_caps *sdw_get_slv_dpn_cap(struct sdw_slave_caps *slv_cap,
+				enum sdw_data_direction direction,
+				unsigned int port_num)
+{
+	int i;
+	struct sdw_dpn_caps *dpn_cap;
+	u8 num_ports;
+	bool port_found = 0;
+
+	if (direction == SDW_DATA_DIR_OUT)
+		num_ports = slv_cap->num_src_ports;
+	else
+		num_ports = slv_cap->num_sink_ports;
+
+	for (i = 0; i < num_ports; i++) {
+		dpn_cap = &slv_cap->dpn_caps[direction][i];
+
+		if (dpn_cap->port_number == port_num) {
+			port_found = 1;
+			break;
+		}
+	}
+
+	if (!port_found)
+		return NULL;
+
+	return dpn_cap;
+
+}
+
+/**
+ * sdw_config_slv_port: Slave Port configuration. This performs
+ *	all the port related configuration including allocation port
+ *	structure memory, assign PCM parameters and add port node in slave
+ *	runtime list.
+ * @slave: Slave handle.
+ * @sdw_rt: Stream runtime information.
+ * @ports_config: Port configuration for Slave.
+ */
+static int sdw_config_slv_port(struct sdw_slave *slave,
+			struct sdw_runtime *sdw_rt,
+			struct sdw_ports_config *ports_config)
+{
+	struct sdw_slv_runtime *slv_rt;
+	struct sdw_port_runtime *port_rt;
+	struct sdw_dpn_caps *dpn_cap;
+	int found = 0, ret = 0;
+	int i, pn;
+
+	/* Get Slave device handle */
+	list_for_each_entry(slv_rt, &sdw_rt->slv_rt_list, slave_strm_node) {
+		if (slv_rt->slv == slave) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		dev_err(&slave->mstr->dev, "Slave not found for this port\n");
+		return -EINVAL;
+	}
+
+	/* Check whether slave capabilities are valid or invalid */
+	if (!slave->priv.slave_cap_updated) {
+		dev_err(&slave->mstr->dev, "Slave capabilities not updated\n");
+		return -EINVAL;
+	}
+
+	/* Allocate resources for port runtime handle */
+	port_rt = kzalloc((sizeof(*port_rt) * ports_config->num_ports),
+					GFP_KERNEL);
+	if (!port_rt)
+		return -ENOMEM;
+
+	/* Assign PCM parameters */
+	for (i = 0; i < ports_config->num_ports; i++) {
+		port_rt[i].channel_mask = ports_config->port_config[i].ch_mask;
+		port_rt[i].port_num = pn =
+				ports_config->port_config[i].num;
+
+		dpn_cap = sdw_get_slv_dpn_cap(&slave->priv.caps,
+				slv_rt->direction,
+				ports_config->port_config[i].num);
+		if (!dpn_cap) {
+			ret = -EINVAL;
+			dev_err(&slave->mstr->dev, "Slave port capabilities not found ret = %d\n", ret);
+			goto error;
+		}
+
+		/* Perform capability check for slave port */
+		ret = sdw_check_dpn_caps(dpn_cap, &slv_rt->stream_params);
+		if (ret < 0) {
+			dev_err(&slave->mstr->dev, "Slave capabilities check failed ret = %d\n", ret);
+			goto error;
+		}
+
+		/* Add node to port runtime list */
+		list_add_tail(&port_rt[i].port_node, &slv_rt->port_rt_list);
+	}
+
+	return ret;
+
+error:
+	kfree(port_rt);
+	return ret;
+}
+
+/**
+ * snd_sdw_config_ports: Configures Master or Slave Port(s) associated with
+ *	the stream. All the Master(s) and Slave(s) associated with the
+ *	stream calls this API with "sdw_ports_config". Master calls this
+ *	function with Slave handle as NULL, Slave calls this with Master
+ *	handle as NULL.
+ *
+ * @mstr: Master handle where the Slave is connected.
+ * @slave: Slave handle.
+ * @ports_config: Port configuration for each Port of SoundWire Slave.
+ * @stream_tag: Stream tag, where this Port is connected.
+ */
+int snd_sdw_config_ports(struct sdw_master *mstr, struct sdw_slave *slave,
+				struct sdw_ports_config *ports_config,
+				unsigned int stream_tag)
+{
+	int ret;
+	int i;
+	struct sdw_stream_tag *stream_tags = snd_sdw_core.stream_tags;
+	struct sdw_runtime *sdw_rt = NULL;
+	struct sdw_stream_tag *stream = NULL;
+
+	/* Retrieve master handle if called by Slave */
+	if (!mstr)
+		mstr = slave->mstr;
+
+	/* Retrieve stream runtime handle */
+	for (i = 0; i < SDW_NUM_STREAM_TAGS; i++) {
+		if (stream_tags[i].stream_tag == stream_tag) {
+			sdw_rt = stream_tags[i].sdw_rt;
+			stream = &stream_tags[i];
+			break;
+		}
+	}
+
+	if (!sdw_rt) {
+		dev_err(&mstr->dev, "Invalid stream tag\n");
+		return -EINVAL;
+	}
+
+	/* Acquire stream lock */
+	mutex_lock(&stream->stream_lock);
+
+	/* Perform Master/Slave port configuration */
+	if (!slave)
+		ret = sdw_mstr_port_configuration(mstr, sdw_rt, ports_config);
+	else
+		ret = sdw_config_slv_port(slave, sdw_rt, ports_config);
+
+	/* Release stream lock */
+	mutex_unlock(&stream->stream_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(snd_sdw_config_ports);
+
+/**
  * snd_sdw_master_stop_clock: Stop the clock. This function broadcasts the
  *	SCP_CTRL register with clock_stop_now bit set.
  *
diff --git a/sound/sdw/sdw_priv.h b/sound/sdw/sdw_priv.h
index bbba27a..fc738b8 100644
--- a/sound/sdw/sdw_priv.h
+++ b/sound/sdw/sdw_priv.h
@@ -68,6 +68,31 @@
 #define SDW_NUM_OF_MSG3_XFRD	3
 #define SDW_NUM_OF_MSG4_XFRD	4
 
+/**
+ * Below values are not defined in MIPI standard. Completely arbitrary
+ * values that can be changed at will.
+ */
+#define SDW_MAX_STREAM_TAG_KEY_SIZE	80
+#define SDW_NUM_STREAM_TAGS		100 /* Max number of stream tags */
+#define SDW_DOUBLE_RATE_FACTOR		2 /* Double rate */
+
+/* TODO: Description to be provided for SDW_FREQ_MOD_FACTOR */
+#define SDW_FREQ_MOD_FACTOR		3000
+
+/**
+ * SDW_STRM_RATE_GROUPING is place holder number used to hold the frame rate
+ * used in grouping stream for efficiently calculating bandwidth. All the
+ * streams with same frame rates belong to same group. This number is
+ * dynamically increased if the group count number increases above 12.
+ */
+#define SDW_STRM_RATE_GROUPING		12
+
+/* Size of buffer in bytes. */
+#define SDW_BUF_SIZE1			1
+#define SDW_BUF_SIZE2			2
+#define SDW_BUF_SIZE3			3
+#define SDW_BUF_SIZE4			4
+
 /* Maximum number of Data Ports. */
 #define SDW_MAX_DATA_PORTS		15
 
@@ -80,6 +105,8 @@
  */
 #define SDW_INTR_STAT_READ_MAX_TRIES	10
 
+extern struct snd_sdw_core snd_sdw_core;
+
 /**
  * sdw_driver: Structure to typecast both Master and Slave driver to generic
  *	SoundWire driver, to find out the driver type.
@@ -95,6 +122,278 @@ struct sdw_driver {
 		container_of(d, struct sdw_driver, driver)
 
 /**
+ * sdw_stream_state: Stream state maintained by bus driver for performing
+ *	stream operations.
+ *
+ * @SDW_STATE_STRM_ALLOC: New stream is allocated.
+ * @SDW_STATE_STRM_CONFIG: Stream is configured. PCM/PDM parameters of the
+ *	Stream is updated to bus driver.
+ *
+ * @SDW_STATE_STRM_PREPARE: Stream is Prepared. All the ports of Master and
+ *	Slave associated with this stream is prepared for enabling.
+ *
+ * @SDW_STATE_STRM_ENABLE: Stream is enabled. All the ports of Master and
+ *	Slave associated with this stream are enable and now stream is
+ *	active.
+ *
+ * @SDW_STATE_STRM_DISABLE: Stream in disabled state, All the ports of
+ *	Master and Slave associated with the stream are disabled, and stream
+ *	is not active on bus.
+ *
+ * @SDW_STATE_STRM_DEPREPARE: Stream in de-prepare state. All the ports of
+ *	Master and Slave associated with the stream are de-prepared.
+ *
+ * @SDW_STATE_STRM_RELEASE: Stream in release state. Stream is not having
+ *	any PCM/PDM configuration. There is not Free state for stream, since
+ *	memory for the stream gets freed, and there is no way to update
+ *	stream as free.
+ */
+enum sdw_stream_state {
+	SDW_STATE_STRM_ALLOC = 0,
+	SDW_STATE_STRM_CONFIG = 1,
+	SDW_STATE_STRM_PREPARE = 2,
+	SDW_STATE_STRM_ENABLE = 3,
+	SDW_STATE_STRM_DISABLE = 4,
+	SDW_STATE_STRM_DEPREPARE = 5,
+	SDW_STATE_STRM_RELEASE = 6,
+};
+
+/**
+ * sdw_update_bus_ops: Operations performed by bus driver for stream state
+ *	transitions. Some of the operations are performed on individual
+ *	streams, while some are global operations affecting all the streams
+ *	on the bus.
+ *
+ * @SDW_BUS_PORT_PRE: Perform all the operations which is to be done before
+ *	initiating the bank switch for stream getting enabled. Master and
+ *	Slave driver may need to perform some operations before bank switch.
+ *	Call Master and Slave handlers to accomplish device specific
+ *	operations before initiating bank switch.
+ *
+ * @SDW_BUS_BANK_SWITCH: Initiate the bank switch operation by broadcasting
+ *	SCP_FrameCtrl register. Depending upon the Master implementation
+ *	broadcast will be finished as a part of this state, or Master may
+ *	set some register as a part of PORT_POST below operation after which
+ *	broadcast will be finished. Initiation of the broadcast message is
+ *	done as part of this operation. Broadcast message gets transmitted
+ *	on the bus during this or next operation is Master dependent.
+ *
+ * @SDW_BUS_PORT_POST: Perform all the operations which are do be done after
+ *	initiating the Bank switch. Call Master and Slave handlers to
+ *	perform Post bank switch operation.
+ *
+ * @SDW_BUS_BANK_SWITCH_WAIT: Bus driver waits here for the Bank switch to
+ *	be completed. This is used for Master(s) running in aggregation mode
+ *	where pre and post operations are performed before and after Bank
+ *	switch operation. The Bank switch message broadcast will happen only
+ *	when clock is enabled which is done as part of post Bank switch
+ *	operation. After post Bank switch operation, bus driver waits for
+ *	response of Bank switch. The bus driver provides SDW_BUS_PORT_PRE
+ *	and SDW_BUS_PORT_POST for Bank switch operation which are as per
+ *	Master implementation.
+ *
+ * @SDW_BUS_PORT_DIS_CHN: Disable all the ports of the alternate bank
+ *	(unused bank) after the bank switch. Once Bank switch operation is
+ *	successful, the running stream(s) enabled port channels on previous
+ *	bank needs to be disabled for both Master(s) and Slave(s).
+ */
+enum sdw_update_bus_ops {
+	SDW_BUS_PORT_PRE,
+	SDW_BUS_BANK_SWITCH,
+	SDW_BUS_PORT_POST,
+	SDW_BUS_BANK_SWITCH_WAIT,
+	SDW_BUS_PORT_DIS_CHN,
+};
+
+/**
+ * sdw_stream_tag: Stream tag represents the unique SoundWire Audio stream.
+ *	All the ports of the Master(s) and Slave(s) part of the same stream
+ *	tags gets enabled/disabled as a part of single bank Switch.If
+ *	samples of the stream are split between the Master(s), its Master
+ *	responsibility of synchronizing the bank switch of two individual
+ *	Masters.
+ *
+ * @stream_tag: Unique stream tag number.
+ * @stream_lock: Lock for stream.
+ * @ref_count: Number of times stream tag is allocated. Stream tag is is
+ *	available for allocation if reference count is 0.
+ *
+ * @sdw_rt: Holds the stream runtime information.
+ */
+struct sdw_stream_tag {
+	int stream_tag;
+	struct mutex stream_lock;
+	int ref_count;
+	struct sdw_runtime *sdw_rt;
+};
+
+/**
+ * sdw_stream_params: Stream parameters.
+ *
+ * @rate: Sampling frequency
+ * @channel_count: Number of channels.
+ * @bps: bits per sample.
+ */
+struct sdw_stream_params {
+	unsigned int rate;
+	unsigned int channel_count;
+	unsigned int bps;
+};
+
+/**
+ * sdw_port_runtime: Holds the port parameters for each of the Master(s)
+ *	Slave(s) port associated with the stream.
+ *
+ * @port_num: Port number.
+ * @channel_mask: Channels of the Stream handled by this port.
+ * @transport_params: Transport parameters of port.
+ * @port_params: Port parameters
+ * @port_node: Port runtime is added to the Port List of Master(s) or
+ *	Slave(s) associated with stream. Node to add the Port runtime to
+ *	Master(s) or Slave(s) list.
+ */
+struct sdw_port_runtime {
+	int port_num;
+	int channel_mask;
+	struct sdw_transport_params transport_params;
+	struct sdw_port_params port_params;
+	struct list_head port_node;
+};
+
+/**
+ * sdw_slave_runtime: Holds the Stream parameters for the Slave associated
+ *	with the stream.
+ *
+ * @slv: Slave handle associated with this Stream.
+ * @sdw_rt: Stream handle to which this Slave stream is associated.
+ * @direction: Port Direction of the Slave for this Stream. Slave is
+ *	transmitting the Data or receiving the Data.
+ *
+ * @stream_params: Stream parameters for Slave.
+ * @port_rt_list: List of Slave Ports associated with this Stream.
+ * @slave_strm_node: Stream runtime data structure maintains list of all the
+ *	Slave runtime instances associated with stream. This is the node to
+ *	add Slave runtime instance to that list. This list is used for the
+ *	stream configuration.
+ *
+ * @slave_mstr_node: Master runtime data structure maintains list of all the
+ *	Slave runtime instances. This is the node to add Slave runtime
+ *	instance to that list. This list is used for Bandwidth calculation
+ *	per bus. Slave runtime instance gets added to two list one for
+ *	stream configuration and other for bandwidth calculation. Stream
+ *	configuration is per stream where there may be multiple Masters and
+ *	Slave associated with Stream. Bandwidth calculation is per Bus,
+ *	where there is Single Master and Multiple Slaves associated with
+ *	bus.
+ */
+struct sdw_slv_runtime {
+	struct sdw_slave *slv;
+	struct sdw_runtime *sdw_rt;
+	int direction;
+	struct sdw_stream_params stream_params;
+	struct list_head port_rt_list;
+	struct list_head slave_strm_node;
+	struct list_head slave_mstr_node;
+};
+
+/**
+ * sdw_bus_runtime: This structure holds the transport params and BW
+ *	required by the stream on the bus. There may be multiple bus
+ *	associated with the stream. This holds bus specific parameters of
+ *	stream. TODO: Currently sdw_bus_runtime is part of sdw_mstr_runtime
+ *	Master handle. Once stream between Slave to Slave is supported by
+ *	bus driver, this needs to be made part of sdw_runtime handle.
+ *
+ * @stream_bw: Bus Bandwidth required by this stream (bps).
+ * @hstart: Horizontal Start column for this stream.
+ * @hstop: Horizontal stop column for this stream.
+ * @block_offset: Block offset for this stream.
+ * @sub_block_offset: Sub Block offset for this stream.
+ */
+struct sdw_bus_runtime {
+	unsigned int stream_bw;
+	int hstart;
+	int hstop;
+	int block_offset;
+	int sub_block_offset;
+
+};
+
+/**
+ * sdw_mstr_runtime: Holds the Stream parameters for the Master associated
+ *		with the stream.
+ *
+ * @mstr: Master handle associated with this stream.
+ * @sdw_rt: Stream handle to which this Master stream is associated.
+ * @stream_params: Stream parameters.
+ * @port_rt_list: List of this Master Ports associated with this Stream.
+ * @mstr_strm_node: Stream runtime data structure maintains list of all the
+ *	Master runtime instances associated with stream. This is the node to
+ *	add Master runtime instance to that list. This list is used for the
+ *	stream configuration.
+ *
+ * @mstr_node: Master data structure maintains list of all the Master
+ *	runtime instances. This is the node to add Master runtime instance
+ *	to to that list. This list is used for Bandwidth calculation per
+ *	bus.  Master runtime instance gets added to two list one for stream
+ *	configuration and other for bandwidth calculation. Stream
+ *	configuration is per stream where there may be multiple Masters and
+ *	Slave associated with Stream. Bandwidth calculation is per Bus,
+ *	where there is Single Master and Multiple Slaves associated with
+ *	bus.
+ *
+ * @slv_rt_list: List of the Slave_runtime instances associated with this
+ *	Master_runtime. Its list of all the Slave(s) stream associated with
+ *	this Master. There may be stereo stream from Master to two Slaves,
+ *	where L and R samples from Master is received by two different
+ *	Slave(s), so this list contains the runtime structure associated
+ *	with both Slaves.
+ *
+ * @bus_rt: Bus parameters for the stream. There may be multiple bus
+ *	associated with stream. This bus_rt is for current Master.
+ */
+struct sdw_mstr_runtime {
+	struct sdw_master *mstr;
+	struct sdw_runtime *sdw_rt;
+	int direction;
+	struct sdw_stream_params stream_params;
+	struct list_head port_rt_list;
+	struct list_head mstr_strm_node;
+	struct list_head mstr_node;
+	struct list_head slv_rt_list;
+	struct sdw_bus_runtime bus_rt;
+};
+
+/**
+ * sdw_runtime: This structure holds runtime information for each unique
+ *	SoundWire stream.
+ *
+ * @tx_ref_count: Number of Transmit devices of stream. This may include
+ *	multiple Master(s) and Slave(s) based on how stream samples are
+ *	split between Mater and Slaves.
+ * @rx_ref_count: Number of Receive devices of stream. This may include
+ *	multiple Master(s) and Slave(s) based on how stream samples are
+ *	split between Mater and Slaves.
+ *
+ * @stream_params: Steam parameters.
+ * @slv_rt_list: List of the slaves part of this stream.
+ * @mstr_rt_list: List of Masters part of this stream.
+ * @type: Stream type PCM or PDM.This is not SoundWire concept, its used
+ *	inside bus driver for efficient BW management.
+ *
+ * @stream_state: Current State of the stream.
+ */
+struct sdw_runtime {
+	int tx_ref_count;
+	int rx_ref_count;
+	struct sdw_stream_params stream_params;
+	struct list_head slv_rt_list;
+	struct list_head mstr_rt_list;
+	enum sdw_stream_type type;
+	enum sdw_stream_state stream_state;
+};
+
+/**
  * sdw_slv_status: List of Slave status.
  *
  * @node: Node for adding status to list of Slave status.
@@ -110,6 +409,20 @@ struct sdw_slv_status {
  *
  * @bus_node: Node to add the bus in the sdw_core list.
  * @mstr: Master reference for the bus.
+ * @clk_state: State of the clock.
+ * @active_bank: Current bank in use.
+ * @max_clk_dr_freq: Maximum double rate clock frequency. This is maximum
+ * double clock rate supported per bus.
+ * @curr_clk_dr_freq: Current double rate clock frequency in use. This is
+ *	current clock rate at which bus is running.
+ *
+ * @clk_div: Current clock divider in use.
+ * @bandwidth: Total bandwidth.
+ * @system_interval: Bus System interval (Stream Synchronization Point).
+ * @stream_interval: Stream interval.
+ * @frame_freq: SoundWire Frame frequency on bus.
+ * @col: Active columns.
+ * @row: Active rows.
  * @status_thread: Thread to process the Slave status.
  * @kworker: Worker for updating the Slave status.
  * @kwork: Work for worker
@@ -121,16 +434,48 @@ struct sdw_slv_status {
  *	context, spinlock is used to put the status reported by Master into
  *	the status list which is processed by bus driver in thread context
  *	later.
+ *
+ * @data: Data to be provided by bus driver for calling xfer_msg_deferred
+ *	callback of Master driver.
+
  */
 
 struct sdw_bus {
 	struct list_head bus_node;
 	struct sdw_master *mstr;
+	unsigned int clk_state;
+	unsigned int active_bank;
+	unsigned int max_dr_clk_freq;
+	unsigned int curr_dr_clk_freq;
+	unsigned int clk_div;
+	unsigned int bandwidth;
+	unsigned int system_interval;
+	unsigned int stream_interval;
+	unsigned int frame_freq;
+	unsigned int col;
+	unsigned int row;
 	struct task_struct *status_thread;
 	struct kthread_worker kworker;
 	struct kthread_work kwork;
 	struct list_head status_list;
 	spinlock_t spinlock;
+	struct sdw_deferred_xfer_data data;
+};
+
+/**
+ * sdw_row_col_pair: Information for each row column pair. This is used by
+ *	bus driver for quick BW calculation.
+ *
+ * @row: Number of rows.
+ * @col: Number of columns
+ * @control_bits: Number of controls bits for this row-column pair.
+ * @data_bits: Number of controls bits for this row-column pair.
+ */
+struct sdw_row_col_pair {
+	int row;
+	int col;
+	int control_bits;
+	int data_bits;
 };
 
 /**
@@ -138,11 +483,17 @@ struct sdw_bus {
  *	spawned across masters and has list of bus structure per every
  *	Master registered.
  *
+ * @row_col_pair: Array holding all row-column pair possible as per MIPI
+ *	1.1 Spec. This is used for quick reference for BW calculation
+ *	algorithm.
+ *
  * @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 sdw_stream_tag stream_tags[SDW_NUM_STREAM_TAGS];
+	struct sdw_row_col_pair row_col_pair[MAX_NUM_ROW_COLS];
 	struct list_head bus_list;
 	struct mutex core_mutex;
 	struct idr idr;
@@ -168,6 +519,58 @@ void sdw_bank_switch_deferred(struct sdw_master *mstr, struct sdw_msg *msg,
 				struct sdw_deferred_xfer_data *data);
 
 /**
+ * sdw_index_to_col: Structure holding mapping of numbers to columns.
+ *
+ * @index: Holds index to number of columns.
+ * @col: Holds actual columns.
+ */
+struct sdw_index_to_col {
+	int index;
+	int col;
+};
+
+/**
+ * sdw_index_to_row: Structure holding mapping of numbers to rows.
+ *
+ * @index: Holds index to number of rows.
+ * @row: Holds actual rows.
+ */
+struct sdw_index_to_row {
+	int index;
+	int row;
+};
+
+/**
+ * sdw_group_params: Structure holding temporary variable while computing
+ *	transport parameters of Master(s) and Slave(s).
+ *
+ * @rate: Holds stream rate.
+ * @full_bw: Holds full bandwidth per group.
+ * @payload_bw: Holds payload bandwidth per group.
+ * @hwidth: Holds hwidth per group.
+ */
+struct sdw_group_params {
+	int rate;
+	int full_bw;
+	int payload_bw;
+	int hwidth;
+};
+
+/**
+ * sdw_group_count: Structure holding group count and stream rate array
+ *	while computing transport parameters of Master(s) and Slave(s).
+ *
+ * @group_count: Holds actual group count.
+ * @max_size: Holds maximum capacity of array.
+ * @stream_rates: Pointer to stream rates.
+ */
+struct sdw_group_count {
+	unsigned int group_count;
+	unsigned int max_size;
+	unsigned int *stream_rates;
+};
+
+/**
  * sdw_enable_disable_dpn_intr: Enable or Disable Slave Data Port interrupt.
  *	This is called by bus driver before prepare and after deprepare of
  *	the ports.
@@ -182,6 +585,52 @@ void sdw_bank_switch_deferred(struct sdw_master *mstr, struct sdw_msg *msg,
 int sdw_enable_disable_dpn_intr(struct sdw_slave *sdw_slv, int port_num,
 					int port_direction, bool enable);
 
+/**
+ * sdw_create_row_col_pair: Initialization of bandwidth related operations.
+ *	This is required to have fast path for the BW calculation when a new
+ *	stream is prepared or deprepared. This is called only once as part
+ *	of SoundWire Bus driver getting initialized.
+ */
+void sdw_create_row_col_pair(void);
+
+/**
+ * sdw_init_bus_params: Sets up bus data structure for BW calculation. This
+ *	is called once per each Master interface registration to the
+ *	SoundWire bus.
+ *
+ * @sdw_bus: Bus handle.
+ */
+void sdw_init_bus_params(struct sdw_bus *sdw_bus);
+
+/**
+ * sdw_get_slv_dpn_caps: Get the data port capabilities based on the port
+ *	number and port direction.
+ *
+ * @slv_cap: Slave capabilities.
+ * @direction: Port data direction.
+ * @port_num: Port number.
+ */
+struct sdw_dpn_caps *sdw_get_slv_dpn_cap(struct sdw_slave_caps *slv_cap,
+			enum sdw_data_direction direction,
+			unsigned int port_num);
+
+/* Return bus structure */
+static inline struct sdw_bus *sdw_master_to_bus(struct sdw_master *mstr)
+{
+	return mstr->bus;
+}
+
+/* Reference count increment */
+static inline void sdw_inc_ref_count(int *ref_count)
+{
+	(*ref_count)++;
+}
+
+/* Reference count decrement */
+static inline void sdw_dec_ref_count(int *ref_count)
+{
+	(*ref_count)--;
+}
 
 /*
  * Helper function for bus driver to write messages. Since bus driver
-- 
1.7.9.5

Powered by blists - more mailing lists