diff options
Diffstat (limited to 'drivers/soundwire/stream.c')
-rw-r--r-- | drivers/soundwire/stream.c | 1479 |
1 files changed, 1479 insertions, 0 deletions
diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c new file mode 100644 index 000000000000..8974a0fcda1b --- /dev/null +++ b/drivers/soundwire/stream.c | |||
@@ -0,0 +1,1479 @@ | |||
1 | // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) | ||
2 | // Copyright(c) 2015-18 Intel Corporation. | ||
3 | |||
4 | /* | ||
5 | * stream.c - SoundWire Bus stream operations. | ||
6 | */ | ||
7 | |||
8 | #include <linux/delay.h> | ||
9 | #include <linux/device.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/mod_devicetable.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/soundwire/sdw_registers.h> | ||
15 | #include <linux/soundwire/sdw.h> | ||
16 | #include "bus.h" | ||
17 | |||
18 | /* | ||
19 | * Array of supported rows and columns as per MIPI SoundWire Specification 1.1 | ||
20 | * | ||
21 | * The rows are arranged as per the array index value programmed | ||
22 | * in register. The index 15 has dummy value 0 in order to fill hole. | ||
23 | */ | ||
24 | int rows[SDW_FRAME_ROWS] = {48, 50, 60, 64, 75, 80, 125, 147, | ||
25 | 96, 100, 120, 128, 150, 160, 250, 0, | ||
26 | 192, 200, 240, 256, 72, 144, 90, 180}; | ||
27 | |||
28 | int cols[SDW_FRAME_COLS] = {2, 4, 6, 8, 10, 12, 14, 16}; | ||
29 | |||
30 | static int sdw_find_col_index(int col) | ||
31 | { | ||
32 | int i; | ||
33 | |||
34 | for (i = 0; i < SDW_FRAME_COLS; i++) { | ||
35 | if (cols[i] == col) | ||
36 | return i; | ||
37 | } | ||
38 | |||
39 | pr_warn("Requested column not found, selecting lowest column no: 2\n"); | ||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | static int sdw_find_row_index(int row) | ||
44 | { | ||
45 | int i; | ||
46 | |||
47 | for (i = 0; i < SDW_FRAME_ROWS; i++) { | ||
48 | if (rows[i] == row) | ||
49 | return i; | ||
50 | } | ||
51 | |||
52 | pr_warn("Requested row not found, selecting lowest row no: 48\n"); | ||
53 | return 0; | ||
54 | } | ||
55 | static int _sdw_program_slave_port_params(struct sdw_bus *bus, | ||
56 | struct sdw_slave *slave, | ||
57 | struct sdw_transport_params *t_params, | ||
58 | enum sdw_dpn_type type) | ||
59 | { | ||
60 | u32 addr1, addr2, addr3, addr4; | ||
61 | int ret; | ||
62 | u16 wbuf; | ||
63 | |||
64 | if (bus->params.next_bank) { | ||
65 | addr1 = SDW_DPN_OFFSETCTRL2_B1(t_params->port_num); | ||
66 | addr2 = SDW_DPN_BLOCKCTRL3_B1(t_params->port_num); | ||
67 | addr3 = SDW_DPN_SAMPLECTRL2_B1(t_params->port_num); | ||
68 | addr4 = SDW_DPN_HCTRL_B1(t_params->port_num); | ||
69 | } else { | ||
70 | addr1 = SDW_DPN_OFFSETCTRL2_B0(t_params->port_num); | ||
71 | addr2 = SDW_DPN_BLOCKCTRL3_B0(t_params->port_num); | ||
72 | addr3 = SDW_DPN_SAMPLECTRL2_B0(t_params->port_num); | ||
73 | addr4 = SDW_DPN_HCTRL_B0(t_params->port_num); | ||
74 | } | ||
75 | |||
76 | /* Program DPN_OffsetCtrl2 registers */ | ||
77 | ret = sdw_write(slave, addr1, t_params->offset2); | ||
78 | if (ret < 0) { | ||
79 | dev_err(bus->dev, "DPN_OffsetCtrl2 register write failed"); | ||
80 | return ret; | ||
81 | } | ||
82 | |||
83 | /* Program DPN_BlockCtrl3 register */ | ||
84 | ret = sdw_write(slave, addr2, t_params->blk_pkg_mode); | ||
85 | if (ret < 0) { | ||
86 | dev_err(bus->dev, "DPN_BlockCtrl3 register write failed"); | ||
87 | return ret; | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * Data ports are FULL, SIMPLE and REDUCED. This function handles | ||
92 | * FULL and REDUCED only and and beyond this point only FULL is | ||
93 | * handled, so bail out if we are not FULL data port type | ||
94 | */ | ||
95 | if (type != SDW_DPN_FULL) | ||
96 | return ret; | ||
97 | |||
98 | /* Program DPN_SampleCtrl2 register */ | ||
99 | wbuf = (t_params->sample_interval - 1); | ||
100 | wbuf &= SDW_DPN_SAMPLECTRL_HIGH; | ||
101 | wbuf >>= SDW_REG_SHIFT(SDW_DPN_SAMPLECTRL_HIGH); | ||
102 | |||
103 | ret = sdw_write(slave, addr3, wbuf); | ||
104 | if (ret < 0) { | ||
105 | dev_err(bus->dev, "DPN_SampleCtrl2 register write failed"); | ||
106 | return ret; | ||
107 | } | ||
108 | |||
109 | /* Program DPN_HCtrl register */ | ||
110 | wbuf = t_params->hstart; | ||
111 | wbuf <<= SDW_REG_SHIFT(SDW_DPN_HCTRL_HSTART); | ||
112 | wbuf |= t_params->hstop; | ||
113 | |||
114 | ret = sdw_write(slave, addr4, wbuf); | ||
115 | if (ret < 0) | ||
116 | dev_err(bus->dev, "DPN_HCtrl register write failed"); | ||
117 | |||
118 | return ret; | ||
119 | } | ||
120 | |||
121 | static int sdw_program_slave_port_params(struct sdw_bus *bus, | ||
122 | struct sdw_slave_runtime *s_rt, | ||
123 | struct sdw_port_runtime *p_rt) | ||
124 | { | ||
125 | struct sdw_transport_params *t_params = &p_rt->transport_params; | ||
126 | struct sdw_port_params *p_params = &p_rt->port_params; | ||
127 | struct sdw_slave_prop *slave_prop = &s_rt->slave->prop; | ||
128 | u32 addr1, addr2, addr3, addr4, addr5, addr6; | ||
129 | struct sdw_dpn_prop *dpn_prop; | ||
130 | int ret; | ||
131 | u8 wbuf; | ||
132 | |||
133 | dpn_prop = sdw_get_slave_dpn_prop(s_rt->slave, | ||
134 | s_rt->direction, | ||
135 | t_params->port_num); | ||
136 | if (!dpn_prop) | ||
137 | return -EINVAL; | ||
138 | |||
139 | addr1 = SDW_DPN_PORTCTRL(t_params->port_num); | ||
140 | addr2 = SDW_DPN_BLOCKCTRL1(t_params->port_num); | ||
141 | |||
142 | if (bus->params.next_bank) { | ||
143 | addr3 = SDW_DPN_SAMPLECTRL1_B1(t_params->port_num); | ||
144 | addr4 = SDW_DPN_OFFSETCTRL1_B1(t_params->port_num); | ||
145 | addr5 = SDW_DPN_BLOCKCTRL2_B1(t_params->port_num); | ||
146 | addr6 = SDW_DPN_LANECTRL_B1(t_params->port_num); | ||
147 | |||
148 | } else { | ||
149 | addr3 = SDW_DPN_SAMPLECTRL1_B0(t_params->port_num); | ||
150 | addr4 = SDW_DPN_OFFSETCTRL1_B0(t_params->port_num); | ||
151 | addr5 = SDW_DPN_BLOCKCTRL2_B0(t_params->port_num); | ||
152 | addr6 = SDW_DPN_LANECTRL_B0(t_params->port_num); | ||
153 | } | ||
154 | |||
155 | /* Program DPN_PortCtrl register */ | ||
156 | wbuf = p_params->data_mode << SDW_REG_SHIFT(SDW_DPN_PORTCTRL_DATAMODE); | ||
157 | wbuf |= p_params->flow_mode; | ||
158 | |||
159 | ret = sdw_update(s_rt->slave, addr1, 0xF, wbuf); | ||
160 | if (ret < 0) { | ||
161 | dev_err(&s_rt->slave->dev, | ||
162 | "DPN_PortCtrl register write failed for port %d", | ||
163 | t_params->port_num); | ||
164 | return ret; | ||
165 | } | ||
166 | |||
167 | /* Program DPN_BlockCtrl1 register */ | ||
168 | ret = sdw_write(s_rt->slave, addr2, (p_params->bps - 1)); | ||
169 | if (ret < 0) { | ||
170 | dev_err(&s_rt->slave->dev, | ||
171 | "DPN_BlockCtrl1 register write failed for port %d", | ||
172 | t_params->port_num); | ||
173 | return ret; | ||
174 | } | ||
175 | |||
176 | /* Program DPN_SampleCtrl1 register */ | ||
177 | wbuf = (t_params->sample_interval - 1) & SDW_DPN_SAMPLECTRL_LOW; | ||
178 | ret = sdw_write(s_rt->slave, addr3, wbuf); | ||
179 | if (ret < 0) { | ||
180 | dev_err(&s_rt->slave->dev, | ||
181 | "DPN_SampleCtrl1 register write failed for port %d", | ||
182 | t_params->port_num); | ||
183 | return ret; | ||
184 | } | ||
185 | |||
186 | /* Program DPN_OffsetCtrl1 registers */ | ||
187 | ret = sdw_write(s_rt->slave, addr4, t_params->offset1); | ||
188 | if (ret < 0) { | ||
189 | dev_err(&s_rt->slave->dev, | ||
190 | "DPN_OffsetCtrl1 register write failed for port %d", | ||
191 | t_params->port_num); | ||
192 | return ret; | ||
193 | } | ||
194 | |||
195 | /* Program DPN_BlockCtrl2 register*/ | ||
196 | if (t_params->blk_grp_ctrl_valid) { | ||
197 | ret = sdw_write(s_rt->slave, addr5, t_params->blk_grp_ctrl); | ||
198 | if (ret < 0) { | ||
199 | dev_err(&s_rt->slave->dev, | ||
200 | "DPN_BlockCtrl2 reg write failed for port %d", | ||
201 | t_params->port_num); | ||
202 | return ret; | ||
203 | } | ||
204 | } | ||
205 | |||
206 | /* program DPN_LaneCtrl register */ | ||
207 | if (slave_prop->lane_control_support) { | ||
208 | ret = sdw_write(s_rt->slave, addr6, t_params->lane_ctrl); | ||
209 | if (ret < 0) { | ||
210 | dev_err(&s_rt->slave->dev, | ||
211 | "DPN_LaneCtrl register write failed for port %d", | ||
212 | t_params->port_num); | ||
213 | return ret; | ||
214 | } | ||
215 | } | ||
216 | |||
217 | if (dpn_prop->type != SDW_DPN_SIMPLE) { | ||
218 | ret = _sdw_program_slave_port_params(bus, s_rt->slave, | ||
219 | t_params, dpn_prop->type); | ||
220 | if (ret < 0) | ||
221 | dev_err(&s_rt->slave->dev, | ||
222 | "Transport reg write failed for port: %d", | ||
223 | t_params->port_num); | ||
224 | } | ||
225 | |||
226 | return ret; | ||
227 | } | ||
228 | |||
229 | static int sdw_program_master_port_params(struct sdw_bus *bus, | ||
230 | struct sdw_port_runtime *p_rt) | ||
231 | { | ||
232 | int ret; | ||
233 | |||
234 | /* | ||
235 | * we need to set transport and port parameters for the port. | ||
236 | * Transport parameters refers to the smaple interval, offsets and | ||
237 | * hstart/stop etc of the data. Port parameters refers to word | ||
238 | * length, flow mode etc of the port | ||
239 | */ | ||
240 | ret = bus->port_ops->dpn_set_port_transport_params(bus, | ||
241 | &p_rt->transport_params, | ||
242 | bus->params.next_bank); | ||
243 | if (ret < 0) | ||
244 | return ret; | ||
245 | |||
246 | return bus->port_ops->dpn_set_port_params(bus, | ||
247 | &p_rt->port_params, | ||
248 | bus->params.next_bank); | ||
249 | } | ||
250 | |||
251 | /** | ||
252 | * sdw_program_port_params() - Programs transport parameters of Master(s) | ||
253 | * and Slave(s) | ||
254 | * | ||
255 | * @m_rt: Master stream runtime | ||
256 | */ | ||
257 | static int sdw_program_port_params(struct sdw_master_runtime *m_rt) | ||
258 | { | ||
259 | struct sdw_slave_runtime *s_rt = NULL; | ||
260 | struct sdw_bus *bus = m_rt->bus; | ||
261 | struct sdw_port_runtime *p_rt; | ||
262 | int ret = 0; | ||
263 | |||
264 | /* Program transport & port parameters for Slave(s) */ | ||
265 | list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { | ||
266 | list_for_each_entry(p_rt, &s_rt->port_list, port_node) { | ||
267 | ret = sdw_program_slave_port_params(bus, s_rt, p_rt); | ||
268 | if (ret < 0) | ||
269 | return ret; | ||
270 | } | ||
271 | } | ||
272 | |||
273 | /* Program transport & port parameters for Master(s) */ | ||
274 | list_for_each_entry(p_rt, &m_rt->port_list, port_node) { | ||
275 | ret = sdw_program_master_port_params(bus, p_rt); | ||
276 | if (ret < 0) | ||
277 | return ret; | ||
278 | } | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | /** | ||
284 | * sdw_enable_disable_slave_ports: Enable/disable slave data port | ||
285 | * | ||
286 | * @bus: bus instance | ||
287 | * @s_rt: slave runtime | ||
288 | * @p_rt: port runtime | ||
289 | * @en: enable or disable operation | ||
290 | * | ||
291 | * This function only sets the enable/disable bits in the relevant bank, the | ||
292 | * actual enable/disable is done with a bank switch | ||
293 | */ | ||
294 | static int sdw_enable_disable_slave_ports(struct sdw_bus *bus, | ||
295 | struct sdw_slave_runtime *s_rt, | ||
296 | struct sdw_port_runtime *p_rt, bool en) | ||
297 | { | ||
298 | struct sdw_transport_params *t_params = &p_rt->transport_params; | ||
299 | u32 addr; | ||
300 | int ret; | ||
301 | |||
302 | if (bus->params.next_bank) | ||
303 | addr = SDW_DPN_CHANNELEN_B1(p_rt->num); | ||
304 | else | ||
305 | addr = SDW_DPN_CHANNELEN_B0(p_rt->num); | ||
306 | |||
307 | /* | ||
308 | * Since bus doesn't support sharing a port across two streams, | ||
309 | * it is safe to reset this register | ||
310 | */ | ||
311 | if (en) | ||
312 | ret = sdw_update(s_rt->slave, addr, 0xFF, p_rt->ch_mask); | ||
313 | else | ||
314 | ret = sdw_update(s_rt->slave, addr, 0xFF, 0x0); | ||
315 | |||
316 | if (ret < 0) | ||
317 | dev_err(&s_rt->slave->dev, | ||
318 | "Slave chn_en reg write failed:%d port:%d", | ||
319 | ret, t_params->port_num); | ||
320 | |||
321 | return ret; | ||
322 | } | ||
323 | |||
324 | static int sdw_enable_disable_master_ports(struct sdw_master_runtime *m_rt, | ||
325 | struct sdw_port_runtime *p_rt, bool en) | ||
326 | { | ||
327 | struct sdw_transport_params *t_params = &p_rt->transport_params; | ||
328 | struct sdw_bus *bus = m_rt->bus; | ||
329 | struct sdw_enable_ch enable_ch; | ||
330 | int ret = 0; | ||
331 | |||
332 | enable_ch.port_num = p_rt->num; | ||
333 | enable_ch.ch_mask = p_rt->ch_mask; | ||
334 | enable_ch.enable = en; | ||
335 | |||
336 | /* Perform Master port channel(s) enable/disable */ | ||
337 | if (bus->port_ops->dpn_port_enable_ch) { | ||
338 | ret = bus->port_ops->dpn_port_enable_ch(bus, | ||
339 | &enable_ch, bus->params.next_bank); | ||
340 | if (ret < 0) { | ||
341 | dev_err(bus->dev, | ||
342 | "Master chn_en write failed:%d port:%d", | ||
343 | ret, t_params->port_num); | ||
344 | return ret; | ||
345 | } | ||
346 | } else { | ||
347 | dev_err(bus->dev, | ||
348 | "dpn_port_enable_ch not supported, %s failed\n", | ||
349 | en ? "enable" : "disable"); | ||
350 | return -EINVAL; | ||
351 | } | ||
352 | |||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | /** | ||
357 | * sdw_enable_disable_ports() - Enable/disable port(s) for Master and | ||
358 | * Slave(s) | ||
359 | * | ||
360 | * @m_rt: Master stream runtime | ||
361 | * @en: mode (enable/disable) | ||
362 | */ | ||
363 | static int sdw_enable_disable_ports(struct sdw_master_runtime *m_rt, bool en) | ||
364 | { | ||
365 | struct sdw_port_runtime *s_port, *m_port; | ||
366 | struct sdw_slave_runtime *s_rt = NULL; | ||
367 | int ret = 0; | ||
368 | |||
369 | /* Enable/Disable Slave port(s) */ | ||
370 | list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { | ||
371 | list_for_each_entry(s_port, &s_rt->port_list, port_node) { | ||
372 | ret = sdw_enable_disable_slave_ports(m_rt->bus, s_rt, | ||
373 | s_port, en); | ||
374 | if (ret < 0) | ||
375 | return ret; | ||
376 | } | ||
377 | } | ||
378 | |||
379 | /* Enable/Disable Master port(s) */ | ||
380 | list_for_each_entry(m_port, &m_rt->port_list, port_node) { | ||
381 | ret = sdw_enable_disable_master_ports(m_rt, m_port, en); | ||
382 | if (ret < 0) | ||
383 | return ret; | ||
384 | } | ||
385 | |||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | static int sdw_do_port_prep(struct sdw_slave_runtime *s_rt, | ||
390 | struct sdw_prepare_ch prep_ch, enum sdw_port_prep_ops cmd) | ||
391 | { | ||
392 | const struct sdw_slave_ops *ops = s_rt->slave->ops; | ||
393 | int ret; | ||
394 | |||
395 | if (ops->port_prep) { | ||
396 | ret = ops->port_prep(s_rt->slave, &prep_ch, cmd); | ||
397 | if (ret < 0) { | ||
398 | dev_err(&s_rt->slave->dev, | ||
399 | "Slave Port Prep cmd %d failed: %d", cmd, ret); | ||
400 | return ret; | ||
401 | } | ||
402 | } | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus, | ||
408 | struct sdw_slave_runtime *s_rt, | ||
409 | struct sdw_port_runtime *p_rt, bool prep) | ||
410 | { | ||
411 | struct completion *port_ready = NULL; | ||
412 | struct sdw_dpn_prop *dpn_prop; | ||
413 | struct sdw_prepare_ch prep_ch; | ||
414 | unsigned int time_left; | ||
415 | bool intr = false; | ||
416 | int ret = 0, val; | ||
417 | u32 addr; | ||
418 | |||
419 | prep_ch.num = p_rt->num; | ||
420 | prep_ch.ch_mask = p_rt->ch_mask; | ||
421 | |||
422 | dpn_prop = sdw_get_slave_dpn_prop(s_rt->slave, | ||
423 | s_rt->direction, | ||
424 | prep_ch.num); | ||
425 | if (!dpn_prop) { | ||
426 | dev_err(bus->dev, | ||
427 | "Slave Port:%d properties not found", prep_ch.num); | ||
428 | return -EINVAL; | ||
429 | } | ||
430 | |||
431 | prep_ch.prepare = prep; | ||
432 | |||
433 | prep_ch.bank = bus->params.next_bank; | ||
434 | |||
435 | if (dpn_prop->device_interrupts || !dpn_prop->simple_ch_prep_sm) | ||
436 | intr = true; | ||
437 | |||
438 | /* | ||
439 | * Enable interrupt before Port prepare. | ||
440 | * For Port de-prepare, it is assumed that port | ||
441 | * was prepared earlier | ||
442 | */ | ||
443 | if (prep && intr) { | ||
444 | ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep, | ||
445 | dpn_prop->device_interrupts); | ||
446 | if (ret < 0) | ||
447 | return ret; | ||
448 | } | ||
449 | |||
450 | /* Inform slave about the impending port prepare */ | ||
451 | sdw_do_port_prep(s_rt, prep_ch, SDW_OPS_PORT_PRE_PREP); | ||
452 | |||
453 | /* Prepare Slave port implementing CP_SM */ | ||
454 | if (!dpn_prop->simple_ch_prep_sm) { | ||
455 | addr = SDW_DPN_PREPARECTRL(p_rt->num); | ||
456 | |||
457 | if (prep) | ||
458 | ret = sdw_update(s_rt->slave, addr, | ||
459 | 0xFF, p_rt->ch_mask); | ||
460 | else | ||
461 | ret = sdw_update(s_rt->slave, addr, 0xFF, 0x0); | ||
462 | |||
463 | if (ret < 0) { | ||
464 | dev_err(&s_rt->slave->dev, | ||
465 | "Slave prep_ctrl reg write failed"); | ||
466 | return ret; | ||
467 | } | ||
468 | |||
469 | /* Wait for completion on port ready */ | ||
470 | port_ready = &s_rt->slave->port_ready[prep_ch.num]; | ||
471 | time_left = wait_for_completion_timeout(port_ready, | ||
472 | msecs_to_jiffies(dpn_prop->ch_prep_timeout)); | ||
473 | |||
474 | val = sdw_read(s_rt->slave, SDW_DPN_PREPARESTATUS(p_rt->num)); | ||
475 | val &= p_rt->ch_mask; | ||
476 | if (!time_left || val) { | ||
477 | dev_err(&s_rt->slave->dev, | ||
478 | "Chn prep failed for port:%d", prep_ch.num); | ||
479 | return -ETIMEDOUT; | ||
480 | } | ||
481 | } | ||
482 | |||
483 | /* Inform slaves about ports prepared */ | ||
484 | sdw_do_port_prep(s_rt, prep_ch, SDW_OPS_PORT_POST_PREP); | ||
485 | |||
486 | /* Disable interrupt after Port de-prepare */ | ||
487 | if (!prep && intr) | ||
488 | ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep, | ||
489 | dpn_prop->device_interrupts); | ||
490 | |||
491 | return ret; | ||
492 | } | ||
493 | |||
494 | static int sdw_prep_deprep_master_ports(struct sdw_master_runtime *m_rt, | ||
495 | struct sdw_port_runtime *p_rt, bool prep) | ||
496 | { | ||
497 | struct sdw_transport_params *t_params = &p_rt->transport_params; | ||
498 | struct sdw_bus *bus = m_rt->bus; | ||
499 | const struct sdw_master_port_ops *ops = bus->port_ops; | ||
500 | struct sdw_prepare_ch prep_ch; | ||
501 | int ret = 0; | ||
502 | |||
503 | prep_ch.num = p_rt->num; | ||
504 | prep_ch.ch_mask = p_rt->ch_mask; | ||
505 | prep_ch.prepare = prep; /* Prepare/De-prepare */ | ||
506 | prep_ch.bank = bus->params.next_bank; | ||
507 | |||
508 | /* Pre-prepare/Pre-deprepare port(s) */ | ||
509 | if (ops->dpn_port_prep) { | ||
510 | ret = ops->dpn_port_prep(bus, &prep_ch); | ||
511 | if (ret < 0) { | ||
512 | dev_err(bus->dev, "Port prepare failed for port:%d", | ||
513 | t_params->port_num); | ||
514 | return ret; | ||
515 | } | ||
516 | } | ||
517 | |||
518 | return ret; | ||
519 | } | ||
520 | |||
521 | /** | ||
522 | * sdw_prep_deprep_ports() - Prepare/De-prepare port(s) for Master(s) and | ||
523 | * Slave(s) | ||
524 | * | ||
525 | * @m_rt: Master runtime handle | ||
526 | * @prep: Prepare or De-prepare | ||
527 | */ | ||
528 | static int sdw_prep_deprep_ports(struct sdw_master_runtime *m_rt, bool prep) | ||
529 | { | ||
530 | struct sdw_slave_runtime *s_rt = NULL; | ||
531 | struct sdw_port_runtime *p_rt; | ||
532 | int ret = 0; | ||
533 | |||
534 | /* Prepare/De-prepare Slave port(s) */ | ||
535 | list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { | ||
536 | list_for_each_entry(p_rt, &s_rt->port_list, port_node) { | ||
537 | ret = sdw_prep_deprep_slave_ports(m_rt->bus, s_rt, | ||
538 | p_rt, prep); | ||
539 | if (ret < 0) | ||
540 | return ret; | ||
541 | } | ||
542 | } | ||
543 | |||
544 | /* Prepare/De-prepare Master port(s) */ | ||
545 | list_for_each_entry(p_rt, &m_rt->port_list, port_node) { | ||
546 | ret = sdw_prep_deprep_master_ports(m_rt, p_rt, prep); | ||
547 | if (ret < 0) | ||
548 | return ret; | ||
549 | } | ||
550 | |||
551 | return ret; | ||
552 | } | ||
553 | |||
554 | /** | ||
555 | * sdw_notify_config() - Notify bus configuration | ||
556 | * | ||
557 | * @m_rt: Master runtime handle | ||
558 | * | ||
559 | * This function notifies the Master(s) and Slave(s) of the | ||
560 | * new bus configuration. | ||
561 | */ | ||
562 | static int sdw_notify_config(struct sdw_master_runtime *m_rt) | ||
563 | { | ||
564 | struct sdw_slave_runtime *s_rt; | ||
565 | struct sdw_bus *bus = m_rt->bus; | ||
566 | struct sdw_slave *slave; | ||
567 | int ret = 0; | ||
568 | |||
569 | if (bus->ops->set_bus_conf) { | ||
570 | ret = bus->ops->set_bus_conf(bus, &bus->params); | ||
571 | if (ret < 0) | ||
572 | return ret; | ||
573 | } | ||
574 | |||
575 | list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { | ||
576 | slave = s_rt->slave; | ||
577 | |||
578 | if (slave->ops->bus_config) { | ||
579 | ret = slave->ops->bus_config(slave, &bus->params); | ||
580 | if (ret < 0) | ||
581 | dev_err(bus->dev, "Notify Slave: %d failed", | ||
582 | slave->dev_num); | ||
583 | return ret; | ||
584 | } | ||
585 | } | ||
586 | |||
587 | return ret; | ||
588 | } | ||
589 | |||
590 | /** | ||
591 | * sdw_program_params() - Program transport and port parameters for Master(s) | ||
592 | * and Slave(s) | ||
593 | * | ||
594 | * @bus: SDW bus instance | ||
595 | */ | ||
596 | static int sdw_program_params(struct sdw_bus *bus) | ||
597 | { | ||
598 | struct sdw_master_runtime *m_rt = NULL; | ||
599 | int ret = 0; | ||
600 | |||
601 | list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { | ||
602 | ret = sdw_program_port_params(m_rt); | ||
603 | if (ret < 0) { | ||
604 | dev_err(bus->dev, | ||
605 | "Program transport params failed: %d", ret); | ||
606 | return ret; | ||
607 | } | ||
608 | |||
609 | ret = sdw_notify_config(m_rt); | ||
610 | if (ret < 0) { | ||
611 | dev_err(bus->dev, "Notify bus config failed: %d", ret); | ||
612 | return ret; | ||
613 | } | ||
614 | |||
615 | /* Enable port(s) on alternate bank for all active streams */ | ||
616 | if (m_rt->stream->state != SDW_STREAM_ENABLED) | ||
617 | continue; | ||
618 | |||
619 | ret = sdw_enable_disable_ports(m_rt, true); | ||
620 | if (ret < 0) { | ||
621 | dev_err(bus->dev, "Enable channel failed: %d", ret); | ||
622 | return ret; | ||
623 | } | ||
624 | } | ||
625 | |||
626 | return ret; | ||
627 | } | ||
628 | |||
629 | static int sdw_bank_switch(struct sdw_bus *bus) | ||
630 | { | ||
631 | int col_index, row_index; | ||
632 | struct sdw_msg *wr_msg; | ||
633 | u8 *wbuf = NULL; | ||
634 | int ret = 0; | ||
635 | u16 addr; | ||
636 | |||
637 | wr_msg = kzalloc(sizeof(*wr_msg), GFP_KERNEL); | ||
638 | if (!wr_msg) | ||
639 | return -ENOMEM; | ||
640 | |||
641 | wbuf = kzalloc(sizeof(*wbuf), GFP_KERNEL); | ||
642 | if (!wbuf) { | ||
643 | ret = -ENOMEM; | ||
644 | goto error_1; | ||
645 | } | ||
646 | |||
647 | /* Get row and column index to program register */ | ||
648 | col_index = sdw_find_col_index(bus->params.col); | ||
649 | row_index = sdw_find_row_index(bus->params.row); | ||
650 | wbuf[0] = col_index | (row_index << 3); | ||
651 | |||
652 | if (bus->params.next_bank) | ||
653 | addr = SDW_SCP_FRAMECTRL_B1; | ||
654 | else | ||
655 | addr = SDW_SCP_FRAMECTRL_B0; | ||
656 | |||
657 | sdw_fill_msg(wr_msg, NULL, addr, 1, SDW_BROADCAST_DEV_NUM, | ||
658 | SDW_MSG_FLAG_WRITE, wbuf); | ||
659 | wr_msg->ssp_sync = true; | ||
660 | |||
661 | ret = sdw_transfer(bus, wr_msg); | ||
662 | if (ret < 0) { | ||
663 | dev_err(bus->dev, "Slave frame_ctrl reg write failed"); | ||
664 | goto error; | ||
665 | } | ||
666 | |||
667 | kfree(wr_msg); | ||
668 | kfree(wbuf); | ||
669 | bus->defer_msg.msg = NULL; | ||
670 | bus->params.curr_bank = !bus->params.curr_bank; | ||
671 | bus->params.next_bank = !bus->params.next_bank; | ||
672 | |||
673 | return 0; | ||
674 | |||
675 | error: | ||
676 | kfree(wbuf); | ||
677 | error_1: | ||
678 | kfree(wr_msg); | ||
679 | return ret; | ||
680 | } | ||
681 | |||
682 | static int do_bank_switch(struct sdw_stream_runtime *stream) | ||
683 | { | ||
684 | struct sdw_master_runtime *m_rt = stream->m_rt; | ||
685 | const struct sdw_master_ops *ops; | ||
686 | struct sdw_bus *bus = m_rt->bus; | ||
687 | int ret = 0; | ||
688 | |||
689 | ops = bus->ops; | ||
690 | |||
691 | /* Pre-bank switch */ | ||
692 | if (ops->pre_bank_switch) { | ||
693 | ret = ops->pre_bank_switch(bus); | ||
694 | if (ret < 0) { | ||
695 | dev_err(bus->dev, "Pre bank switch op failed: %d", ret); | ||
696 | return ret; | ||
697 | } | ||
698 | } | ||
699 | |||
700 | /* Bank switch */ | ||
701 | ret = sdw_bank_switch(bus); | ||
702 | if (ret < 0) { | ||
703 | dev_err(bus->dev, "Bank switch failed: %d", ret); | ||
704 | return ret; | ||
705 | } | ||
706 | |||
707 | /* Post-bank switch */ | ||
708 | if (ops->post_bank_switch) { | ||
709 | ret = ops->post_bank_switch(bus); | ||
710 | if (ret < 0) { | ||
711 | dev_err(bus->dev, | ||
712 | "Post bank switch op failed: %d", ret); | ||
713 | } | ||
714 | } | ||
715 | |||
716 | return ret; | ||
717 | } | ||
718 | |||
719 | /** | ||
720 | * sdw_release_stream() - Free the assigned stream runtime | ||
721 | * | ||
722 | * @stream: SoundWire stream runtime | ||
723 | * | ||
724 | * sdw_release_stream should be called only once per stream | ||
725 | */ | ||
726 | void sdw_release_stream(struct sdw_stream_runtime *stream) | ||
727 | { | ||
728 | kfree(stream); | ||
729 | } | ||
730 | EXPORT_SYMBOL(sdw_release_stream); | ||
731 | |||
732 | /** | ||
733 | * sdw_alloc_stream() - Allocate and return stream runtime | ||
734 | * | ||
735 | * @stream_name: SoundWire stream name | ||
736 | * | ||
737 | * Allocates a SoundWire stream runtime instance. | ||
738 | * sdw_alloc_stream should be called only once per stream. Typically | ||
739 | * invoked from ALSA/ASoC machine/platform driver. | ||
740 | */ | ||
741 | struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name) | ||
742 | { | ||
743 | struct sdw_stream_runtime *stream; | ||
744 | |||
745 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); | ||
746 | if (!stream) | ||
747 | return NULL; | ||
748 | |||
749 | stream->name = stream_name; | ||
750 | stream->state = SDW_STREAM_ALLOCATED; | ||
751 | |||
752 | return stream; | ||
753 | } | ||
754 | EXPORT_SYMBOL(sdw_alloc_stream); | ||
755 | |||
756 | /** | ||
757 | * sdw_alloc_master_rt() - Allocates and initialize Master runtime handle | ||
758 | * | ||
759 | * @bus: SDW bus instance | ||
760 | * @stream_config: Stream configuration | ||
761 | * @stream: Stream runtime handle. | ||
762 | * | ||
763 | * This function is to be called with bus_lock held. | ||
764 | */ | ||
765 | static struct sdw_master_runtime | ||
766 | *sdw_alloc_master_rt(struct sdw_bus *bus, | ||
767 | struct sdw_stream_config *stream_config, | ||
768 | struct sdw_stream_runtime *stream) | ||
769 | { | ||
770 | struct sdw_master_runtime *m_rt; | ||
771 | |||
772 | m_rt = stream->m_rt; | ||
773 | |||
774 | /* | ||
775 | * check if Master is already allocated (as a result of Slave adding | ||
776 | * it first), if so skip allocation and go to configure | ||
777 | */ | ||
778 | if (m_rt) | ||
779 | goto stream_config; | ||
780 | |||
781 | m_rt = kzalloc(sizeof(*m_rt), GFP_KERNEL); | ||
782 | if (!m_rt) | ||
783 | return NULL; | ||
784 | |||
785 | /* Initialization of Master runtime handle */ | ||
786 | INIT_LIST_HEAD(&m_rt->port_list); | ||
787 | INIT_LIST_HEAD(&m_rt->slave_rt_list); | ||
788 | stream->m_rt = m_rt; | ||
789 | |||
790 | list_add_tail(&m_rt->bus_node, &bus->m_rt_list); | ||
791 | |||
792 | stream_config: | ||
793 | m_rt->ch_count = stream_config->ch_count; | ||
794 | m_rt->bus = bus; | ||
795 | m_rt->stream = stream; | ||
796 | m_rt->direction = stream_config->direction; | ||
797 | |||
798 | return m_rt; | ||
799 | } | ||
800 | |||
801 | /** | ||
802 | * sdw_alloc_slave_rt() - Allocate and initialize Slave runtime handle. | ||
803 | * | ||
804 | * @slave: Slave handle | ||
805 | * @stream_config: Stream configuration | ||
806 | * @stream: Stream runtime handle | ||
807 | * | ||
808 | * This function is to be called with bus_lock held. | ||
809 | */ | ||
810 | static struct sdw_slave_runtime | ||
811 | *sdw_alloc_slave_rt(struct sdw_slave *slave, | ||
812 | struct sdw_stream_config *stream_config, | ||
813 | struct sdw_stream_runtime *stream) | ||
814 | { | ||
815 | struct sdw_slave_runtime *s_rt = NULL; | ||
816 | |||
817 | s_rt = kzalloc(sizeof(*s_rt), GFP_KERNEL); | ||
818 | if (!s_rt) | ||
819 | return NULL; | ||
820 | |||
821 | INIT_LIST_HEAD(&s_rt->port_list); | ||
822 | s_rt->ch_count = stream_config->ch_count; | ||
823 | s_rt->direction = stream_config->direction; | ||
824 | s_rt->slave = slave; | ||
825 | |||
826 | return s_rt; | ||
827 | } | ||
828 | |||
829 | static void sdw_master_port_release(struct sdw_bus *bus, | ||
830 | struct sdw_master_runtime *m_rt) | ||
831 | { | ||
832 | struct sdw_port_runtime *p_rt, *_p_rt; | ||
833 | |||
834 | list_for_each_entry_safe(p_rt, _p_rt, | ||
835 | &m_rt->port_list, port_node) { | ||
836 | list_del(&p_rt->port_node); | ||
837 | kfree(p_rt); | ||
838 | } | ||
839 | } | ||
840 | |||
841 | static void sdw_slave_port_release(struct sdw_bus *bus, | ||
842 | struct sdw_slave *slave, | ||
843 | struct sdw_stream_runtime *stream) | ||
844 | { | ||
845 | struct sdw_port_runtime *p_rt, *_p_rt; | ||
846 | struct sdw_master_runtime *m_rt = stream->m_rt; | ||
847 | struct sdw_slave_runtime *s_rt; | ||
848 | |||
849 | list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { | ||
850 | if (s_rt->slave != slave) | ||
851 | continue; | ||
852 | |||
853 | list_for_each_entry_safe(p_rt, _p_rt, | ||
854 | &s_rt->port_list, port_node) { | ||
855 | list_del(&p_rt->port_node); | ||
856 | kfree(p_rt); | ||
857 | } | ||
858 | } | ||
859 | } | ||
860 | |||
861 | /** | ||
862 | * sdw_release_slave_stream() - Free Slave(s) runtime handle | ||
863 | * | ||
864 | * @slave: Slave handle. | ||
865 | * @stream: Stream runtime handle. | ||
866 | * | ||
867 | * This function is to be called with bus_lock held. | ||
868 | */ | ||
869 | static void sdw_release_slave_stream(struct sdw_slave *slave, | ||
870 | struct sdw_stream_runtime *stream) | ||
871 | { | ||
872 | struct sdw_slave_runtime *s_rt, *_s_rt; | ||
873 | struct sdw_master_runtime *m_rt = stream->m_rt; | ||
874 | |||
875 | /* Retrieve Slave runtime handle */ | ||
876 | list_for_each_entry_safe(s_rt, _s_rt, | ||
877 | &m_rt->slave_rt_list, m_rt_node) { | ||
878 | |||
879 | if (s_rt->slave == slave) { | ||
880 | list_del(&s_rt->m_rt_node); | ||
881 | kfree(s_rt); | ||
882 | return; | ||
883 | } | ||
884 | } | ||
885 | } | ||
886 | |||
887 | /** | ||
888 | * sdw_release_master_stream() - Free Master runtime handle | ||
889 | * | ||
890 | * @stream: Stream runtime handle. | ||
891 | * | ||
892 | * This function is to be called with bus_lock held | ||
893 | * It frees the Master runtime handle and associated Slave(s) runtime | ||
894 | * handle. If this is called first then sdw_release_slave_stream() will have | ||
895 | * no effect as Slave(s) runtime handle would already be freed up. | ||
896 | */ | ||
897 | static void sdw_release_master_stream(struct sdw_stream_runtime *stream) | ||
898 | { | ||
899 | struct sdw_master_runtime *m_rt = stream->m_rt; | ||
900 | struct sdw_slave_runtime *s_rt, *_s_rt; | ||
901 | |||
902 | list_for_each_entry_safe(s_rt, _s_rt, | ||
903 | &m_rt->slave_rt_list, m_rt_node) | ||
904 | sdw_stream_remove_slave(s_rt->slave, stream); | ||
905 | |||
906 | list_del(&m_rt->bus_node); | ||
907 | } | ||
908 | |||
909 | /** | ||
910 | * sdw_stream_remove_master() - Remove master from sdw_stream | ||
911 | * | ||
912 | * @bus: SDW Bus instance | ||
913 | * @stream: SoundWire stream | ||
914 | * | ||
915 | * This removes and frees port_rt and master_rt from a stream | ||
916 | */ | ||
917 | int sdw_stream_remove_master(struct sdw_bus *bus, | ||
918 | struct sdw_stream_runtime *stream) | ||
919 | { | ||
920 | mutex_lock(&bus->bus_lock); | ||
921 | |||
922 | sdw_release_master_stream(stream); | ||
923 | sdw_master_port_release(bus, stream->m_rt); | ||
924 | stream->state = SDW_STREAM_RELEASED; | ||
925 | kfree(stream->m_rt); | ||
926 | stream->m_rt = NULL; | ||
927 | |||
928 | mutex_unlock(&bus->bus_lock); | ||
929 | |||
930 | return 0; | ||
931 | } | ||
932 | EXPORT_SYMBOL(sdw_stream_remove_master); | ||
933 | |||
934 | /** | ||
935 | * sdw_stream_remove_slave() - Remove slave from sdw_stream | ||
936 | * | ||
937 | * @slave: SDW Slave instance | ||
938 | * @stream: SoundWire stream | ||
939 | * | ||
940 | * This removes and frees port_rt and slave_rt from a stream | ||
941 | */ | ||
942 | int sdw_stream_remove_slave(struct sdw_slave *slave, | ||
943 | struct sdw_stream_runtime *stream) | ||
944 | { | ||
945 | mutex_lock(&slave->bus->bus_lock); | ||
946 | |||
947 | sdw_slave_port_release(slave->bus, slave, stream); | ||
948 | sdw_release_slave_stream(slave, stream); | ||
949 | |||
950 | mutex_unlock(&slave->bus->bus_lock); | ||
951 | |||
952 | return 0; | ||
953 | } | ||
954 | EXPORT_SYMBOL(sdw_stream_remove_slave); | ||
955 | |||
956 | /** | ||
957 | * sdw_config_stream() - Configure the allocated stream | ||
958 | * | ||
959 | * @dev: SDW device | ||
960 | * @stream: SoundWire stream | ||
961 | * @stream_config: Stream configuration for audio stream | ||
962 | * @is_slave: is API called from Slave or Master | ||
963 | * | ||
964 | * This function is to be called with bus_lock held. | ||
965 | */ | ||
966 | static int sdw_config_stream(struct device *dev, | ||
967 | struct sdw_stream_runtime *stream, | ||
968 | struct sdw_stream_config *stream_config, bool is_slave) | ||
969 | { | ||
970 | /* | ||
971 | * Update the stream rate, channel and bps based on data | ||
972 | * source. For more than one data source (multilink), | ||
973 | * match the rate, bps, stream type and increment number of channels. | ||
974 | * | ||
975 | * If rate/bps is zero, it means the values are not set, so skip | ||
976 | * comparison and allow the value to be set and stored in stream | ||
977 | */ | ||
978 | if (stream->params.rate && | ||
979 | stream->params.rate != stream_config->frame_rate) { | ||
980 | dev_err(dev, "rate not matching, stream:%s", stream->name); | ||
981 | return -EINVAL; | ||
982 | } | ||
983 | |||
984 | if (stream->params.bps && | ||
985 | stream->params.bps != stream_config->bps) { | ||
986 | dev_err(dev, "bps not matching, stream:%s", stream->name); | ||
987 | return -EINVAL; | ||
988 | } | ||
989 | |||
990 | stream->type = stream_config->type; | ||
991 | stream->params.rate = stream_config->frame_rate; | ||
992 | stream->params.bps = stream_config->bps; | ||
993 | |||
994 | /* TODO: Update this check during Device-device support */ | ||
995 | if (is_slave) | ||
996 | stream->params.ch_count += stream_config->ch_count; | ||
997 | |||
998 | return 0; | ||
999 | } | ||
1000 | |||
1001 | static int sdw_is_valid_port_range(struct device *dev, | ||
1002 | struct sdw_port_runtime *p_rt) | ||
1003 | { | ||
1004 | if (!SDW_VALID_PORT_RANGE(p_rt->num)) { | ||
1005 | dev_err(dev, | ||
1006 | "SoundWire: Invalid port number :%d", p_rt->num); | ||
1007 | return -EINVAL; | ||
1008 | } | ||
1009 | |||
1010 | return 0; | ||
1011 | } | ||
1012 | |||
1013 | static struct sdw_port_runtime *sdw_port_alloc(struct device *dev, | ||
1014 | struct sdw_port_config *port_config, | ||
1015 | int port_index) | ||
1016 | { | ||
1017 | struct sdw_port_runtime *p_rt; | ||
1018 | |||
1019 | p_rt = kzalloc(sizeof(*p_rt), GFP_KERNEL); | ||
1020 | if (!p_rt) | ||
1021 | return NULL; | ||
1022 | |||
1023 | p_rt->ch_mask = port_config[port_index].ch_mask; | ||
1024 | p_rt->num = port_config[port_index].num; | ||
1025 | |||
1026 | return p_rt; | ||
1027 | } | ||
1028 | |||
1029 | static int sdw_master_port_config(struct sdw_bus *bus, | ||
1030 | struct sdw_master_runtime *m_rt, | ||
1031 | struct sdw_port_config *port_config, | ||
1032 | unsigned int num_ports) | ||
1033 | { | ||
1034 | struct sdw_port_runtime *p_rt; | ||
1035 | int i; | ||
1036 | |||
1037 | /* Iterate for number of ports to perform initialization */ | ||
1038 | for (i = 0; i < num_ports; i++) { | ||
1039 | p_rt = sdw_port_alloc(bus->dev, port_config, i); | ||
1040 | if (!p_rt) | ||
1041 | return -ENOMEM; | ||
1042 | |||
1043 | /* | ||
1044 | * TODO: Check port capabilities for requested | ||
1045 | * configuration (audio mode support) | ||
1046 | */ | ||
1047 | |||
1048 | list_add_tail(&p_rt->port_node, &m_rt->port_list); | ||
1049 | } | ||
1050 | |||
1051 | return 0; | ||
1052 | } | ||
1053 | |||
1054 | static int sdw_slave_port_config(struct sdw_slave *slave, | ||
1055 | struct sdw_slave_runtime *s_rt, | ||
1056 | struct sdw_port_config *port_config, | ||
1057 | unsigned int num_config) | ||
1058 | { | ||
1059 | struct sdw_port_runtime *p_rt; | ||
1060 | int i, ret; | ||
1061 | |||
1062 | /* Iterate for number of ports to perform initialization */ | ||
1063 | for (i = 0; i < num_config; i++) { | ||
1064 | p_rt = sdw_port_alloc(&slave->dev, port_config, i); | ||
1065 | if (!p_rt) | ||
1066 | return -ENOMEM; | ||
1067 | |||
1068 | /* | ||
1069 | * TODO: Check valid port range as defined by DisCo/ | ||
1070 | * slave | ||
1071 | */ | ||
1072 | ret = sdw_is_valid_port_range(&slave->dev, p_rt); | ||
1073 | if (ret < 0) { | ||
1074 | kfree(p_rt); | ||
1075 | return ret; | ||
1076 | } | ||
1077 | |||
1078 | /* | ||
1079 | * TODO: Check port capabilities for requested | ||
1080 | * configuration (audio mode support) | ||
1081 | */ | ||
1082 | |||
1083 | list_add_tail(&p_rt->port_node, &s_rt->port_list); | ||
1084 | } | ||
1085 | |||
1086 | return 0; | ||
1087 | } | ||
1088 | |||
1089 | /** | ||
1090 | * sdw_stream_add_master() - Allocate and add master runtime to a stream | ||
1091 | * | ||
1092 | * @bus: SDW Bus instance | ||
1093 | * @stream_config: Stream configuration for audio stream | ||
1094 | * @port_config: Port configuration for audio stream | ||
1095 | * @num_ports: Number of ports | ||
1096 | * @stream: SoundWire stream | ||
1097 | */ | ||
1098 | int sdw_stream_add_master(struct sdw_bus *bus, | ||
1099 | struct sdw_stream_config *stream_config, | ||
1100 | struct sdw_port_config *port_config, | ||
1101 | unsigned int num_ports, | ||
1102 | struct sdw_stream_runtime *stream) | ||
1103 | { | ||
1104 | struct sdw_master_runtime *m_rt = NULL; | ||
1105 | int ret; | ||
1106 | |||
1107 | mutex_lock(&bus->bus_lock); | ||
1108 | |||
1109 | m_rt = sdw_alloc_master_rt(bus, stream_config, stream); | ||
1110 | if (!m_rt) { | ||
1111 | dev_err(bus->dev, | ||
1112 | "Master runtime config failed for stream:%s", | ||
1113 | stream->name); | ||
1114 | ret = -ENOMEM; | ||
1115 | goto error; | ||
1116 | } | ||
1117 | |||
1118 | ret = sdw_config_stream(bus->dev, stream, stream_config, false); | ||
1119 | if (ret) | ||
1120 | goto stream_error; | ||
1121 | |||
1122 | ret = sdw_master_port_config(bus, m_rt, port_config, num_ports); | ||
1123 | if (ret) | ||
1124 | goto stream_error; | ||
1125 | |||
1126 | stream->state = SDW_STREAM_CONFIGURED; | ||
1127 | |||
1128 | stream_error: | ||
1129 | sdw_release_master_stream(stream); | ||
1130 | error: | ||
1131 | mutex_unlock(&bus->bus_lock); | ||
1132 | return ret; | ||
1133 | } | ||
1134 | EXPORT_SYMBOL(sdw_stream_add_master); | ||
1135 | |||
1136 | /** | ||
1137 | * sdw_stream_add_slave() - Allocate and add master/slave runtime to a stream | ||
1138 | * | ||
1139 | * @slave: SDW Slave instance | ||
1140 | * @stream_config: Stream configuration for audio stream | ||
1141 | * @stream: SoundWire stream | ||
1142 | * @port_config: Port configuration for audio stream | ||
1143 | * @num_ports: Number of ports | ||
1144 | */ | ||
1145 | int sdw_stream_add_slave(struct sdw_slave *slave, | ||
1146 | struct sdw_stream_config *stream_config, | ||
1147 | struct sdw_port_config *port_config, | ||
1148 | unsigned int num_ports, | ||
1149 | struct sdw_stream_runtime *stream) | ||
1150 | { | ||
1151 | struct sdw_slave_runtime *s_rt; | ||
1152 | struct sdw_master_runtime *m_rt; | ||
1153 | int ret; | ||
1154 | |||
1155 | mutex_lock(&slave->bus->bus_lock); | ||
1156 | |||
1157 | /* | ||
1158 | * If this API is invoked by Slave first then m_rt is not valid. | ||
1159 | * So, allocate m_rt and add Slave to it. | ||
1160 | */ | ||
1161 | m_rt = sdw_alloc_master_rt(slave->bus, stream_config, stream); | ||
1162 | if (!m_rt) { | ||
1163 | dev_err(&slave->dev, | ||
1164 | "alloc master runtime failed for stream:%s", | ||
1165 | stream->name); | ||
1166 | ret = -ENOMEM; | ||
1167 | goto error; | ||
1168 | } | ||
1169 | |||
1170 | s_rt = sdw_alloc_slave_rt(slave, stream_config, stream); | ||
1171 | if (!s_rt) { | ||
1172 | dev_err(&slave->dev, | ||
1173 | "Slave runtime config failed for stream:%s", | ||
1174 | stream->name); | ||
1175 | ret = -ENOMEM; | ||
1176 | goto stream_error; | ||
1177 | } | ||
1178 | |||
1179 | ret = sdw_config_stream(&slave->dev, stream, stream_config, true); | ||
1180 | if (ret) | ||
1181 | goto stream_error; | ||
1182 | |||
1183 | list_add_tail(&s_rt->m_rt_node, &m_rt->slave_rt_list); | ||
1184 | |||
1185 | ret = sdw_slave_port_config(slave, s_rt, port_config, num_ports); | ||
1186 | if (ret) | ||
1187 | goto stream_error; | ||
1188 | |||
1189 | stream->state = SDW_STREAM_CONFIGURED; | ||
1190 | goto error; | ||
1191 | |||
1192 | stream_error: | ||
1193 | /* | ||
1194 | * we hit error so cleanup the stream, release all Slave(s) and | ||
1195 | * Master runtime | ||
1196 | */ | ||
1197 | sdw_release_master_stream(stream); | ||
1198 | error: | ||
1199 | mutex_unlock(&slave->bus->bus_lock); | ||
1200 | return ret; | ||
1201 | } | ||
1202 | EXPORT_SYMBOL(sdw_stream_add_slave); | ||
1203 | |||
1204 | /** | ||
1205 | * sdw_get_slave_dpn_prop() - Get Slave port capabilities | ||
1206 | * | ||
1207 | * @slave: Slave handle | ||
1208 | * @direction: Data direction. | ||
1209 | * @port_num: Port number | ||
1210 | */ | ||
1211 | struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave, | ||
1212 | enum sdw_data_direction direction, | ||
1213 | unsigned int port_num) | ||
1214 | { | ||
1215 | struct sdw_dpn_prop *dpn_prop; | ||
1216 | u8 num_ports; | ||
1217 | int i; | ||
1218 | |||
1219 | if (direction == SDW_DATA_DIR_TX) { | ||
1220 | num_ports = hweight32(slave->prop.source_ports); | ||
1221 | dpn_prop = slave->prop.src_dpn_prop; | ||
1222 | } else { | ||
1223 | num_ports = hweight32(slave->prop.sink_ports); | ||
1224 | dpn_prop = slave->prop.sink_dpn_prop; | ||
1225 | } | ||
1226 | |||
1227 | for (i = 0; i < num_ports; i++) { | ||
1228 | dpn_prop = &dpn_prop[i]; | ||
1229 | |||
1230 | if (dpn_prop->num == port_num) | ||
1231 | return &dpn_prop[i]; | ||
1232 | } | ||
1233 | |||
1234 | return NULL; | ||
1235 | } | ||
1236 | |||
1237 | static int _sdw_prepare_stream(struct sdw_stream_runtime *stream) | ||
1238 | { | ||
1239 | struct sdw_master_runtime *m_rt = stream->m_rt; | ||
1240 | struct sdw_bus *bus = m_rt->bus; | ||
1241 | struct sdw_master_prop *prop = NULL; | ||
1242 | struct sdw_bus_params params; | ||
1243 | int ret; | ||
1244 | |||
1245 | prop = &bus->prop; | ||
1246 | memcpy(¶ms, &bus->params, sizeof(params)); | ||
1247 | |||
1248 | /* TODO: Support Asynchronous mode */ | ||
1249 | if ((prop->max_freq % stream->params.rate) != 0) { | ||
1250 | dev_err(bus->dev, "Async mode not supported"); | ||
1251 | return -EINVAL; | ||
1252 | } | ||
1253 | |||
1254 | /* Increment cumulative bus bandwidth */ | ||
1255 | /* TODO: Update this during Device-Device support */ | ||
1256 | bus->params.bandwidth += m_rt->stream->params.rate * | ||
1257 | m_rt->ch_count * m_rt->stream->params.bps; | ||
1258 | |||
1259 | /* Program params */ | ||
1260 | ret = sdw_program_params(bus); | ||
1261 | if (ret < 0) { | ||
1262 | dev_err(bus->dev, "Program params failed: %d", ret); | ||
1263 | goto restore_params; | ||
1264 | } | ||
1265 | |||
1266 | ret = do_bank_switch(stream); | ||
1267 | if (ret < 0) { | ||
1268 | dev_err(bus->dev, "Bank switch failed: %d", ret); | ||
1269 | goto restore_params; | ||
1270 | } | ||
1271 | |||
1272 | /* Prepare port(s) on the new clock configuration */ | ||
1273 | ret = sdw_prep_deprep_ports(m_rt, true); | ||
1274 | if (ret < 0) { | ||
1275 | dev_err(bus->dev, "Prepare port(s) failed ret = %d", | ||
1276 | ret); | ||
1277 | return ret; | ||
1278 | } | ||
1279 | |||
1280 | stream->state = SDW_STREAM_PREPARED; | ||
1281 | |||
1282 | return ret; | ||
1283 | |||
1284 | restore_params: | ||
1285 | memcpy(&bus->params, ¶ms, sizeof(params)); | ||
1286 | return ret; | ||
1287 | } | ||
1288 | |||
1289 | /** | ||
1290 | * sdw_prepare_stream() - Prepare SoundWire stream | ||
1291 | * | ||
1292 | * @stream: Soundwire stream | ||
1293 | * | ||
1294 | * Documentation/soundwire/stream.txt explains this API in detail | ||
1295 | */ | ||
1296 | int sdw_prepare_stream(struct sdw_stream_runtime *stream) | ||
1297 | { | ||
1298 | int ret = 0; | ||
1299 | |||
1300 | if (!stream) { | ||
1301 | pr_err("SoundWire: Handle not found for stream"); | ||
1302 | return -EINVAL; | ||
1303 | } | ||
1304 | |||
1305 | mutex_lock(&stream->m_rt->bus->bus_lock); | ||
1306 | |||
1307 | ret = _sdw_prepare_stream(stream); | ||
1308 | if (ret < 0) | ||
1309 | pr_err("Prepare for stream:%s failed: %d", stream->name, ret); | ||
1310 | |||
1311 | mutex_unlock(&stream->m_rt->bus->bus_lock); | ||
1312 | return ret; | ||
1313 | } | ||
1314 | EXPORT_SYMBOL(sdw_prepare_stream); | ||
1315 | |||
1316 | static int _sdw_enable_stream(struct sdw_stream_runtime *stream) | ||
1317 | { | ||
1318 | struct sdw_master_runtime *m_rt = stream->m_rt; | ||
1319 | struct sdw_bus *bus = m_rt->bus; | ||
1320 | int ret; | ||
1321 | |||
1322 | /* Program params */ | ||
1323 | ret = sdw_program_params(bus); | ||
1324 | if (ret < 0) { | ||
1325 | dev_err(bus->dev, "Program params failed: %d", ret); | ||
1326 | return ret; | ||
1327 | } | ||
1328 | |||
1329 | /* Enable port(s) */ | ||
1330 | ret = sdw_enable_disable_ports(m_rt, true); | ||
1331 | if (ret < 0) { | ||
1332 | dev_err(bus->dev, "Enable port(s) failed ret: %d", ret); | ||
1333 | return ret; | ||
1334 | } | ||
1335 | |||
1336 | ret = do_bank_switch(stream); | ||
1337 | if (ret < 0) { | ||
1338 | dev_err(bus->dev, "Bank switch failed: %d", ret); | ||
1339 | return ret; | ||
1340 | } | ||
1341 | |||
1342 | stream->state = SDW_STREAM_ENABLED; | ||
1343 | return 0; | ||
1344 | } | ||
1345 | |||
1346 | /** | ||
1347 | * sdw_enable_stream() - Enable SoundWire stream | ||
1348 | * | ||
1349 | * @stream: Soundwire stream | ||
1350 | * | ||
1351 | * Documentation/soundwire/stream.txt explains this API in detail | ||
1352 | */ | ||
1353 | int sdw_enable_stream(struct sdw_stream_runtime *stream) | ||
1354 | { | ||
1355 | int ret = 0; | ||
1356 | |||
1357 | if (!stream) { | ||
1358 | pr_err("SoundWire: Handle not found for stream"); | ||
1359 | return -EINVAL; | ||
1360 | } | ||
1361 | |||
1362 | mutex_lock(&stream->m_rt->bus->bus_lock); | ||
1363 | |||
1364 | ret = _sdw_enable_stream(stream); | ||
1365 | if (ret < 0) | ||
1366 | pr_err("Enable for stream:%s failed: %d", stream->name, ret); | ||
1367 | |||
1368 | mutex_unlock(&stream->m_rt->bus->bus_lock); | ||
1369 | return ret; | ||
1370 | } | ||
1371 | EXPORT_SYMBOL(sdw_enable_stream); | ||
1372 | |||
1373 | static int _sdw_disable_stream(struct sdw_stream_runtime *stream) | ||
1374 | { | ||
1375 | struct sdw_master_runtime *m_rt = stream->m_rt; | ||
1376 | struct sdw_bus *bus = m_rt->bus; | ||
1377 | int ret; | ||
1378 | |||
1379 | /* Disable port(s) */ | ||
1380 | ret = sdw_enable_disable_ports(m_rt, false); | ||
1381 | if (ret < 0) { | ||
1382 | dev_err(bus->dev, "Disable port(s) failed: %d", ret); | ||
1383 | return ret; | ||
1384 | } | ||
1385 | |||
1386 | stream->state = SDW_STREAM_DISABLED; | ||
1387 | |||
1388 | /* Program params */ | ||
1389 | ret = sdw_program_params(bus); | ||
1390 | if (ret < 0) { | ||
1391 | dev_err(bus->dev, "Program params failed: %d", ret); | ||
1392 | return ret; | ||
1393 | } | ||
1394 | |||
1395 | return do_bank_switch(stream); | ||
1396 | } | ||
1397 | |||
1398 | /** | ||
1399 | * sdw_disable_stream() - Disable SoundWire stream | ||
1400 | * | ||
1401 | * @stream: Soundwire stream | ||
1402 | * | ||
1403 | * Documentation/soundwire/stream.txt explains this API in detail | ||
1404 | */ | ||
1405 | int sdw_disable_stream(struct sdw_stream_runtime *stream) | ||
1406 | { | ||
1407 | int ret = 0; | ||
1408 | |||
1409 | if (!stream) { | ||
1410 | pr_err("SoundWire: Handle not found for stream"); | ||
1411 | return -EINVAL; | ||
1412 | } | ||
1413 | |||
1414 | mutex_lock(&stream->m_rt->bus->bus_lock); | ||
1415 | |||
1416 | ret = _sdw_disable_stream(stream); | ||
1417 | if (ret < 0) | ||
1418 | pr_err("Disable for stream:%s failed: %d", stream->name, ret); | ||
1419 | |||
1420 | mutex_unlock(&stream->m_rt->bus->bus_lock); | ||
1421 | return ret; | ||
1422 | } | ||
1423 | EXPORT_SYMBOL(sdw_disable_stream); | ||
1424 | |||
1425 | static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream) | ||
1426 | { | ||
1427 | struct sdw_master_runtime *m_rt = stream->m_rt; | ||
1428 | struct sdw_bus *bus = m_rt->bus; | ||
1429 | int ret = 0; | ||
1430 | |||
1431 | /* De-prepare port(s) */ | ||
1432 | ret = sdw_prep_deprep_ports(m_rt, false); | ||
1433 | if (ret < 0) { | ||
1434 | dev_err(bus->dev, "De-prepare port(s) failed: %d", ret); | ||
1435 | return ret; | ||
1436 | } | ||
1437 | |||
1438 | stream->state = SDW_STREAM_DEPREPARED; | ||
1439 | |||
1440 | /* TODO: Update this during Device-Device support */ | ||
1441 | bus->params.bandwidth -= m_rt->stream->params.rate * | ||
1442 | m_rt->ch_count * m_rt->stream->params.bps; | ||
1443 | |||
1444 | /* Program params */ | ||
1445 | ret = sdw_program_params(bus); | ||
1446 | if (ret < 0) { | ||
1447 | dev_err(bus->dev, "Program params failed: %d", ret); | ||
1448 | return ret; | ||
1449 | } | ||
1450 | |||
1451 | return do_bank_switch(stream); | ||
1452 | } | ||
1453 | |||
1454 | /** | ||
1455 | * sdw_deprepare_stream() - Deprepare SoundWire stream | ||
1456 | * | ||
1457 | * @stream: Soundwire stream | ||
1458 | * | ||
1459 | * Documentation/soundwire/stream.txt explains this API in detail | ||
1460 | */ | ||
1461 | int sdw_deprepare_stream(struct sdw_stream_runtime *stream) | ||
1462 | { | ||
1463 | int ret = 0; | ||
1464 | |||
1465 | if (!stream) { | ||
1466 | pr_err("SoundWire: Handle not found for stream"); | ||
1467 | return -EINVAL; | ||
1468 | } | ||
1469 | |||
1470 | mutex_lock(&stream->m_rt->bus->bus_lock); | ||
1471 | |||
1472 | ret = _sdw_deprepare_stream(stream); | ||
1473 | if (ret < 0) | ||
1474 | pr_err("De-prepare for stream:%d failed: %d", ret, ret); | ||
1475 | |||
1476 | mutex_unlock(&stream->m_rt->bus->bus_lock); | ||
1477 | return ret; | ||
1478 | } | ||
1479 | EXPORT_SYMBOL(sdw_deprepare_stream); | ||