xref: /openbmc/linux/drivers/soundwire/stream.c (revision 0c4a1049)
189e59053SSanyog Kale // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
289e59053SSanyog Kale // Copyright(c) 2015-18 Intel Corporation.
389e59053SSanyog Kale 
489e59053SSanyog Kale /*
589e59053SSanyog Kale  *  stream.c - SoundWire Bus stream operations.
689e59053SSanyog Kale  */
789e59053SSanyog Kale 
889e59053SSanyog Kale #include <linux/delay.h>
989e59053SSanyog Kale #include <linux/device.h>
1089e59053SSanyog Kale #include <linux/init.h>
1189e59053SSanyog Kale #include <linux/module.h>
1289e59053SSanyog Kale #include <linux/mod_devicetable.h>
1389e59053SSanyog Kale #include <linux/slab.h>
14f8101c74SSanyog Kale #include <linux/soundwire/sdw_registers.h>
1589e59053SSanyog Kale #include <linux/soundwire/sdw.h>
1689e59053SSanyog Kale #include "bus.h"
1789e59053SSanyog Kale 
1899b8a5d6SSanyog Kale /*
1999b8a5d6SSanyog Kale  * Array of supported rows and columns as per MIPI SoundWire Specification 1.1
2099b8a5d6SSanyog Kale  *
2199b8a5d6SSanyog Kale  * The rows are arranged as per the array index value programmed
2299b8a5d6SSanyog Kale  * in register. The index 15 has dummy value 0 in order to fill hole.
2399b8a5d6SSanyog Kale  */
2499b8a5d6SSanyog Kale int rows[SDW_FRAME_ROWS] = {48, 50, 60, 64, 75, 80, 125, 147,
2599b8a5d6SSanyog Kale 			96, 100, 120, 128, 150, 160, 250, 0,
2699b8a5d6SSanyog Kale 			192, 200, 240, 256, 72, 144, 90, 180};
2799b8a5d6SSanyog Kale 
2899b8a5d6SSanyog Kale int cols[SDW_FRAME_COLS] = {2, 4, 6, 8, 10, 12, 14, 16};
2999b8a5d6SSanyog Kale 
3099b8a5d6SSanyog Kale static int sdw_find_col_index(int col)
3199b8a5d6SSanyog Kale {
3299b8a5d6SSanyog Kale 	int i;
3399b8a5d6SSanyog Kale 
3499b8a5d6SSanyog Kale 	for (i = 0; i < SDW_FRAME_COLS; i++) {
3599b8a5d6SSanyog Kale 		if (cols[i] == col)
3699b8a5d6SSanyog Kale 			return i;
3799b8a5d6SSanyog Kale 	}
3899b8a5d6SSanyog Kale 
3999b8a5d6SSanyog Kale 	pr_warn("Requested column not found, selecting lowest column no: 2\n");
4099b8a5d6SSanyog Kale 	return 0;
4199b8a5d6SSanyog Kale }
4299b8a5d6SSanyog Kale 
4399b8a5d6SSanyog Kale static int sdw_find_row_index(int row)
4499b8a5d6SSanyog Kale {
4599b8a5d6SSanyog Kale 	int i;
4699b8a5d6SSanyog Kale 
4799b8a5d6SSanyog Kale 	for (i = 0; i < SDW_FRAME_ROWS; i++) {
4899b8a5d6SSanyog Kale 		if (rows[i] == row)
4999b8a5d6SSanyog Kale 			return i;
5099b8a5d6SSanyog Kale 	}
5199b8a5d6SSanyog Kale 
5299b8a5d6SSanyog Kale 	pr_warn("Requested row not found, selecting lowest row no: 48\n");
5399b8a5d6SSanyog Kale 	return 0;
5499b8a5d6SSanyog Kale }
55f8101c74SSanyog Kale static int _sdw_program_slave_port_params(struct sdw_bus *bus,
56f8101c74SSanyog Kale 				struct sdw_slave *slave,
57f8101c74SSanyog Kale 				struct sdw_transport_params *t_params,
58f8101c74SSanyog Kale 				enum sdw_dpn_type type)
59f8101c74SSanyog Kale {
60f8101c74SSanyog Kale 	u32 addr1, addr2, addr3, addr4;
61f8101c74SSanyog Kale 	int ret;
62f8101c74SSanyog Kale 	u16 wbuf;
63f8101c74SSanyog Kale 
64f8101c74SSanyog Kale 	if (bus->params.next_bank) {
65f8101c74SSanyog Kale 		addr1 = SDW_DPN_OFFSETCTRL2_B1(t_params->port_num);
66f8101c74SSanyog Kale 		addr2 = SDW_DPN_BLOCKCTRL3_B1(t_params->port_num);
67f8101c74SSanyog Kale 		addr3 = SDW_DPN_SAMPLECTRL2_B1(t_params->port_num);
68f8101c74SSanyog Kale 		addr4 = SDW_DPN_HCTRL_B1(t_params->port_num);
69f8101c74SSanyog Kale 	} else {
70f8101c74SSanyog Kale 		addr1 = SDW_DPN_OFFSETCTRL2_B0(t_params->port_num);
71f8101c74SSanyog Kale 		addr2 = SDW_DPN_BLOCKCTRL3_B0(t_params->port_num);
72f8101c74SSanyog Kale 		addr3 = SDW_DPN_SAMPLECTRL2_B0(t_params->port_num);
73f8101c74SSanyog Kale 		addr4 = SDW_DPN_HCTRL_B0(t_params->port_num);
74f8101c74SSanyog Kale 	}
75f8101c74SSanyog Kale 
76f8101c74SSanyog Kale 	/* Program DPN_OffsetCtrl2 registers */
77f8101c74SSanyog Kale 	ret = sdw_write(slave, addr1, t_params->offset2);
78f8101c74SSanyog Kale 	if (ret < 0) {
79f8101c74SSanyog Kale 		dev_err(bus->dev, "DPN_OffsetCtrl2 register write failed");
80f8101c74SSanyog Kale 		return ret;
81f8101c74SSanyog Kale 	}
82f8101c74SSanyog Kale 
83f8101c74SSanyog Kale 	/* Program DPN_BlockCtrl3 register */
84f8101c74SSanyog Kale 	ret = sdw_write(slave, addr2, t_params->blk_pkg_mode);
85f8101c74SSanyog Kale 	if (ret < 0) {
86f8101c74SSanyog Kale 		dev_err(bus->dev, "DPN_BlockCtrl3 register write failed");
87f8101c74SSanyog Kale 		return ret;
88f8101c74SSanyog Kale 	}
89f8101c74SSanyog Kale 
90f8101c74SSanyog Kale 	/*
91f8101c74SSanyog Kale 	 * Data ports are FULL, SIMPLE and REDUCED. This function handles
92f8101c74SSanyog Kale 	 * FULL and REDUCED only and and beyond this point only FULL is
93f8101c74SSanyog Kale 	 * handled, so bail out if we are not FULL data port type
94f8101c74SSanyog Kale 	 */
95f8101c74SSanyog Kale 	if (type != SDW_DPN_FULL)
96f8101c74SSanyog Kale 		return ret;
97f8101c74SSanyog Kale 
98f8101c74SSanyog Kale 	/* Program DPN_SampleCtrl2 register */
99f8101c74SSanyog Kale 	wbuf = (t_params->sample_interval - 1);
100f8101c74SSanyog Kale 	wbuf &= SDW_DPN_SAMPLECTRL_HIGH;
101f8101c74SSanyog Kale 	wbuf >>= SDW_REG_SHIFT(SDW_DPN_SAMPLECTRL_HIGH);
102f8101c74SSanyog Kale 
103f8101c74SSanyog Kale 	ret = sdw_write(slave, addr3, wbuf);
104f8101c74SSanyog Kale 	if (ret < 0) {
105f8101c74SSanyog Kale 		dev_err(bus->dev, "DPN_SampleCtrl2 register write failed");
106f8101c74SSanyog Kale 		return ret;
107f8101c74SSanyog Kale 	}
108f8101c74SSanyog Kale 
109f8101c74SSanyog Kale 	/* Program DPN_HCtrl register */
110f8101c74SSanyog Kale 	wbuf = t_params->hstart;
111f8101c74SSanyog Kale 	wbuf <<= SDW_REG_SHIFT(SDW_DPN_HCTRL_HSTART);
112f8101c74SSanyog Kale 	wbuf |= t_params->hstop;
113f8101c74SSanyog Kale 
114f8101c74SSanyog Kale 	ret = sdw_write(slave, addr4, wbuf);
115f8101c74SSanyog Kale 	if (ret < 0)
116f8101c74SSanyog Kale 		dev_err(bus->dev, "DPN_HCtrl register write failed");
117f8101c74SSanyog Kale 
118f8101c74SSanyog Kale 	return ret;
119f8101c74SSanyog Kale }
120f8101c74SSanyog Kale 
121f8101c74SSanyog Kale static int sdw_program_slave_port_params(struct sdw_bus *bus,
122f8101c74SSanyog Kale 			struct sdw_slave_runtime *s_rt,
123f8101c74SSanyog Kale 			struct sdw_port_runtime *p_rt)
124f8101c74SSanyog Kale {
125f8101c74SSanyog Kale 	struct sdw_transport_params *t_params = &p_rt->transport_params;
126f8101c74SSanyog Kale 	struct sdw_port_params *p_params = &p_rt->port_params;
127f8101c74SSanyog Kale 	struct sdw_slave_prop *slave_prop = &s_rt->slave->prop;
128f8101c74SSanyog Kale 	u32 addr1, addr2, addr3, addr4, addr5, addr6;
129f8101c74SSanyog Kale 	struct sdw_dpn_prop *dpn_prop;
130f8101c74SSanyog Kale 	int ret;
131f8101c74SSanyog Kale 	u8 wbuf;
132f8101c74SSanyog Kale 
133f8101c74SSanyog Kale 	dpn_prop = sdw_get_slave_dpn_prop(s_rt->slave,
134f8101c74SSanyog Kale 					s_rt->direction,
135f8101c74SSanyog Kale 					t_params->port_num);
136f8101c74SSanyog Kale 	if (!dpn_prop)
137f8101c74SSanyog Kale 		return -EINVAL;
138f8101c74SSanyog Kale 
139f8101c74SSanyog Kale 	addr1 = SDW_DPN_PORTCTRL(t_params->port_num);
140f8101c74SSanyog Kale 	addr2 = SDW_DPN_BLOCKCTRL1(t_params->port_num);
141f8101c74SSanyog Kale 
142f8101c74SSanyog Kale 	if (bus->params.next_bank) {
143f8101c74SSanyog Kale 		addr3 = SDW_DPN_SAMPLECTRL1_B1(t_params->port_num);
144f8101c74SSanyog Kale 		addr4 = SDW_DPN_OFFSETCTRL1_B1(t_params->port_num);
145f8101c74SSanyog Kale 		addr5 = SDW_DPN_BLOCKCTRL2_B1(t_params->port_num);
146f8101c74SSanyog Kale 		addr6 = SDW_DPN_LANECTRL_B1(t_params->port_num);
147f8101c74SSanyog Kale 
148f8101c74SSanyog Kale 	} else {
149f8101c74SSanyog Kale 		addr3 = SDW_DPN_SAMPLECTRL1_B0(t_params->port_num);
150f8101c74SSanyog Kale 		addr4 = SDW_DPN_OFFSETCTRL1_B0(t_params->port_num);
151f8101c74SSanyog Kale 		addr5 = SDW_DPN_BLOCKCTRL2_B0(t_params->port_num);
152f8101c74SSanyog Kale 		addr6 = SDW_DPN_LANECTRL_B0(t_params->port_num);
153f8101c74SSanyog Kale 	}
154f8101c74SSanyog Kale 
155f8101c74SSanyog Kale 	/* Program DPN_PortCtrl register */
156f8101c74SSanyog Kale 	wbuf = p_params->data_mode << SDW_REG_SHIFT(SDW_DPN_PORTCTRL_DATAMODE);
157f8101c74SSanyog Kale 	wbuf |= p_params->flow_mode;
158f8101c74SSanyog Kale 
159f8101c74SSanyog Kale 	ret = sdw_update(s_rt->slave, addr1, 0xF, wbuf);
160f8101c74SSanyog Kale 	if (ret < 0) {
161f8101c74SSanyog Kale 		dev_err(&s_rt->slave->dev,
162f8101c74SSanyog Kale 			"DPN_PortCtrl register write failed for port %d",
163f8101c74SSanyog Kale 			t_params->port_num);
164f8101c74SSanyog Kale 		return ret;
165f8101c74SSanyog Kale 	}
166f8101c74SSanyog Kale 
167f8101c74SSanyog Kale 	/* Program DPN_BlockCtrl1 register */
168f8101c74SSanyog Kale 	ret = sdw_write(s_rt->slave, addr2, (p_params->bps - 1));
169f8101c74SSanyog Kale 	if (ret < 0) {
170f8101c74SSanyog Kale 		dev_err(&s_rt->slave->dev,
171f8101c74SSanyog Kale 			"DPN_BlockCtrl1 register write failed for port %d",
172f8101c74SSanyog Kale 			t_params->port_num);
173f8101c74SSanyog Kale 		return ret;
174f8101c74SSanyog Kale 	}
175f8101c74SSanyog Kale 
176f8101c74SSanyog Kale 	/* Program DPN_SampleCtrl1 register */
177f8101c74SSanyog Kale 	wbuf = (t_params->sample_interval - 1) & SDW_DPN_SAMPLECTRL_LOW;
178f8101c74SSanyog Kale 	ret = sdw_write(s_rt->slave, addr3, wbuf);
179f8101c74SSanyog Kale 	if (ret < 0) {
180f8101c74SSanyog Kale 		dev_err(&s_rt->slave->dev,
181f8101c74SSanyog Kale 			"DPN_SampleCtrl1 register write failed for port %d",
182f8101c74SSanyog Kale 			t_params->port_num);
183f8101c74SSanyog Kale 		return ret;
184f8101c74SSanyog Kale 	}
185f8101c74SSanyog Kale 
186f8101c74SSanyog Kale 	/* Program DPN_OffsetCtrl1 registers */
187f8101c74SSanyog Kale 	ret = sdw_write(s_rt->slave, addr4, t_params->offset1);
188f8101c74SSanyog Kale 	if (ret < 0) {
189f8101c74SSanyog Kale 		dev_err(&s_rt->slave->dev,
190f8101c74SSanyog Kale 			"DPN_OffsetCtrl1 register write failed for port %d",
191f8101c74SSanyog Kale 			t_params->port_num);
192f8101c74SSanyog Kale 		return ret;
193f8101c74SSanyog Kale 	}
194f8101c74SSanyog Kale 
195f8101c74SSanyog Kale 	/* Program DPN_BlockCtrl2 register*/
196f8101c74SSanyog Kale 	if (t_params->blk_grp_ctrl_valid) {
197f8101c74SSanyog Kale 		ret = sdw_write(s_rt->slave, addr5, t_params->blk_grp_ctrl);
198f8101c74SSanyog Kale 		if (ret < 0) {
199f8101c74SSanyog Kale 			dev_err(&s_rt->slave->dev,
200f8101c74SSanyog Kale 				"DPN_BlockCtrl2 reg write failed for port %d",
201f8101c74SSanyog Kale 				t_params->port_num);
202f8101c74SSanyog Kale 			return ret;
203f8101c74SSanyog Kale 		}
204f8101c74SSanyog Kale 	}
205f8101c74SSanyog Kale 
206f8101c74SSanyog Kale 	/* program DPN_LaneCtrl register */
207f8101c74SSanyog Kale 	if (slave_prop->lane_control_support) {
208f8101c74SSanyog Kale 		ret = sdw_write(s_rt->slave, addr6, t_params->lane_ctrl);
209f8101c74SSanyog Kale 		if (ret < 0) {
210f8101c74SSanyog Kale 			dev_err(&s_rt->slave->dev,
211f8101c74SSanyog Kale 				"DPN_LaneCtrl register write failed for port %d",
212f8101c74SSanyog Kale 				t_params->port_num);
213f8101c74SSanyog Kale 			return ret;
214f8101c74SSanyog Kale 		}
215f8101c74SSanyog Kale 	}
216f8101c74SSanyog Kale 
217f8101c74SSanyog Kale 	if (dpn_prop->type != SDW_DPN_SIMPLE) {
218f8101c74SSanyog Kale 		ret = _sdw_program_slave_port_params(bus, s_rt->slave,
219f8101c74SSanyog Kale 						t_params, dpn_prop->type);
220f8101c74SSanyog Kale 		if (ret < 0)
221f8101c74SSanyog Kale 			dev_err(&s_rt->slave->dev,
222f8101c74SSanyog Kale 				"Transport reg write failed for port: %d",
223f8101c74SSanyog Kale 				t_params->port_num);
224f8101c74SSanyog Kale 	}
225f8101c74SSanyog Kale 
226f8101c74SSanyog Kale 	return ret;
227f8101c74SSanyog Kale }
228f8101c74SSanyog Kale 
229f8101c74SSanyog Kale static int sdw_program_master_port_params(struct sdw_bus *bus,
230f8101c74SSanyog Kale 		struct sdw_port_runtime *p_rt)
231f8101c74SSanyog Kale {
232f8101c74SSanyog Kale 	int ret;
233f8101c74SSanyog Kale 
234f8101c74SSanyog Kale 	/*
235f8101c74SSanyog Kale 	 * we need to set transport and port parameters for the port.
236f8101c74SSanyog Kale 	 * Transport parameters refers to the smaple interval, offsets and
237f8101c74SSanyog Kale 	 * hstart/stop etc of the data. Port parameters refers to word
238f8101c74SSanyog Kale 	 * length, flow mode etc of the port
239f8101c74SSanyog Kale 	 */
240f8101c74SSanyog Kale 	ret = bus->port_ops->dpn_set_port_transport_params(bus,
241f8101c74SSanyog Kale 					&p_rt->transport_params,
242f8101c74SSanyog Kale 					bus->params.next_bank);
243f8101c74SSanyog Kale 	if (ret < 0)
244f8101c74SSanyog Kale 		return ret;
245f8101c74SSanyog Kale 
246f8101c74SSanyog Kale 	return bus->port_ops->dpn_set_port_params(bus,
247f8101c74SSanyog Kale 				&p_rt->port_params,
248f8101c74SSanyog Kale 				bus->params.next_bank);
249f8101c74SSanyog Kale }
250f8101c74SSanyog Kale 
251f8101c74SSanyog Kale /**
252f8101c74SSanyog Kale  * sdw_program_port_params() - Programs transport parameters of Master(s)
253f8101c74SSanyog Kale  * and Slave(s)
254f8101c74SSanyog Kale  *
255f8101c74SSanyog Kale  * @m_rt: Master stream runtime
256f8101c74SSanyog Kale  */
257f8101c74SSanyog Kale static int sdw_program_port_params(struct sdw_master_runtime *m_rt)
258f8101c74SSanyog Kale {
259f8101c74SSanyog Kale 	struct sdw_slave_runtime *s_rt = NULL;
260f8101c74SSanyog Kale 	struct sdw_bus *bus = m_rt->bus;
261f8101c74SSanyog Kale 	struct sdw_port_runtime *p_rt;
262f8101c74SSanyog Kale 	int ret = 0;
263f8101c74SSanyog Kale 
264f8101c74SSanyog Kale 	/* Program transport & port parameters for Slave(s) */
265f8101c74SSanyog Kale 	list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
266f8101c74SSanyog Kale 		list_for_each_entry(p_rt, &s_rt->port_list, port_node) {
267f8101c74SSanyog Kale 			ret = sdw_program_slave_port_params(bus, s_rt, p_rt);
268f8101c74SSanyog Kale 			if (ret < 0)
269f8101c74SSanyog Kale 				return ret;
270f8101c74SSanyog Kale 		}
271f8101c74SSanyog Kale 	}
272f8101c74SSanyog Kale 
273f8101c74SSanyog Kale 	/* Program transport & port parameters for Master(s) */
274f8101c74SSanyog Kale 	list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
275f8101c74SSanyog Kale 		ret = sdw_program_master_port_params(bus, p_rt);
276f8101c74SSanyog Kale 		if (ret < 0)
277f8101c74SSanyog Kale 			return ret;
278f8101c74SSanyog Kale 	}
279f8101c74SSanyog Kale 
280f8101c74SSanyog Kale 	return 0;
281f8101c74SSanyog Kale }
282f8101c74SSanyog Kale 
28389e59053SSanyog Kale /**
28479df15b7SSanyog Kale  * sdw_enable_disable_slave_ports: Enable/disable slave data port
28579df15b7SSanyog Kale  *
28679df15b7SSanyog Kale  * @bus: bus instance
28779df15b7SSanyog Kale  * @s_rt: slave runtime
28879df15b7SSanyog Kale  * @p_rt: port runtime
28979df15b7SSanyog Kale  * @en: enable or disable operation
29079df15b7SSanyog Kale  *
29179df15b7SSanyog Kale  * This function only sets the enable/disable bits in the relevant bank, the
29279df15b7SSanyog Kale  * actual enable/disable is done with a bank switch
29379df15b7SSanyog Kale  */
29479df15b7SSanyog Kale static int sdw_enable_disable_slave_ports(struct sdw_bus *bus,
29579df15b7SSanyog Kale 				struct sdw_slave_runtime *s_rt,
29679df15b7SSanyog Kale 				struct sdw_port_runtime *p_rt, bool en)
29779df15b7SSanyog Kale {
29879df15b7SSanyog Kale 	struct sdw_transport_params *t_params = &p_rt->transport_params;
29979df15b7SSanyog Kale 	u32 addr;
30079df15b7SSanyog Kale 	int ret;
30179df15b7SSanyog Kale 
30279df15b7SSanyog Kale 	if (bus->params.next_bank)
30379df15b7SSanyog Kale 		addr = SDW_DPN_CHANNELEN_B1(p_rt->num);
30479df15b7SSanyog Kale 	else
30579df15b7SSanyog Kale 		addr = SDW_DPN_CHANNELEN_B0(p_rt->num);
30679df15b7SSanyog Kale 
30779df15b7SSanyog Kale 	/*
30879df15b7SSanyog Kale 	 * Since bus doesn't support sharing a port across two streams,
30979df15b7SSanyog Kale 	 * it is safe to reset this register
31079df15b7SSanyog Kale 	 */
31179df15b7SSanyog Kale 	if (en)
31279df15b7SSanyog Kale 		ret = sdw_update(s_rt->slave, addr, 0xFF, p_rt->ch_mask);
31379df15b7SSanyog Kale 	else
31479df15b7SSanyog Kale 		ret = sdw_update(s_rt->slave, addr, 0xFF, 0x0);
31579df15b7SSanyog Kale 
31679df15b7SSanyog Kale 	if (ret < 0)
31779df15b7SSanyog Kale 		dev_err(&s_rt->slave->dev,
31879df15b7SSanyog Kale 			"Slave chn_en reg write failed:%d port:%d",
31979df15b7SSanyog Kale 			ret, t_params->port_num);
32079df15b7SSanyog Kale 
32179df15b7SSanyog Kale 	return ret;
32279df15b7SSanyog Kale }
32379df15b7SSanyog Kale 
32479df15b7SSanyog Kale static int sdw_enable_disable_master_ports(struct sdw_master_runtime *m_rt,
32579df15b7SSanyog Kale 			struct sdw_port_runtime *p_rt, bool en)
32679df15b7SSanyog Kale {
32779df15b7SSanyog Kale 	struct sdw_transport_params *t_params = &p_rt->transport_params;
32879df15b7SSanyog Kale 	struct sdw_bus *bus = m_rt->bus;
32979df15b7SSanyog Kale 	struct sdw_enable_ch enable_ch;
33079df15b7SSanyog Kale 	int ret = 0;
33179df15b7SSanyog Kale 
33279df15b7SSanyog Kale 	enable_ch.port_num = p_rt->num;
33379df15b7SSanyog Kale 	enable_ch.ch_mask = p_rt->ch_mask;
33479df15b7SSanyog Kale 	enable_ch.enable = en;
33579df15b7SSanyog Kale 
33679df15b7SSanyog Kale 	/* Perform Master port channel(s) enable/disable */
33779df15b7SSanyog Kale 	if (bus->port_ops->dpn_port_enable_ch) {
33879df15b7SSanyog Kale 		ret = bus->port_ops->dpn_port_enable_ch(bus,
33979df15b7SSanyog Kale 				&enable_ch, bus->params.next_bank);
34079df15b7SSanyog Kale 		if (ret < 0) {
34179df15b7SSanyog Kale 			dev_err(bus->dev,
34279df15b7SSanyog Kale 				"Master chn_en write failed:%d port:%d",
34379df15b7SSanyog Kale 				ret, t_params->port_num);
34479df15b7SSanyog Kale 			return ret;
34579df15b7SSanyog Kale 		}
34679df15b7SSanyog Kale 	} else {
34779df15b7SSanyog Kale 		dev_err(bus->dev,
34879df15b7SSanyog Kale 			"dpn_port_enable_ch not supported, %s failed\n",
34979df15b7SSanyog Kale 			en ? "enable" : "disable");
35079df15b7SSanyog Kale 		return -EINVAL;
35179df15b7SSanyog Kale 	}
35279df15b7SSanyog Kale 
35379df15b7SSanyog Kale 	return 0;
35479df15b7SSanyog Kale }
35579df15b7SSanyog Kale 
35679df15b7SSanyog Kale /**
35779df15b7SSanyog Kale  * sdw_enable_disable_ports() - Enable/disable port(s) for Master and
35879df15b7SSanyog Kale  * Slave(s)
35979df15b7SSanyog Kale  *
36079df15b7SSanyog Kale  * @m_rt: Master stream runtime
36179df15b7SSanyog Kale  * @en: mode (enable/disable)
36279df15b7SSanyog Kale  */
36379df15b7SSanyog Kale static int sdw_enable_disable_ports(struct sdw_master_runtime *m_rt, bool en)
36479df15b7SSanyog Kale {
36579df15b7SSanyog Kale 	struct sdw_port_runtime *s_port, *m_port;
36679df15b7SSanyog Kale 	struct sdw_slave_runtime *s_rt = NULL;
36779df15b7SSanyog Kale 	int ret = 0;
36879df15b7SSanyog Kale 
36979df15b7SSanyog Kale 	/* Enable/Disable Slave port(s) */
37079df15b7SSanyog Kale 	list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
37179df15b7SSanyog Kale 		list_for_each_entry(s_port, &s_rt->port_list, port_node) {
37279df15b7SSanyog Kale 			ret = sdw_enable_disable_slave_ports(m_rt->bus, s_rt,
37379df15b7SSanyog Kale 							s_port, en);
37479df15b7SSanyog Kale 			if (ret < 0)
37579df15b7SSanyog Kale 				return ret;
37679df15b7SSanyog Kale 		}
37779df15b7SSanyog Kale 	}
37879df15b7SSanyog Kale 
37979df15b7SSanyog Kale 	/* Enable/Disable Master port(s) */
38079df15b7SSanyog Kale 	list_for_each_entry(m_port, &m_rt->port_list, port_node) {
38179df15b7SSanyog Kale 		ret = sdw_enable_disable_master_ports(m_rt, m_port, en);
38279df15b7SSanyog Kale 		if (ret < 0)
38379df15b7SSanyog Kale 			return ret;
38479df15b7SSanyog Kale 	}
38579df15b7SSanyog Kale 
38679df15b7SSanyog Kale 	return 0;
38779df15b7SSanyog Kale }
38879df15b7SSanyog Kale 
38979df15b7SSanyog Kale static int sdw_do_port_prep(struct sdw_slave_runtime *s_rt,
39079df15b7SSanyog Kale 		struct sdw_prepare_ch prep_ch, enum sdw_port_prep_ops cmd)
39179df15b7SSanyog Kale {
39279df15b7SSanyog Kale 	const struct sdw_slave_ops *ops = s_rt->slave->ops;
39379df15b7SSanyog Kale 	int ret;
39479df15b7SSanyog Kale 
39579df15b7SSanyog Kale 	if (ops->port_prep) {
39679df15b7SSanyog Kale 		ret = ops->port_prep(s_rt->slave, &prep_ch, cmd);
39779df15b7SSanyog Kale 		if (ret < 0) {
39879df15b7SSanyog Kale 			dev_err(&s_rt->slave->dev,
39979df15b7SSanyog Kale 				"Slave Port Prep cmd %d failed: %d", cmd, ret);
40079df15b7SSanyog Kale 			return ret;
40179df15b7SSanyog Kale 		}
40279df15b7SSanyog Kale 	}
40379df15b7SSanyog Kale 
40479df15b7SSanyog Kale 	return 0;
40579df15b7SSanyog Kale }
40679df15b7SSanyog Kale 
40779df15b7SSanyog Kale static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
40879df15b7SSanyog Kale 			struct sdw_slave_runtime *s_rt,
40979df15b7SSanyog Kale 			struct sdw_port_runtime *p_rt, bool prep)
41079df15b7SSanyog Kale {
41179df15b7SSanyog Kale 	struct completion *port_ready = NULL;
41279df15b7SSanyog Kale 	struct sdw_dpn_prop *dpn_prop;
41379df15b7SSanyog Kale 	struct sdw_prepare_ch prep_ch;
41479df15b7SSanyog Kale 	unsigned int time_left;
41579df15b7SSanyog Kale 	bool intr = false;
41679df15b7SSanyog Kale 	int ret = 0, val;
41779df15b7SSanyog Kale 	u32 addr;
41879df15b7SSanyog Kale 
41979df15b7SSanyog Kale 	prep_ch.num = p_rt->num;
42079df15b7SSanyog Kale 	prep_ch.ch_mask = p_rt->ch_mask;
42179df15b7SSanyog Kale 
42279df15b7SSanyog Kale 	dpn_prop = sdw_get_slave_dpn_prop(s_rt->slave,
42379df15b7SSanyog Kale 					s_rt->direction,
42479df15b7SSanyog Kale 					prep_ch.num);
42579df15b7SSanyog Kale 	if (!dpn_prop) {
42679df15b7SSanyog Kale 		dev_err(bus->dev,
42779df15b7SSanyog Kale 			"Slave Port:%d properties not found", prep_ch.num);
42879df15b7SSanyog Kale 		return -EINVAL;
42979df15b7SSanyog Kale 	}
43079df15b7SSanyog Kale 
43179df15b7SSanyog Kale 	prep_ch.prepare = prep;
43279df15b7SSanyog Kale 
43379df15b7SSanyog Kale 	prep_ch.bank = bus->params.next_bank;
43479df15b7SSanyog Kale 
43579df15b7SSanyog Kale 	if (dpn_prop->device_interrupts || !dpn_prop->simple_ch_prep_sm)
43679df15b7SSanyog Kale 		intr = true;
43779df15b7SSanyog Kale 
43879df15b7SSanyog Kale 	/*
43979df15b7SSanyog Kale 	 * Enable interrupt before Port prepare.
44079df15b7SSanyog Kale 	 * For Port de-prepare, it is assumed that port
44179df15b7SSanyog Kale 	 * was prepared earlier
44279df15b7SSanyog Kale 	 */
44379df15b7SSanyog Kale 	if (prep && intr) {
44479df15b7SSanyog Kale 		ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep,
44579df15b7SSanyog Kale 						dpn_prop->device_interrupts);
44679df15b7SSanyog Kale 		if (ret < 0)
44779df15b7SSanyog Kale 			return ret;
44879df15b7SSanyog Kale 	}
44979df15b7SSanyog Kale 
45079df15b7SSanyog Kale 	/* Inform slave about the impending port prepare */
45179df15b7SSanyog Kale 	sdw_do_port_prep(s_rt, prep_ch, SDW_OPS_PORT_PRE_PREP);
45279df15b7SSanyog Kale 
45379df15b7SSanyog Kale 	/* Prepare Slave port implementing CP_SM */
45479df15b7SSanyog Kale 	if (!dpn_prop->simple_ch_prep_sm) {
45579df15b7SSanyog Kale 		addr = SDW_DPN_PREPARECTRL(p_rt->num);
45679df15b7SSanyog Kale 
45779df15b7SSanyog Kale 		if (prep)
45879df15b7SSanyog Kale 			ret = sdw_update(s_rt->slave, addr,
45979df15b7SSanyog Kale 					0xFF, p_rt->ch_mask);
46079df15b7SSanyog Kale 		else
46179df15b7SSanyog Kale 			ret = sdw_update(s_rt->slave, addr, 0xFF, 0x0);
46279df15b7SSanyog Kale 
46379df15b7SSanyog Kale 		if (ret < 0) {
46479df15b7SSanyog Kale 			dev_err(&s_rt->slave->dev,
46579df15b7SSanyog Kale 				"Slave prep_ctrl reg write failed");
46679df15b7SSanyog Kale 			return ret;
46779df15b7SSanyog Kale 		}
46879df15b7SSanyog Kale 
46979df15b7SSanyog Kale 		/* Wait for completion on port ready */
47079df15b7SSanyog Kale 		port_ready = &s_rt->slave->port_ready[prep_ch.num];
47179df15b7SSanyog Kale 		time_left = wait_for_completion_timeout(port_ready,
47279df15b7SSanyog Kale 				msecs_to_jiffies(dpn_prop->ch_prep_timeout));
47379df15b7SSanyog Kale 
47479df15b7SSanyog Kale 		val = sdw_read(s_rt->slave, SDW_DPN_PREPARESTATUS(p_rt->num));
47579df15b7SSanyog Kale 		val &= p_rt->ch_mask;
47679df15b7SSanyog Kale 		if (!time_left || val) {
47779df15b7SSanyog Kale 			dev_err(&s_rt->slave->dev,
47879df15b7SSanyog Kale 				"Chn prep failed for port:%d", prep_ch.num);
47979df15b7SSanyog Kale 			return -ETIMEDOUT;
48079df15b7SSanyog Kale 		}
48179df15b7SSanyog Kale 	}
48279df15b7SSanyog Kale 
48379df15b7SSanyog Kale 	/* Inform slaves about ports prepared */
48479df15b7SSanyog Kale 	sdw_do_port_prep(s_rt, prep_ch, SDW_OPS_PORT_POST_PREP);
48579df15b7SSanyog Kale 
48679df15b7SSanyog Kale 	/* Disable interrupt after Port de-prepare */
48779df15b7SSanyog Kale 	if (!prep && intr)
48879df15b7SSanyog Kale 		ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep,
48979df15b7SSanyog Kale 						dpn_prop->device_interrupts);
49079df15b7SSanyog Kale 
49179df15b7SSanyog Kale 	return ret;
49279df15b7SSanyog Kale }
49379df15b7SSanyog Kale 
49479df15b7SSanyog Kale static int sdw_prep_deprep_master_ports(struct sdw_master_runtime *m_rt,
49579df15b7SSanyog Kale 				struct sdw_port_runtime *p_rt, bool prep)
49679df15b7SSanyog Kale {
49779df15b7SSanyog Kale 	struct sdw_transport_params *t_params = &p_rt->transport_params;
49879df15b7SSanyog Kale 	struct sdw_bus *bus = m_rt->bus;
49979df15b7SSanyog Kale 	const struct sdw_master_port_ops *ops = bus->port_ops;
50079df15b7SSanyog Kale 	struct sdw_prepare_ch prep_ch;
50179df15b7SSanyog Kale 	int ret = 0;
50279df15b7SSanyog Kale 
50379df15b7SSanyog Kale 	prep_ch.num = p_rt->num;
50479df15b7SSanyog Kale 	prep_ch.ch_mask = p_rt->ch_mask;
50579df15b7SSanyog Kale 	prep_ch.prepare = prep; /* Prepare/De-prepare */
50679df15b7SSanyog Kale 	prep_ch.bank = bus->params.next_bank;
50779df15b7SSanyog Kale 
50879df15b7SSanyog Kale 	/* Pre-prepare/Pre-deprepare port(s) */
50979df15b7SSanyog Kale 	if (ops->dpn_port_prep) {
51079df15b7SSanyog Kale 		ret = ops->dpn_port_prep(bus, &prep_ch);
51179df15b7SSanyog Kale 		if (ret < 0) {
51279df15b7SSanyog Kale 			dev_err(bus->dev, "Port prepare failed for port:%d",
51379df15b7SSanyog Kale 					t_params->port_num);
51479df15b7SSanyog Kale 			return ret;
51579df15b7SSanyog Kale 		}
51679df15b7SSanyog Kale 	}
51779df15b7SSanyog Kale 
51879df15b7SSanyog Kale 	return ret;
51979df15b7SSanyog Kale }
52079df15b7SSanyog Kale 
52179df15b7SSanyog Kale /**
52279df15b7SSanyog Kale  * sdw_prep_deprep_ports() - Prepare/De-prepare port(s) for Master(s) and
52379df15b7SSanyog Kale  * Slave(s)
52479df15b7SSanyog Kale  *
52579df15b7SSanyog Kale  * @m_rt: Master runtime handle
52679df15b7SSanyog Kale  * @prep: Prepare or De-prepare
52779df15b7SSanyog Kale  */
52879df15b7SSanyog Kale static int sdw_prep_deprep_ports(struct sdw_master_runtime *m_rt, bool prep)
52979df15b7SSanyog Kale {
53079df15b7SSanyog Kale 	struct sdw_slave_runtime *s_rt = NULL;
53179df15b7SSanyog Kale 	struct sdw_port_runtime *p_rt;
53279df15b7SSanyog Kale 	int ret = 0;
53379df15b7SSanyog Kale 
53479df15b7SSanyog Kale 	/* Prepare/De-prepare Slave port(s) */
53579df15b7SSanyog Kale 	list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
53679df15b7SSanyog Kale 		list_for_each_entry(p_rt, &s_rt->port_list, port_node) {
53779df15b7SSanyog Kale 			ret = sdw_prep_deprep_slave_ports(m_rt->bus, s_rt,
53879df15b7SSanyog Kale 							p_rt, prep);
53979df15b7SSanyog Kale 			if (ret < 0)
54079df15b7SSanyog Kale 				return ret;
54179df15b7SSanyog Kale 		}
54279df15b7SSanyog Kale 	}
54379df15b7SSanyog Kale 
54479df15b7SSanyog Kale 	/* Prepare/De-prepare Master port(s) */
54579df15b7SSanyog Kale 	list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
54679df15b7SSanyog Kale 		ret = sdw_prep_deprep_master_ports(m_rt, p_rt, prep);
54779df15b7SSanyog Kale 		if (ret < 0)
54879df15b7SSanyog Kale 			return ret;
54979df15b7SSanyog Kale 	}
55079df15b7SSanyog Kale 
55179df15b7SSanyog Kale 	return ret;
55279df15b7SSanyog Kale }
55379df15b7SSanyog Kale 
55479df15b7SSanyog Kale /**
55599b8a5d6SSanyog Kale  * sdw_notify_config() - Notify bus configuration
55699b8a5d6SSanyog Kale  *
55799b8a5d6SSanyog Kale  * @m_rt: Master runtime handle
55899b8a5d6SSanyog Kale  *
55999b8a5d6SSanyog Kale  * This function notifies the Master(s) and Slave(s) of the
56099b8a5d6SSanyog Kale  * new bus configuration.
56199b8a5d6SSanyog Kale  */
56299b8a5d6SSanyog Kale static int sdw_notify_config(struct sdw_master_runtime *m_rt)
56399b8a5d6SSanyog Kale {
56499b8a5d6SSanyog Kale 	struct sdw_slave_runtime *s_rt;
56599b8a5d6SSanyog Kale 	struct sdw_bus *bus = m_rt->bus;
56699b8a5d6SSanyog Kale 	struct sdw_slave *slave;
56799b8a5d6SSanyog Kale 	int ret = 0;
56899b8a5d6SSanyog Kale 
56999b8a5d6SSanyog Kale 	if (bus->ops->set_bus_conf) {
57099b8a5d6SSanyog Kale 		ret = bus->ops->set_bus_conf(bus, &bus->params);
57199b8a5d6SSanyog Kale 		if (ret < 0)
57299b8a5d6SSanyog Kale 			return ret;
57399b8a5d6SSanyog Kale 	}
57499b8a5d6SSanyog Kale 
57599b8a5d6SSanyog Kale 	list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
57699b8a5d6SSanyog Kale 		slave = s_rt->slave;
57799b8a5d6SSanyog Kale 
57899b8a5d6SSanyog Kale 		if (slave->ops->bus_config) {
57999b8a5d6SSanyog Kale 			ret = slave->ops->bus_config(slave, &bus->params);
58099b8a5d6SSanyog Kale 			if (ret < 0)
58199b8a5d6SSanyog Kale 				dev_err(bus->dev, "Notify Slave: %d failed",
58299b8a5d6SSanyog Kale 								slave->dev_num);
58399b8a5d6SSanyog Kale 			return ret;
58499b8a5d6SSanyog Kale 		}
58599b8a5d6SSanyog Kale 	}
58699b8a5d6SSanyog Kale 
58799b8a5d6SSanyog Kale 	return ret;
58899b8a5d6SSanyog Kale }
58999b8a5d6SSanyog Kale 
59099b8a5d6SSanyog Kale /**
59199b8a5d6SSanyog Kale  * sdw_program_params() - Program transport and port parameters for Master(s)
59299b8a5d6SSanyog Kale  * and Slave(s)
59399b8a5d6SSanyog Kale  *
59499b8a5d6SSanyog Kale  * @bus: SDW bus instance
59599b8a5d6SSanyog Kale  */
59699b8a5d6SSanyog Kale static int sdw_program_params(struct sdw_bus *bus)
59799b8a5d6SSanyog Kale {
59899b8a5d6SSanyog Kale 	struct sdw_master_runtime *m_rt = NULL;
59999b8a5d6SSanyog Kale 	int ret = 0;
60099b8a5d6SSanyog Kale 
60199b8a5d6SSanyog Kale 	list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
60299b8a5d6SSanyog Kale 		ret = sdw_program_port_params(m_rt);
60399b8a5d6SSanyog Kale 		if (ret < 0) {
60499b8a5d6SSanyog Kale 			dev_err(bus->dev,
60599b8a5d6SSanyog Kale 				"Program transport params failed: %d", ret);
60699b8a5d6SSanyog Kale 			return ret;
60799b8a5d6SSanyog Kale 		}
60899b8a5d6SSanyog Kale 
60999b8a5d6SSanyog Kale 		ret = sdw_notify_config(m_rt);
61099b8a5d6SSanyog Kale 		if (ret < 0) {
61199b8a5d6SSanyog Kale 			dev_err(bus->dev, "Notify bus config failed: %d", ret);
61299b8a5d6SSanyog Kale 			return ret;
61399b8a5d6SSanyog Kale 		}
61499b8a5d6SSanyog Kale 
61599b8a5d6SSanyog Kale 		/* Enable port(s) on alternate bank for all active streams */
61699b8a5d6SSanyog Kale 		if (m_rt->stream->state != SDW_STREAM_ENABLED)
61799b8a5d6SSanyog Kale 			continue;
61899b8a5d6SSanyog Kale 
61999b8a5d6SSanyog Kale 		ret = sdw_enable_disable_ports(m_rt, true);
62099b8a5d6SSanyog Kale 		if (ret < 0) {
62199b8a5d6SSanyog Kale 			dev_err(bus->dev, "Enable channel failed: %d", ret);
62299b8a5d6SSanyog Kale 			return ret;
62399b8a5d6SSanyog Kale 		}
62499b8a5d6SSanyog Kale 	}
62599b8a5d6SSanyog Kale 
62699b8a5d6SSanyog Kale 	return ret;
62799b8a5d6SSanyog Kale }
62899b8a5d6SSanyog Kale 
62999b8a5d6SSanyog Kale static int sdw_bank_switch(struct sdw_bus *bus)
63099b8a5d6SSanyog Kale {
63199b8a5d6SSanyog Kale 	int col_index, row_index;
63299b8a5d6SSanyog Kale 	struct sdw_msg *wr_msg;
63399b8a5d6SSanyog Kale 	u8 *wbuf = NULL;
63499b8a5d6SSanyog Kale 	int ret = 0;
63599b8a5d6SSanyog Kale 	u16 addr;
63699b8a5d6SSanyog Kale 
63799b8a5d6SSanyog Kale 	wr_msg = kzalloc(sizeof(*wr_msg), GFP_KERNEL);
63899b8a5d6SSanyog Kale 	if (!wr_msg)
63999b8a5d6SSanyog Kale 		return -ENOMEM;
64099b8a5d6SSanyog Kale 
64199b8a5d6SSanyog Kale 	wbuf = kzalloc(sizeof(*wbuf), GFP_KERNEL);
64299b8a5d6SSanyog Kale 	if (!wbuf) {
64399b8a5d6SSanyog Kale 		ret = -ENOMEM;
64499b8a5d6SSanyog Kale 		goto error_1;
64599b8a5d6SSanyog Kale 	}
64699b8a5d6SSanyog Kale 
64799b8a5d6SSanyog Kale 	/* Get row and column index to program register */
64899b8a5d6SSanyog Kale 	col_index = sdw_find_col_index(bus->params.col);
64999b8a5d6SSanyog Kale 	row_index = sdw_find_row_index(bus->params.row);
65099b8a5d6SSanyog Kale 	wbuf[0] = col_index | (row_index << 3);
65199b8a5d6SSanyog Kale 
65299b8a5d6SSanyog Kale 	if (bus->params.next_bank)
65399b8a5d6SSanyog Kale 		addr = SDW_SCP_FRAMECTRL_B1;
65499b8a5d6SSanyog Kale 	else
65599b8a5d6SSanyog Kale 		addr = SDW_SCP_FRAMECTRL_B0;
65699b8a5d6SSanyog Kale 
65799b8a5d6SSanyog Kale 	sdw_fill_msg(wr_msg, NULL, addr, 1, SDW_BROADCAST_DEV_NUM,
65899b8a5d6SSanyog Kale 					SDW_MSG_FLAG_WRITE, wbuf);
65999b8a5d6SSanyog Kale 	wr_msg->ssp_sync = true;
66099b8a5d6SSanyog Kale 
66199b8a5d6SSanyog Kale 	ret = sdw_transfer(bus, wr_msg);
66299b8a5d6SSanyog Kale 	if (ret < 0) {
66399b8a5d6SSanyog Kale 		dev_err(bus->dev, "Slave frame_ctrl reg write failed");
66499b8a5d6SSanyog Kale 		goto error;
66599b8a5d6SSanyog Kale 	}
66699b8a5d6SSanyog Kale 
66799b8a5d6SSanyog Kale 	kfree(wr_msg);
66899b8a5d6SSanyog Kale 	kfree(wbuf);
66999b8a5d6SSanyog Kale 	bus->defer_msg.msg = NULL;
67099b8a5d6SSanyog Kale 	bus->params.curr_bank = !bus->params.curr_bank;
67199b8a5d6SSanyog Kale 	bus->params.next_bank = !bus->params.next_bank;
67299b8a5d6SSanyog Kale 
67399b8a5d6SSanyog Kale 	return 0;
67499b8a5d6SSanyog Kale 
67599b8a5d6SSanyog Kale error:
67699b8a5d6SSanyog Kale 	kfree(wbuf);
67799b8a5d6SSanyog Kale error_1:
67899b8a5d6SSanyog Kale 	kfree(wr_msg);
67999b8a5d6SSanyog Kale 	return ret;
68099b8a5d6SSanyog Kale }
68199b8a5d6SSanyog Kale 
68299b8a5d6SSanyog Kale static int do_bank_switch(struct sdw_stream_runtime *stream)
68399b8a5d6SSanyog Kale {
68499b8a5d6SSanyog Kale 	struct sdw_master_runtime *m_rt = stream->m_rt;
68599b8a5d6SSanyog Kale 	const struct sdw_master_ops *ops;
68699b8a5d6SSanyog Kale 	struct sdw_bus *bus = m_rt->bus;
68799b8a5d6SSanyog Kale 	int ret = 0;
68899b8a5d6SSanyog Kale 
68999b8a5d6SSanyog Kale 	ops = bus->ops;
69099b8a5d6SSanyog Kale 
69199b8a5d6SSanyog Kale 	/* Pre-bank switch */
69299b8a5d6SSanyog Kale 	if (ops->pre_bank_switch) {
69399b8a5d6SSanyog Kale 		ret = ops->pre_bank_switch(bus);
69499b8a5d6SSanyog Kale 		if (ret < 0) {
69599b8a5d6SSanyog Kale 			dev_err(bus->dev, "Pre bank switch op failed: %d", ret);
69699b8a5d6SSanyog Kale 			return ret;
69799b8a5d6SSanyog Kale 		}
69899b8a5d6SSanyog Kale 	}
69999b8a5d6SSanyog Kale 
70099b8a5d6SSanyog Kale 	/* Bank switch */
70199b8a5d6SSanyog Kale 	ret = sdw_bank_switch(bus);
70299b8a5d6SSanyog Kale 	if (ret < 0) {
70399b8a5d6SSanyog Kale 		dev_err(bus->dev, "Bank switch failed: %d", ret);
70499b8a5d6SSanyog Kale 		return ret;
70599b8a5d6SSanyog Kale 	}
70699b8a5d6SSanyog Kale 
70799b8a5d6SSanyog Kale 	/* Post-bank switch */
70899b8a5d6SSanyog Kale 	if (ops->post_bank_switch) {
70999b8a5d6SSanyog Kale 		ret = ops->post_bank_switch(bus);
71099b8a5d6SSanyog Kale 		if (ret < 0) {
71199b8a5d6SSanyog Kale 			dev_err(bus->dev,
71299b8a5d6SSanyog Kale 					"Post bank switch op failed: %d", ret);
71399b8a5d6SSanyog Kale 		}
71499b8a5d6SSanyog Kale 	}
71599b8a5d6SSanyog Kale 
71699b8a5d6SSanyog Kale 	return ret;
71799b8a5d6SSanyog Kale }
71899b8a5d6SSanyog Kale 
71999b8a5d6SSanyog Kale /**
72089e59053SSanyog Kale  * sdw_release_stream() - Free the assigned stream runtime
72189e59053SSanyog Kale  *
72289e59053SSanyog Kale  * @stream: SoundWire stream runtime
72389e59053SSanyog Kale  *
72489e59053SSanyog Kale  * sdw_release_stream should be called only once per stream
72589e59053SSanyog Kale  */
72689e59053SSanyog Kale void sdw_release_stream(struct sdw_stream_runtime *stream)
72789e59053SSanyog Kale {
72889e59053SSanyog Kale 	kfree(stream);
72989e59053SSanyog Kale }
73089e59053SSanyog Kale EXPORT_SYMBOL(sdw_release_stream);
73189e59053SSanyog Kale 
73289e59053SSanyog Kale /**
73389e59053SSanyog Kale  * sdw_alloc_stream() - Allocate and return stream runtime
73489e59053SSanyog Kale  *
73589e59053SSanyog Kale  * @stream_name: SoundWire stream name
73689e59053SSanyog Kale  *
73789e59053SSanyog Kale  * Allocates a SoundWire stream runtime instance.
73889e59053SSanyog Kale  * sdw_alloc_stream should be called only once per stream. Typically
73989e59053SSanyog Kale  * invoked from ALSA/ASoC machine/platform driver.
74089e59053SSanyog Kale  */
74189e59053SSanyog Kale struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name)
74289e59053SSanyog Kale {
74389e59053SSanyog Kale 	struct sdw_stream_runtime *stream;
74489e59053SSanyog Kale 
74589e59053SSanyog Kale 	stream = kzalloc(sizeof(*stream), GFP_KERNEL);
74689e59053SSanyog Kale 	if (!stream)
74789e59053SSanyog Kale 		return NULL;
74889e59053SSanyog Kale 
74989e59053SSanyog Kale 	stream->name = stream_name;
7500c4a1049SSanyog Kale 	INIT_LIST_HEAD(&stream->master_list);
75189e59053SSanyog Kale 	stream->state = SDW_STREAM_ALLOCATED;
75289e59053SSanyog Kale 
75389e59053SSanyog Kale 	return stream;
75489e59053SSanyog Kale }
75589e59053SSanyog Kale EXPORT_SYMBOL(sdw_alloc_stream);
75689e59053SSanyog Kale 
75789e59053SSanyog Kale /**
75889e59053SSanyog Kale  * sdw_alloc_master_rt() - Allocates and initialize Master runtime handle
75989e59053SSanyog Kale  *
76089e59053SSanyog Kale  * @bus: SDW bus instance
76189e59053SSanyog Kale  * @stream_config: Stream configuration
76289e59053SSanyog Kale  * @stream: Stream runtime handle.
76389e59053SSanyog Kale  *
76489e59053SSanyog Kale  * This function is to be called with bus_lock held.
76589e59053SSanyog Kale  */
76689e59053SSanyog Kale static struct sdw_master_runtime
76789e59053SSanyog Kale *sdw_alloc_master_rt(struct sdw_bus *bus,
76889e59053SSanyog Kale 			struct sdw_stream_config *stream_config,
76989e59053SSanyog Kale 			struct sdw_stream_runtime *stream)
77089e59053SSanyog Kale {
77189e59053SSanyog Kale 	struct sdw_master_runtime *m_rt;
77289e59053SSanyog Kale 
77389e59053SSanyog Kale 	m_rt = stream->m_rt;
77489e59053SSanyog Kale 
77589e59053SSanyog Kale 	/*
77689e59053SSanyog Kale 	 * check if Master is already allocated (as a result of Slave adding
77789e59053SSanyog Kale 	 * it first), if so skip allocation and go to configure
77889e59053SSanyog Kale 	 */
77989e59053SSanyog Kale 	if (m_rt)
78089e59053SSanyog Kale 		goto stream_config;
78189e59053SSanyog Kale 
78289e59053SSanyog Kale 	m_rt = kzalloc(sizeof(*m_rt), GFP_KERNEL);
78389e59053SSanyog Kale 	if (!m_rt)
78489e59053SSanyog Kale 		return NULL;
78589e59053SSanyog Kale 
78689e59053SSanyog Kale 	/* Initialization of Master runtime handle */
787bbe7379dSSanyog Kale 	INIT_LIST_HEAD(&m_rt->port_list);
78889e59053SSanyog Kale 	INIT_LIST_HEAD(&m_rt->slave_rt_list);
78989e59053SSanyog Kale 	stream->m_rt = m_rt;
79089e59053SSanyog Kale 
79189e59053SSanyog Kale 	list_add_tail(&m_rt->bus_node, &bus->m_rt_list);
79289e59053SSanyog Kale 
79389e59053SSanyog Kale stream_config:
79489e59053SSanyog Kale 	m_rt->ch_count = stream_config->ch_count;
79589e59053SSanyog Kale 	m_rt->bus = bus;
79689e59053SSanyog Kale 	m_rt->stream = stream;
79789e59053SSanyog Kale 	m_rt->direction = stream_config->direction;
79889e59053SSanyog Kale 
79989e59053SSanyog Kale 	return m_rt;
80089e59053SSanyog Kale }
80189e59053SSanyog Kale 
80289e59053SSanyog Kale /**
80389e59053SSanyog Kale  * sdw_alloc_slave_rt() - Allocate and initialize Slave runtime handle.
80489e59053SSanyog Kale  *
80589e59053SSanyog Kale  * @slave: Slave handle
80689e59053SSanyog Kale  * @stream_config: Stream configuration
80789e59053SSanyog Kale  * @stream: Stream runtime handle
80889e59053SSanyog Kale  *
80989e59053SSanyog Kale  * This function is to be called with bus_lock held.
81089e59053SSanyog Kale  */
81189e59053SSanyog Kale static struct sdw_slave_runtime
81289e59053SSanyog Kale *sdw_alloc_slave_rt(struct sdw_slave *slave,
81389e59053SSanyog Kale 			struct sdw_stream_config *stream_config,
81489e59053SSanyog Kale 			struct sdw_stream_runtime *stream)
81589e59053SSanyog Kale {
81689e59053SSanyog Kale 	struct sdw_slave_runtime *s_rt = NULL;
81789e59053SSanyog Kale 
81889e59053SSanyog Kale 	s_rt = kzalloc(sizeof(*s_rt), GFP_KERNEL);
81989e59053SSanyog Kale 	if (!s_rt)
82089e59053SSanyog Kale 		return NULL;
82189e59053SSanyog Kale 
822bbe7379dSSanyog Kale 	INIT_LIST_HEAD(&s_rt->port_list);
82389e59053SSanyog Kale 	s_rt->ch_count = stream_config->ch_count;
82489e59053SSanyog Kale 	s_rt->direction = stream_config->direction;
82589e59053SSanyog Kale 	s_rt->slave = slave;
82689e59053SSanyog Kale 
82789e59053SSanyog Kale 	return s_rt;
82889e59053SSanyog Kale }
82989e59053SSanyog Kale 
830bbe7379dSSanyog Kale static void sdw_master_port_release(struct sdw_bus *bus,
831bbe7379dSSanyog Kale 			struct sdw_master_runtime *m_rt)
832bbe7379dSSanyog Kale {
833bbe7379dSSanyog Kale 	struct sdw_port_runtime *p_rt, *_p_rt;
834bbe7379dSSanyog Kale 
835bbe7379dSSanyog Kale 	list_for_each_entry_safe(p_rt, _p_rt,
836bbe7379dSSanyog Kale 			&m_rt->port_list, port_node) {
837bbe7379dSSanyog Kale 		list_del(&p_rt->port_node);
838bbe7379dSSanyog Kale 		kfree(p_rt);
839bbe7379dSSanyog Kale 	}
840bbe7379dSSanyog Kale }
841bbe7379dSSanyog Kale 
842bbe7379dSSanyog Kale static void sdw_slave_port_release(struct sdw_bus *bus,
843bbe7379dSSanyog Kale 			struct sdw_slave *slave,
844bbe7379dSSanyog Kale 			struct sdw_stream_runtime *stream)
845bbe7379dSSanyog Kale {
846bbe7379dSSanyog Kale 	struct sdw_port_runtime *p_rt, *_p_rt;
847bbe7379dSSanyog Kale 	struct sdw_master_runtime *m_rt = stream->m_rt;
848bbe7379dSSanyog Kale 	struct sdw_slave_runtime *s_rt;
849bbe7379dSSanyog Kale 
850bbe7379dSSanyog Kale 	list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
851bbe7379dSSanyog Kale 		if (s_rt->slave != slave)
852bbe7379dSSanyog Kale 			continue;
853bbe7379dSSanyog Kale 
854bbe7379dSSanyog Kale 		list_for_each_entry_safe(p_rt, _p_rt,
855bbe7379dSSanyog Kale 				&s_rt->port_list, port_node) {
856bbe7379dSSanyog Kale 			list_del(&p_rt->port_node);
857bbe7379dSSanyog Kale 			kfree(p_rt);
858bbe7379dSSanyog Kale 		}
859bbe7379dSSanyog Kale 	}
860bbe7379dSSanyog Kale }
861bbe7379dSSanyog Kale 
86289e59053SSanyog Kale /**
86389e59053SSanyog Kale  * sdw_release_slave_stream() - Free Slave(s) runtime handle
86489e59053SSanyog Kale  *
86589e59053SSanyog Kale  * @slave: Slave handle.
86689e59053SSanyog Kale  * @stream: Stream runtime handle.
86789e59053SSanyog Kale  *
86889e59053SSanyog Kale  * This function is to be called with bus_lock held.
86989e59053SSanyog Kale  */
87089e59053SSanyog Kale static void sdw_release_slave_stream(struct sdw_slave *slave,
87189e59053SSanyog Kale 			struct sdw_stream_runtime *stream)
87289e59053SSanyog Kale {
87389e59053SSanyog Kale 	struct sdw_slave_runtime *s_rt, *_s_rt;
87489e59053SSanyog Kale 	struct sdw_master_runtime *m_rt = stream->m_rt;
87589e59053SSanyog Kale 
87689e59053SSanyog Kale 	/* Retrieve Slave runtime handle */
87789e59053SSanyog Kale 	list_for_each_entry_safe(s_rt, _s_rt,
87889e59053SSanyog Kale 			&m_rt->slave_rt_list, m_rt_node) {
87989e59053SSanyog Kale 
88089e59053SSanyog Kale 		if (s_rt->slave == slave) {
88189e59053SSanyog Kale 			list_del(&s_rt->m_rt_node);
88289e59053SSanyog Kale 			kfree(s_rt);
88389e59053SSanyog Kale 			return;
88489e59053SSanyog Kale 		}
88589e59053SSanyog Kale 	}
88689e59053SSanyog Kale }
88789e59053SSanyog Kale 
88889e59053SSanyog Kale /**
88989e59053SSanyog Kale  * sdw_release_master_stream() - Free Master runtime handle
89089e59053SSanyog Kale  *
89189e59053SSanyog Kale  * @stream: Stream runtime handle.
89289e59053SSanyog Kale  *
89389e59053SSanyog Kale  * This function is to be called with bus_lock held
89489e59053SSanyog Kale  * It frees the Master runtime handle and associated Slave(s) runtime
89589e59053SSanyog Kale  * handle. If this is called first then sdw_release_slave_stream() will have
89689e59053SSanyog Kale  * no effect as Slave(s) runtime handle would already be freed up.
89789e59053SSanyog Kale  */
89889e59053SSanyog Kale static void sdw_release_master_stream(struct sdw_stream_runtime *stream)
89989e59053SSanyog Kale {
90089e59053SSanyog Kale 	struct sdw_master_runtime *m_rt = stream->m_rt;
90189e59053SSanyog Kale 	struct sdw_slave_runtime *s_rt, *_s_rt;
90289e59053SSanyog Kale 
9038d6ccf5cSSanyog Kale 	list_for_each_entry_safe(s_rt, _s_rt, &m_rt->slave_rt_list, m_rt_node) {
9048d6ccf5cSSanyog Kale 		sdw_slave_port_release(s_rt->slave->bus, s_rt->slave, stream);
9058d6ccf5cSSanyog Kale 		sdw_release_slave_stream(s_rt->slave, stream);
9068d6ccf5cSSanyog Kale 	}
90789e59053SSanyog Kale 
90889e59053SSanyog Kale 	list_del(&m_rt->bus_node);
90989e59053SSanyog Kale }
91089e59053SSanyog Kale 
91189e59053SSanyog Kale /**
91289e59053SSanyog Kale  * sdw_stream_remove_master() - Remove master from sdw_stream
91389e59053SSanyog Kale  *
91489e59053SSanyog Kale  * @bus: SDW Bus instance
91589e59053SSanyog Kale  * @stream: SoundWire stream
91689e59053SSanyog Kale  *
917bbe7379dSSanyog Kale  * This removes and frees port_rt and master_rt from a stream
91889e59053SSanyog Kale  */
91989e59053SSanyog Kale int sdw_stream_remove_master(struct sdw_bus *bus,
92089e59053SSanyog Kale 		struct sdw_stream_runtime *stream)
92189e59053SSanyog Kale {
92289e59053SSanyog Kale 	mutex_lock(&bus->bus_lock);
92389e59053SSanyog Kale 
92489e59053SSanyog Kale 	sdw_release_master_stream(stream);
925bbe7379dSSanyog Kale 	sdw_master_port_release(bus, stream->m_rt);
92689e59053SSanyog Kale 	stream->state = SDW_STREAM_RELEASED;
92789e59053SSanyog Kale 	kfree(stream->m_rt);
92889e59053SSanyog Kale 	stream->m_rt = NULL;
92989e59053SSanyog Kale 
93089e59053SSanyog Kale 	mutex_unlock(&bus->bus_lock);
93189e59053SSanyog Kale 
93289e59053SSanyog Kale 	return 0;
93389e59053SSanyog Kale }
93489e59053SSanyog Kale EXPORT_SYMBOL(sdw_stream_remove_master);
93589e59053SSanyog Kale 
93689e59053SSanyog Kale /**
93789e59053SSanyog Kale  * sdw_stream_remove_slave() - Remove slave from sdw_stream
93889e59053SSanyog Kale  *
93989e59053SSanyog Kale  * @slave: SDW Slave instance
94089e59053SSanyog Kale  * @stream: SoundWire stream
94189e59053SSanyog Kale  *
942bbe7379dSSanyog Kale  * This removes and frees port_rt and slave_rt from a stream
94389e59053SSanyog Kale  */
94489e59053SSanyog Kale int sdw_stream_remove_slave(struct sdw_slave *slave,
94589e59053SSanyog Kale 		struct sdw_stream_runtime *stream)
94689e59053SSanyog Kale {
94789e59053SSanyog Kale 	mutex_lock(&slave->bus->bus_lock);
94889e59053SSanyog Kale 
949bbe7379dSSanyog Kale 	sdw_slave_port_release(slave->bus, slave, stream);
95089e59053SSanyog Kale 	sdw_release_slave_stream(slave, stream);
95189e59053SSanyog Kale 
95289e59053SSanyog Kale 	mutex_unlock(&slave->bus->bus_lock);
95389e59053SSanyog Kale 
95489e59053SSanyog Kale 	return 0;
95589e59053SSanyog Kale }
95689e59053SSanyog Kale EXPORT_SYMBOL(sdw_stream_remove_slave);
95789e59053SSanyog Kale 
95889e59053SSanyog Kale /**
95989e59053SSanyog Kale  * sdw_config_stream() - Configure the allocated stream
96089e59053SSanyog Kale  *
96189e59053SSanyog Kale  * @dev: SDW device
96289e59053SSanyog Kale  * @stream: SoundWire stream
96389e59053SSanyog Kale  * @stream_config: Stream configuration for audio stream
96489e59053SSanyog Kale  * @is_slave: is API called from Slave or Master
96589e59053SSanyog Kale  *
96689e59053SSanyog Kale  * This function is to be called with bus_lock held.
96789e59053SSanyog Kale  */
96889e59053SSanyog Kale static int sdw_config_stream(struct device *dev,
96989e59053SSanyog Kale 		struct sdw_stream_runtime *stream,
97089e59053SSanyog Kale 		struct sdw_stream_config *stream_config, bool is_slave)
97189e59053SSanyog Kale {
97289e59053SSanyog Kale 	/*
97389e59053SSanyog Kale 	 * Update the stream rate, channel and bps based on data
97489e59053SSanyog Kale 	 * source. For more than one data source (multilink),
97589e59053SSanyog Kale 	 * match the rate, bps, stream type and increment number of channels.
97689e59053SSanyog Kale 	 *
97789e59053SSanyog Kale 	 * If rate/bps is zero, it means the values are not set, so skip
97889e59053SSanyog Kale 	 * comparison and allow the value to be set and stored in stream
97989e59053SSanyog Kale 	 */
98089e59053SSanyog Kale 	if (stream->params.rate &&
98189e59053SSanyog Kale 			stream->params.rate != stream_config->frame_rate) {
98289e59053SSanyog Kale 		dev_err(dev, "rate not matching, stream:%s", stream->name);
98389e59053SSanyog Kale 		return -EINVAL;
98489e59053SSanyog Kale 	}
98589e59053SSanyog Kale 
98689e59053SSanyog Kale 	if (stream->params.bps &&
98789e59053SSanyog Kale 			stream->params.bps != stream_config->bps) {
98889e59053SSanyog Kale 		dev_err(dev, "bps not matching, stream:%s", stream->name);
98989e59053SSanyog Kale 		return -EINVAL;
99089e59053SSanyog Kale 	}
99189e59053SSanyog Kale 
99289e59053SSanyog Kale 	stream->type = stream_config->type;
99389e59053SSanyog Kale 	stream->params.rate = stream_config->frame_rate;
99489e59053SSanyog Kale 	stream->params.bps = stream_config->bps;
99589e59053SSanyog Kale 
99689e59053SSanyog Kale 	/* TODO: Update this check during Device-device support */
99789e59053SSanyog Kale 	if (is_slave)
99889e59053SSanyog Kale 		stream->params.ch_count += stream_config->ch_count;
99989e59053SSanyog Kale 
100089e59053SSanyog Kale 	return 0;
100189e59053SSanyog Kale }
100289e59053SSanyog Kale 
1003bbe7379dSSanyog Kale static int sdw_is_valid_port_range(struct device *dev,
1004bbe7379dSSanyog Kale 				struct sdw_port_runtime *p_rt)
1005bbe7379dSSanyog Kale {
1006bbe7379dSSanyog Kale 	if (!SDW_VALID_PORT_RANGE(p_rt->num)) {
1007bbe7379dSSanyog Kale 		dev_err(dev,
1008bbe7379dSSanyog Kale 			"SoundWire: Invalid port number :%d", p_rt->num);
1009bbe7379dSSanyog Kale 		return -EINVAL;
1010bbe7379dSSanyog Kale 	}
1011bbe7379dSSanyog Kale 
1012bbe7379dSSanyog Kale 	return 0;
1013bbe7379dSSanyog Kale }
1014bbe7379dSSanyog Kale 
1015bbe7379dSSanyog Kale static struct sdw_port_runtime *sdw_port_alloc(struct device *dev,
1016bbe7379dSSanyog Kale 				struct sdw_port_config *port_config,
1017bbe7379dSSanyog Kale 				int port_index)
1018bbe7379dSSanyog Kale {
1019bbe7379dSSanyog Kale 	struct sdw_port_runtime *p_rt;
1020bbe7379dSSanyog Kale 
1021bbe7379dSSanyog Kale 	p_rt = kzalloc(sizeof(*p_rt), GFP_KERNEL);
1022bbe7379dSSanyog Kale 	if (!p_rt)
1023bbe7379dSSanyog Kale 		return NULL;
1024bbe7379dSSanyog Kale 
1025bbe7379dSSanyog Kale 	p_rt->ch_mask = port_config[port_index].ch_mask;
1026bbe7379dSSanyog Kale 	p_rt->num = port_config[port_index].num;
1027bbe7379dSSanyog Kale 
1028bbe7379dSSanyog Kale 	return p_rt;
1029bbe7379dSSanyog Kale }
1030bbe7379dSSanyog Kale 
1031bbe7379dSSanyog Kale static int sdw_master_port_config(struct sdw_bus *bus,
1032bbe7379dSSanyog Kale 			struct sdw_master_runtime *m_rt,
1033bbe7379dSSanyog Kale 			struct sdw_port_config *port_config,
1034bbe7379dSSanyog Kale 			unsigned int num_ports)
1035bbe7379dSSanyog Kale {
1036bbe7379dSSanyog Kale 	struct sdw_port_runtime *p_rt;
1037bbe7379dSSanyog Kale 	int i;
1038bbe7379dSSanyog Kale 
1039bbe7379dSSanyog Kale 	/* Iterate for number of ports to perform initialization */
1040bbe7379dSSanyog Kale 	for (i = 0; i < num_ports; i++) {
1041bbe7379dSSanyog Kale 		p_rt = sdw_port_alloc(bus->dev, port_config, i);
1042bbe7379dSSanyog Kale 		if (!p_rt)
1043bbe7379dSSanyog Kale 			return -ENOMEM;
1044bbe7379dSSanyog Kale 
1045bbe7379dSSanyog Kale 		/*
1046bbe7379dSSanyog Kale 		 * TODO: Check port capabilities for requested
1047bbe7379dSSanyog Kale 		 * configuration (audio mode support)
1048bbe7379dSSanyog Kale 		 */
1049bbe7379dSSanyog Kale 
1050bbe7379dSSanyog Kale 		list_add_tail(&p_rt->port_node, &m_rt->port_list);
1051bbe7379dSSanyog Kale 	}
1052bbe7379dSSanyog Kale 
1053bbe7379dSSanyog Kale 	return 0;
1054bbe7379dSSanyog Kale }
1055bbe7379dSSanyog Kale 
1056bbe7379dSSanyog Kale static int sdw_slave_port_config(struct sdw_slave *slave,
1057bbe7379dSSanyog Kale 			struct sdw_slave_runtime *s_rt,
1058bbe7379dSSanyog Kale 			struct sdw_port_config *port_config,
1059bbe7379dSSanyog Kale 			unsigned int num_config)
1060bbe7379dSSanyog Kale {
1061bbe7379dSSanyog Kale 	struct sdw_port_runtime *p_rt;
1062bbe7379dSSanyog Kale 	int i, ret;
1063bbe7379dSSanyog Kale 
1064bbe7379dSSanyog Kale 	/* Iterate for number of ports to perform initialization */
1065bbe7379dSSanyog Kale 	for (i = 0; i < num_config; i++) {
1066bbe7379dSSanyog Kale 		p_rt = sdw_port_alloc(&slave->dev, port_config, i);
1067bbe7379dSSanyog Kale 		if (!p_rt)
1068bbe7379dSSanyog Kale 			return -ENOMEM;
1069bbe7379dSSanyog Kale 
1070bbe7379dSSanyog Kale 		/*
1071bbe7379dSSanyog Kale 		 * TODO: Check valid port range as defined by DisCo/
1072bbe7379dSSanyog Kale 		 * slave
1073bbe7379dSSanyog Kale 		 */
1074bbe7379dSSanyog Kale 		ret = sdw_is_valid_port_range(&slave->dev, p_rt);
1075bbe7379dSSanyog Kale 		if (ret < 0) {
1076bbe7379dSSanyog Kale 			kfree(p_rt);
1077bbe7379dSSanyog Kale 			return ret;
1078bbe7379dSSanyog Kale 		}
1079bbe7379dSSanyog Kale 
1080bbe7379dSSanyog Kale 		/*
1081bbe7379dSSanyog Kale 		 * TODO: Check port capabilities for requested
1082bbe7379dSSanyog Kale 		 * configuration (audio mode support)
1083bbe7379dSSanyog Kale 		 */
1084bbe7379dSSanyog Kale 
1085bbe7379dSSanyog Kale 		list_add_tail(&p_rt->port_node, &s_rt->port_list);
1086bbe7379dSSanyog Kale 	}
1087bbe7379dSSanyog Kale 
1088bbe7379dSSanyog Kale 	return 0;
1089bbe7379dSSanyog Kale }
1090bbe7379dSSanyog Kale 
109189e59053SSanyog Kale /**
109289e59053SSanyog Kale  * sdw_stream_add_master() - Allocate and add master runtime to a stream
109389e59053SSanyog Kale  *
109489e59053SSanyog Kale  * @bus: SDW Bus instance
109589e59053SSanyog Kale  * @stream_config: Stream configuration for audio stream
1096bbe7379dSSanyog Kale  * @port_config: Port configuration for audio stream
1097bbe7379dSSanyog Kale  * @num_ports: Number of ports
109889e59053SSanyog Kale  * @stream: SoundWire stream
109989e59053SSanyog Kale  */
110089e59053SSanyog Kale int sdw_stream_add_master(struct sdw_bus *bus,
110189e59053SSanyog Kale 		struct sdw_stream_config *stream_config,
1102bbe7379dSSanyog Kale 		struct sdw_port_config *port_config,
1103bbe7379dSSanyog Kale 		unsigned int num_ports,
110489e59053SSanyog Kale 		struct sdw_stream_runtime *stream)
110589e59053SSanyog Kale {
110689e59053SSanyog Kale 	struct sdw_master_runtime *m_rt = NULL;
110789e59053SSanyog Kale 	int ret;
110889e59053SSanyog Kale 
110989e59053SSanyog Kale 	mutex_lock(&bus->bus_lock);
111089e59053SSanyog Kale 
111189e59053SSanyog Kale 	m_rt = sdw_alloc_master_rt(bus, stream_config, stream);
111289e59053SSanyog Kale 	if (!m_rt) {
111389e59053SSanyog Kale 		dev_err(bus->dev,
111489e59053SSanyog Kale 				"Master runtime config failed for stream:%s",
111589e59053SSanyog Kale 				stream->name);
111689e59053SSanyog Kale 		ret = -ENOMEM;
11173fef1a22SShreyas NC 		goto unlock;
111889e59053SSanyog Kale 	}
111989e59053SSanyog Kale 
112089e59053SSanyog Kale 	ret = sdw_config_stream(bus->dev, stream, stream_config, false);
112189e59053SSanyog Kale 	if (ret)
112289e59053SSanyog Kale 		goto stream_error;
112389e59053SSanyog Kale 
1124bbe7379dSSanyog Kale 	ret = sdw_master_port_config(bus, m_rt, port_config, num_ports);
1125bbe7379dSSanyog Kale 	if (ret)
1126bbe7379dSSanyog Kale 		goto stream_error;
1127bbe7379dSSanyog Kale 
11283fef1a22SShreyas NC 	goto unlock;
11293fef1a22SShreyas NC 
113089e59053SSanyog Kale stream_error:
113189e59053SSanyog Kale 	sdw_release_master_stream(stream);
11323fef1a22SShreyas NC unlock:
113389e59053SSanyog Kale 	mutex_unlock(&bus->bus_lock);
113489e59053SSanyog Kale 	return ret;
113589e59053SSanyog Kale }
113689e59053SSanyog Kale EXPORT_SYMBOL(sdw_stream_add_master);
113789e59053SSanyog Kale 
113889e59053SSanyog Kale /**
113989e59053SSanyog Kale  * sdw_stream_add_slave() - Allocate and add master/slave runtime to a stream
114089e59053SSanyog Kale  *
114189e59053SSanyog Kale  * @slave: SDW Slave instance
114289e59053SSanyog Kale  * @stream_config: Stream configuration for audio stream
114389e59053SSanyog Kale  * @stream: SoundWire stream
1144bbe7379dSSanyog Kale  * @port_config: Port configuration for audio stream
1145bbe7379dSSanyog Kale  * @num_ports: Number of ports
11460aebe40bSShreyas NC  *
11470aebe40bSShreyas NC  * It is expected that Slave is added before adding Master
11480aebe40bSShreyas NC  * to the Stream.
11490aebe40bSShreyas NC  *
115089e59053SSanyog Kale  */
115189e59053SSanyog Kale int sdw_stream_add_slave(struct sdw_slave *slave,
115289e59053SSanyog Kale 		struct sdw_stream_config *stream_config,
1153bbe7379dSSanyog Kale 		struct sdw_port_config *port_config,
1154bbe7379dSSanyog Kale 		unsigned int num_ports,
115589e59053SSanyog Kale 		struct sdw_stream_runtime *stream)
115689e59053SSanyog Kale {
115789e59053SSanyog Kale 	struct sdw_slave_runtime *s_rt;
115889e59053SSanyog Kale 	struct sdw_master_runtime *m_rt;
115989e59053SSanyog Kale 	int ret;
116089e59053SSanyog Kale 
116189e59053SSanyog Kale 	mutex_lock(&slave->bus->bus_lock);
116289e59053SSanyog Kale 
116389e59053SSanyog Kale 	/*
116489e59053SSanyog Kale 	 * If this API is invoked by Slave first then m_rt is not valid.
116589e59053SSanyog Kale 	 * So, allocate m_rt and add Slave to it.
116689e59053SSanyog Kale 	 */
116789e59053SSanyog Kale 	m_rt = sdw_alloc_master_rt(slave->bus, stream_config, stream);
116889e59053SSanyog Kale 	if (!m_rt) {
116989e59053SSanyog Kale 		dev_err(&slave->dev,
117089e59053SSanyog Kale 				"alloc master runtime failed for stream:%s",
117189e59053SSanyog Kale 				stream->name);
117289e59053SSanyog Kale 		ret = -ENOMEM;
117389e59053SSanyog Kale 		goto error;
117489e59053SSanyog Kale 	}
117589e59053SSanyog Kale 
117689e59053SSanyog Kale 	s_rt = sdw_alloc_slave_rt(slave, stream_config, stream);
117789e59053SSanyog Kale 	if (!s_rt) {
117889e59053SSanyog Kale 		dev_err(&slave->dev,
117989e59053SSanyog Kale 				"Slave runtime config failed for stream:%s",
118089e59053SSanyog Kale 				stream->name);
118189e59053SSanyog Kale 		ret = -ENOMEM;
118289e59053SSanyog Kale 		goto stream_error;
118389e59053SSanyog Kale 	}
118489e59053SSanyog Kale 
118589e59053SSanyog Kale 	ret = sdw_config_stream(&slave->dev, stream, stream_config, true);
118689e59053SSanyog Kale 	if (ret)
118789e59053SSanyog Kale 		goto stream_error;
118889e59053SSanyog Kale 
118989e59053SSanyog Kale 	list_add_tail(&s_rt->m_rt_node, &m_rt->slave_rt_list);
119089e59053SSanyog Kale 
1191bbe7379dSSanyog Kale 	ret = sdw_slave_port_config(slave, s_rt, port_config, num_ports);
1192bbe7379dSSanyog Kale 	if (ret)
1193bbe7379dSSanyog Kale 		goto stream_error;
1194bbe7379dSSanyog Kale 
11950aebe40bSShreyas NC 	/*
11960aebe40bSShreyas NC 	 * Change stream state to CONFIGURED on first Slave add.
11970aebe40bSShreyas NC 	 * Bus is not aware of number of Slave(s) in a stream at this
11980aebe40bSShreyas NC 	 * point so cannot depend on all Slave(s) to be added in order to
11990aebe40bSShreyas NC 	 * change stream state to CONFIGURED.
12000aebe40bSShreyas NC 	 */
120189e59053SSanyog Kale 	stream->state = SDW_STREAM_CONFIGURED;
120289e59053SSanyog Kale 	goto error;
120389e59053SSanyog Kale 
120489e59053SSanyog Kale stream_error:
120589e59053SSanyog Kale 	/*
120689e59053SSanyog Kale 	 * we hit error so cleanup the stream, release all Slave(s) and
120789e59053SSanyog Kale 	 * Master runtime
120889e59053SSanyog Kale 	 */
120989e59053SSanyog Kale 	sdw_release_master_stream(stream);
121089e59053SSanyog Kale error:
121189e59053SSanyog Kale 	mutex_unlock(&slave->bus->bus_lock);
121289e59053SSanyog Kale 	return ret;
121389e59053SSanyog Kale }
121489e59053SSanyog Kale EXPORT_SYMBOL(sdw_stream_add_slave);
1215f8101c74SSanyog Kale 
1216f8101c74SSanyog Kale /**
1217f8101c74SSanyog Kale  * sdw_get_slave_dpn_prop() - Get Slave port capabilities
1218f8101c74SSanyog Kale  *
1219f8101c74SSanyog Kale  * @slave: Slave handle
1220f8101c74SSanyog Kale  * @direction: Data direction.
1221f8101c74SSanyog Kale  * @port_num: Port number
1222f8101c74SSanyog Kale  */
1223f8101c74SSanyog Kale struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave,
1224f8101c74SSanyog Kale 				enum sdw_data_direction direction,
1225f8101c74SSanyog Kale 				unsigned int port_num)
1226f8101c74SSanyog Kale {
1227f8101c74SSanyog Kale 	struct sdw_dpn_prop *dpn_prop;
1228f8101c74SSanyog Kale 	u8 num_ports;
1229f8101c74SSanyog Kale 	int i;
1230f8101c74SSanyog Kale 
1231f8101c74SSanyog Kale 	if (direction == SDW_DATA_DIR_TX) {
1232f8101c74SSanyog Kale 		num_ports = hweight32(slave->prop.source_ports);
1233f8101c74SSanyog Kale 		dpn_prop = slave->prop.src_dpn_prop;
1234f8101c74SSanyog Kale 	} else {
1235f8101c74SSanyog Kale 		num_ports = hweight32(slave->prop.sink_ports);
1236f8101c74SSanyog Kale 		dpn_prop = slave->prop.sink_dpn_prop;
1237f8101c74SSanyog Kale 	}
1238f8101c74SSanyog Kale 
1239f8101c74SSanyog Kale 	for (i = 0; i < num_ports; i++) {
1240f8101c74SSanyog Kale 		dpn_prop = &dpn_prop[i];
1241f8101c74SSanyog Kale 
1242f8101c74SSanyog Kale 		if (dpn_prop->num == port_num)
1243f8101c74SSanyog Kale 			return &dpn_prop[i];
1244f8101c74SSanyog Kale 	}
1245f8101c74SSanyog Kale 
1246f8101c74SSanyog Kale 	return NULL;
1247f8101c74SSanyog Kale }
12485c3eb9f7SSanyog Kale 
12490c4a1049SSanyog Kale /**
12500c4a1049SSanyog Kale  * sdw_acquire_bus_lock: Acquire bus lock for all Master runtime(s)
12510c4a1049SSanyog Kale  *
12520c4a1049SSanyog Kale  * @stream: SoundWire stream
12530c4a1049SSanyog Kale  *
12540c4a1049SSanyog Kale  * Acquire bus_lock for each of the master runtime(m_rt) part of this
12550c4a1049SSanyog Kale  * stream to reconfigure the bus.
12560c4a1049SSanyog Kale  * NOTE: This function is called from SoundWire stream ops and is
12570c4a1049SSanyog Kale  * expected that a global lock is held before acquiring bus_lock.
12580c4a1049SSanyog Kale  */
12590c4a1049SSanyog Kale static void sdw_acquire_bus_lock(struct sdw_stream_runtime *stream)
12600c4a1049SSanyog Kale {
12610c4a1049SSanyog Kale 	struct sdw_master_runtime *m_rt = NULL;
12620c4a1049SSanyog Kale 	struct sdw_bus *bus = NULL;
12630c4a1049SSanyog Kale 
12640c4a1049SSanyog Kale 	/* Iterate for all Master(s) in Master list */
12650c4a1049SSanyog Kale 	list_for_each_entry(m_rt, &stream->master_list, stream_node) {
12660c4a1049SSanyog Kale 		bus = m_rt->bus;
12670c4a1049SSanyog Kale 
12680c4a1049SSanyog Kale 		mutex_lock(&bus->bus_lock);
12690c4a1049SSanyog Kale 	}
12700c4a1049SSanyog Kale }
12710c4a1049SSanyog Kale 
12720c4a1049SSanyog Kale /**
12730c4a1049SSanyog Kale  * sdw_release_bus_lock: Release bus lock for all Master runtime(s)
12740c4a1049SSanyog Kale  *
12750c4a1049SSanyog Kale  * @stream: SoundWire stream
12760c4a1049SSanyog Kale  *
12770c4a1049SSanyog Kale  * Release the previously held bus_lock after reconfiguring the bus.
12780c4a1049SSanyog Kale  */
12790c4a1049SSanyog Kale static void sdw_release_bus_lock(struct sdw_stream_runtime *stream)
12800c4a1049SSanyog Kale {
12810c4a1049SSanyog Kale 	struct sdw_master_runtime *m_rt = NULL;
12820c4a1049SSanyog Kale 	struct sdw_bus *bus = NULL;
12830c4a1049SSanyog Kale 
12840c4a1049SSanyog Kale 	/* Iterate for all Master(s) in Master list */
12850c4a1049SSanyog Kale 	list_for_each_entry_reverse(m_rt, &stream->master_list, stream_node) {
12860c4a1049SSanyog Kale 		bus = m_rt->bus;
12870c4a1049SSanyog Kale 		mutex_unlock(&bus->bus_lock);
12880c4a1049SSanyog Kale 	}
12890c4a1049SSanyog Kale }
12900c4a1049SSanyog Kale 
12915c3eb9f7SSanyog Kale static int _sdw_prepare_stream(struct sdw_stream_runtime *stream)
12925c3eb9f7SSanyog Kale {
12935c3eb9f7SSanyog Kale 	struct sdw_master_runtime *m_rt = stream->m_rt;
12945c3eb9f7SSanyog Kale 	struct sdw_bus *bus = m_rt->bus;
12955c3eb9f7SSanyog Kale 	struct sdw_master_prop *prop = NULL;
12965c3eb9f7SSanyog Kale 	struct sdw_bus_params params;
12975c3eb9f7SSanyog Kale 	int ret;
12985c3eb9f7SSanyog Kale 
12995c3eb9f7SSanyog Kale 	prop = &bus->prop;
13005c3eb9f7SSanyog Kale 	memcpy(&params, &bus->params, sizeof(params));
13015c3eb9f7SSanyog Kale 
13025c3eb9f7SSanyog Kale 	/* TODO: Support Asynchronous mode */
13035c3eb9f7SSanyog Kale 	if ((prop->max_freq % stream->params.rate) != 0) {
13045c3eb9f7SSanyog Kale 		dev_err(bus->dev, "Async mode not supported");
13055c3eb9f7SSanyog Kale 		return -EINVAL;
13065c3eb9f7SSanyog Kale 	}
13075c3eb9f7SSanyog Kale 
13085c3eb9f7SSanyog Kale 	/* Increment cumulative bus bandwidth */
13095c3eb9f7SSanyog Kale 	/* TODO: Update this during Device-Device support */
13105c3eb9f7SSanyog Kale 	bus->params.bandwidth += m_rt->stream->params.rate *
13115c3eb9f7SSanyog Kale 		m_rt->ch_count * m_rt->stream->params.bps;
13125c3eb9f7SSanyog Kale 
13135c3eb9f7SSanyog Kale 	/* Program params */
13145c3eb9f7SSanyog Kale 	ret = sdw_program_params(bus);
13155c3eb9f7SSanyog Kale 	if (ret < 0) {
13165c3eb9f7SSanyog Kale 		dev_err(bus->dev, "Program params failed: %d", ret);
13175c3eb9f7SSanyog Kale 		goto restore_params;
13185c3eb9f7SSanyog Kale 	}
13195c3eb9f7SSanyog Kale 
13205c3eb9f7SSanyog Kale 	ret = do_bank_switch(stream);
13215c3eb9f7SSanyog Kale 	if (ret < 0) {
13225c3eb9f7SSanyog Kale 		dev_err(bus->dev, "Bank switch failed: %d", ret);
13235c3eb9f7SSanyog Kale 		goto restore_params;
13245c3eb9f7SSanyog Kale 	}
13255c3eb9f7SSanyog Kale 
13265c3eb9f7SSanyog Kale 	/* Prepare port(s) on the new clock configuration */
13275c3eb9f7SSanyog Kale 	ret = sdw_prep_deprep_ports(m_rt, true);
13285c3eb9f7SSanyog Kale 	if (ret < 0) {
13295c3eb9f7SSanyog Kale 		dev_err(bus->dev, "Prepare port(s) failed ret = %d",
13305c3eb9f7SSanyog Kale 				ret);
13315c3eb9f7SSanyog Kale 		return ret;
13325c3eb9f7SSanyog Kale 	}
13335c3eb9f7SSanyog Kale 
13345c3eb9f7SSanyog Kale 	stream->state = SDW_STREAM_PREPARED;
13355c3eb9f7SSanyog Kale 
13365c3eb9f7SSanyog Kale 	return ret;
13375c3eb9f7SSanyog Kale 
13385c3eb9f7SSanyog Kale restore_params:
13395c3eb9f7SSanyog Kale 	memcpy(&bus->params, &params, sizeof(params));
13405c3eb9f7SSanyog Kale 	return ret;
13415c3eb9f7SSanyog Kale }
13425c3eb9f7SSanyog Kale 
13435c3eb9f7SSanyog Kale /**
13445c3eb9f7SSanyog Kale  * sdw_prepare_stream() - Prepare SoundWire stream
13455c3eb9f7SSanyog Kale  *
13465c3eb9f7SSanyog Kale  * @stream: Soundwire stream
13475c3eb9f7SSanyog Kale  *
134834962fb8SMauro Carvalho Chehab  * Documentation/driver-api/soundwire/stream.rst explains this API in detail
13495c3eb9f7SSanyog Kale  */
13505c3eb9f7SSanyog Kale int sdw_prepare_stream(struct sdw_stream_runtime *stream)
13515c3eb9f7SSanyog Kale {
13525c3eb9f7SSanyog Kale 	int ret = 0;
13535c3eb9f7SSanyog Kale 
13545c3eb9f7SSanyog Kale 	if (!stream) {
13555c3eb9f7SSanyog Kale 		pr_err("SoundWire: Handle not found for stream");
13565c3eb9f7SSanyog Kale 		return -EINVAL;
13575c3eb9f7SSanyog Kale 	}
13585c3eb9f7SSanyog Kale 
13595c3eb9f7SSanyog Kale 	mutex_lock(&stream->m_rt->bus->bus_lock);
13605c3eb9f7SSanyog Kale 
13615c3eb9f7SSanyog Kale 	ret = _sdw_prepare_stream(stream);
13625c3eb9f7SSanyog Kale 	if (ret < 0)
13635c3eb9f7SSanyog Kale 		pr_err("Prepare for stream:%s failed: %d", stream->name, ret);
13645c3eb9f7SSanyog Kale 
13655c3eb9f7SSanyog Kale 	mutex_unlock(&stream->m_rt->bus->bus_lock);
13665c3eb9f7SSanyog Kale 	return ret;
13675c3eb9f7SSanyog Kale }
13685c3eb9f7SSanyog Kale EXPORT_SYMBOL(sdw_prepare_stream);
13695c3eb9f7SSanyog Kale 
13705c3eb9f7SSanyog Kale static int _sdw_enable_stream(struct sdw_stream_runtime *stream)
13715c3eb9f7SSanyog Kale {
13725c3eb9f7SSanyog Kale 	struct sdw_master_runtime *m_rt = stream->m_rt;
13735c3eb9f7SSanyog Kale 	struct sdw_bus *bus = m_rt->bus;
13745c3eb9f7SSanyog Kale 	int ret;
13755c3eb9f7SSanyog Kale 
13765c3eb9f7SSanyog Kale 	/* Program params */
13775c3eb9f7SSanyog Kale 	ret = sdw_program_params(bus);
13785c3eb9f7SSanyog Kale 	if (ret < 0) {
13795c3eb9f7SSanyog Kale 		dev_err(bus->dev, "Program params failed: %d", ret);
13805c3eb9f7SSanyog Kale 		return ret;
13815c3eb9f7SSanyog Kale 	}
13825c3eb9f7SSanyog Kale 
13835c3eb9f7SSanyog Kale 	/* Enable port(s) */
13845c3eb9f7SSanyog Kale 	ret = sdw_enable_disable_ports(m_rt, true);
13855c3eb9f7SSanyog Kale 	if (ret < 0) {
13865c3eb9f7SSanyog Kale 		dev_err(bus->dev, "Enable port(s) failed ret: %d", ret);
13875c3eb9f7SSanyog Kale 		return ret;
13885c3eb9f7SSanyog Kale 	}
13895c3eb9f7SSanyog Kale 
13905c3eb9f7SSanyog Kale 	ret = do_bank_switch(stream);
13915c3eb9f7SSanyog Kale 	if (ret < 0) {
13925c3eb9f7SSanyog Kale 		dev_err(bus->dev, "Bank switch failed: %d", ret);
13935c3eb9f7SSanyog Kale 		return ret;
13945c3eb9f7SSanyog Kale 	}
13955c3eb9f7SSanyog Kale 
13965c3eb9f7SSanyog Kale 	stream->state = SDW_STREAM_ENABLED;
13975c3eb9f7SSanyog Kale 	return 0;
13985c3eb9f7SSanyog Kale }
13995c3eb9f7SSanyog Kale 
14005c3eb9f7SSanyog Kale /**
14015c3eb9f7SSanyog Kale  * sdw_enable_stream() - Enable SoundWire stream
14025c3eb9f7SSanyog Kale  *
14035c3eb9f7SSanyog Kale  * @stream: Soundwire stream
14045c3eb9f7SSanyog Kale  *
140534962fb8SMauro Carvalho Chehab  * Documentation/driver-api/soundwire/stream.rst explains this API in detail
14065c3eb9f7SSanyog Kale  */
14075c3eb9f7SSanyog Kale int sdw_enable_stream(struct sdw_stream_runtime *stream)
14085c3eb9f7SSanyog Kale {
14095c3eb9f7SSanyog Kale 	int ret = 0;
14105c3eb9f7SSanyog Kale 
14115c3eb9f7SSanyog Kale 	if (!stream) {
14125c3eb9f7SSanyog Kale 		pr_err("SoundWire: Handle not found for stream");
14135c3eb9f7SSanyog Kale 		return -EINVAL;
14145c3eb9f7SSanyog Kale 	}
14155c3eb9f7SSanyog Kale 
14165c3eb9f7SSanyog Kale 	mutex_lock(&stream->m_rt->bus->bus_lock);
14175c3eb9f7SSanyog Kale 
14185c3eb9f7SSanyog Kale 	ret = _sdw_enable_stream(stream);
14195c3eb9f7SSanyog Kale 	if (ret < 0)
14205c3eb9f7SSanyog Kale 		pr_err("Enable for stream:%s failed: %d", stream->name, ret);
14215c3eb9f7SSanyog Kale 
14225c3eb9f7SSanyog Kale 	mutex_unlock(&stream->m_rt->bus->bus_lock);
14235c3eb9f7SSanyog Kale 	return ret;
14245c3eb9f7SSanyog Kale }
14255c3eb9f7SSanyog Kale EXPORT_SYMBOL(sdw_enable_stream);
14265c3eb9f7SSanyog Kale 
14275c3eb9f7SSanyog Kale static int _sdw_disable_stream(struct sdw_stream_runtime *stream)
14285c3eb9f7SSanyog Kale {
14295c3eb9f7SSanyog Kale 	struct sdw_master_runtime *m_rt = stream->m_rt;
14305c3eb9f7SSanyog Kale 	struct sdw_bus *bus = m_rt->bus;
14315c3eb9f7SSanyog Kale 	int ret;
14325c3eb9f7SSanyog Kale 
14335c3eb9f7SSanyog Kale 	/* Disable port(s) */
14345c3eb9f7SSanyog Kale 	ret = sdw_enable_disable_ports(m_rt, false);
14355c3eb9f7SSanyog Kale 	if (ret < 0) {
14365c3eb9f7SSanyog Kale 		dev_err(bus->dev, "Disable port(s) failed: %d", ret);
14375c3eb9f7SSanyog Kale 		return ret;
14385c3eb9f7SSanyog Kale 	}
14395c3eb9f7SSanyog Kale 
14405c3eb9f7SSanyog Kale 	stream->state = SDW_STREAM_DISABLED;
14415c3eb9f7SSanyog Kale 
14425c3eb9f7SSanyog Kale 	/* Program params */
14435c3eb9f7SSanyog Kale 	ret = sdw_program_params(bus);
14445c3eb9f7SSanyog Kale 	if (ret < 0) {
14455c3eb9f7SSanyog Kale 		dev_err(bus->dev, "Program params failed: %d", ret);
14465c3eb9f7SSanyog Kale 		return ret;
14475c3eb9f7SSanyog Kale 	}
14485c3eb9f7SSanyog Kale 
14495c3eb9f7SSanyog Kale 	return do_bank_switch(stream);
14505c3eb9f7SSanyog Kale }
14515c3eb9f7SSanyog Kale 
14525c3eb9f7SSanyog Kale /**
14535c3eb9f7SSanyog Kale  * sdw_disable_stream() - Disable SoundWire stream
14545c3eb9f7SSanyog Kale  *
14555c3eb9f7SSanyog Kale  * @stream: Soundwire stream
14565c3eb9f7SSanyog Kale  *
145734962fb8SMauro Carvalho Chehab  * Documentation/driver-api/soundwire/stream.rst explains this API in detail
14585c3eb9f7SSanyog Kale  */
14595c3eb9f7SSanyog Kale int sdw_disable_stream(struct sdw_stream_runtime *stream)
14605c3eb9f7SSanyog Kale {
14615c3eb9f7SSanyog Kale 	int ret = 0;
14625c3eb9f7SSanyog Kale 
14635c3eb9f7SSanyog Kale 	if (!stream) {
14645c3eb9f7SSanyog Kale 		pr_err("SoundWire: Handle not found for stream");
14655c3eb9f7SSanyog Kale 		return -EINVAL;
14665c3eb9f7SSanyog Kale 	}
14675c3eb9f7SSanyog Kale 
14685c3eb9f7SSanyog Kale 	mutex_lock(&stream->m_rt->bus->bus_lock);
14695c3eb9f7SSanyog Kale 
14705c3eb9f7SSanyog Kale 	ret = _sdw_disable_stream(stream);
14715c3eb9f7SSanyog Kale 	if (ret < 0)
14725c3eb9f7SSanyog Kale 		pr_err("Disable for stream:%s failed: %d", stream->name, ret);
14735c3eb9f7SSanyog Kale 
14745c3eb9f7SSanyog Kale 	mutex_unlock(&stream->m_rt->bus->bus_lock);
14755c3eb9f7SSanyog Kale 	return ret;
14765c3eb9f7SSanyog Kale }
14775c3eb9f7SSanyog Kale EXPORT_SYMBOL(sdw_disable_stream);
14785c3eb9f7SSanyog Kale 
14795c3eb9f7SSanyog Kale static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
14805c3eb9f7SSanyog Kale {
14815c3eb9f7SSanyog Kale 	struct sdw_master_runtime *m_rt = stream->m_rt;
14825c3eb9f7SSanyog Kale 	struct sdw_bus *bus = m_rt->bus;
14835c3eb9f7SSanyog Kale 	int ret = 0;
14845c3eb9f7SSanyog Kale 
14855c3eb9f7SSanyog Kale 	/* De-prepare port(s) */
14865c3eb9f7SSanyog Kale 	ret = sdw_prep_deprep_ports(m_rt, false);
14875c3eb9f7SSanyog Kale 	if (ret < 0) {
14885c3eb9f7SSanyog Kale 		dev_err(bus->dev, "De-prepare port(s) failed: %d", ret);
14895c3eb9f7SSanyog Kale 		return ret;
14905c3eb9f7SSanyog Kale 	}
14915c3eb9f7SSanyog Kale 
14925c3eb9f7SSanyog Kale 	stream->state = SDW_STREAM_DEPREPARED;
14935c3eb9f7SSanyog Kale 
14945c3eb9f7SSanyog Kale 	/* TODO: Update this during Device-Device support */
14955c3eb9f7SSanyog Kale 	bus->params.bandwidth -= m_rt->stream->params.rate *
14965c3eb9f7SSanyog Kale 		m_rt->ch_count * m_rt->stream->params.bps;
14975c3eb9f7SSanyog Kale 
14985c3eb9f7SSanyog Kale 	/* Program params */
14995c3eb9f7SSanyog Kale 	ret = sdw_program_params(bus);
15005c3eb9f7SSanyog Kale 	if (ret < 0) {
15015c3eb9f7SSanyog Kale 		dev_err(bus->dev, "Program params failed: %d", ret);
15025c3eb9f7SSanyog Kale 		return ret;
15035c3eb9f7SSanyog Kale 	}
15045c3eb9f7SSanyog Kale 
15055c3eb9f7SSanyog Kale 	return do_bank_switch(stream);
15065c3eb9f7SSanyog Kale }
15075c3eb9f7SSanyog Kale 
15085c3eb9f7SSanyog Kale /**
15095c3eb9f7SSanyog Kale  * sdw_deprepare_stream() - Deprepare SoundWire stream
15105c3eb9f7SSanyog Kale  *
15115c3eb9f7SSanyog Kale  * @stream: Soundwire stream
15125c3eb9f7SSanyog Kale  *
151334962fb8SMauro Carvalho Chehab  * Documentation/driver-api/soundwire/stream.rst explains this API in detail
15145c3eb9f7SSanyog Kale  */
15155c3eb9f7SSanyog Kale int sdw_deprepare_stream(struct sdw_stream_runtime *stream)
15165c3eb9f7SSanyog Kale {
15175c3eb9f7SSanyog Kale 	int ret = 0;
15185c3eb9f7SSanyog Kale 
15195c3eb9f7SSanyog Kale 	if (!stream) {
15205c3eb9f7SSanyog Kale 		pr_err("SoundWire: Handle not found for stream");
15215c3eb9f7SSanyog Kale 		return -EINVAL;
15225c3eb9f7SSanyog Kale 	}
15235c3eb9f7SSanyog Kale 
15245c3eb9f7SSanyog Kale 	mutex_lock(&stream->m_rt->bus->bus_lock);
15255c3eb9f7SSanyog Kale 
15265c3eb9f7SSanyog Kale 	ret = _sdw_deprepare_stream(stream);
15275c3eb9f7SSanyog Kale 	if (ret < 0)
15285c3eb9f7SSanyog Kale 		pr_err("De-prepare for stream:%d failed: %d", ret, ret);
15295c3eb9f7SSanyog Kale 
15305c3eb9f7SSanyog Kale 	mutex_unlock(&stream->m_rt->bus->bus_lock);
15315c3eb9f7SSanyog Kale 	return ret;
15325c3eb9f7SSanyog Kale }
15335c3eb9f7SSanyog Kale EXPORT_SYMBOL(sdw_deprepare_stream);
1534