blob: 289342340262f9acfb6ff0e76c065528e05f44dd [file] [log] [blame]
Sanyog Kale89e59052018-04-26 18:38:08 +05301// 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.h>
15#include "bus.h"
16
17/**
18 * sdw_release_stream() - Free the assigned stream runtime
19 *
20 * @stream: SoundWire stream runtime
21 *
22 * sdw_release_stream should be called only once per stream
23 */
24void sdw_release_stream(struct sdw_stream_runtime *stream)
25{
26 kfree(stream);
27}
28EXPORT_SYMBOL(sdw_release_stream);
29
30/**
31 * sdw_alloc_stream() - Allocate and return stream runtime
32 *
33 * @stream_name: SoundWire stream name
34 *
35 * Allocates a SoundWire stream runtime instance.
36 * sdw_alloc_stream should be called only once per stream. Typically
37 * invoked from ALSA/ASoC machine/platform driver.
38 */
39struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name)
40{
41 struct sdw_stream_runtime *stream;
42
43 stream = kzalloc(sizeof(*stream), GFP_KERNEL);
44 if (!stream)
45 return NULL;
46
47 stream->name = stream_name;
48 stream->state = SDW_STREAM_ALLOCATED;
49
50 return stream;
51}
52EXPORT_SYMBOL(sdw_alloc_stream);
53
54/**
55 * sdw_alloc_master_rt() - Allocates and initialize Master runtime handle
56 *
57 * @bus: SDW bus instance
58 * @stream_config: Stream configuration
59 * @stream: Stream runtime handle.
60 *
61 * This function is to be called with bus_lock held.
62 */
63static struct sdw_master_runtime
64*sdw_alloc_master_rt(struct sdw_bus *bus,
65 struct sdw_stream_config *stream_config,
66 struct sdw_stream_runtime *stream)
67{
68 struct sdw_master_runtime *m_rt;
69
70 m_rt = stream->m_rt;
71
72 /*
73 * check if Master is already allocated (as a result of Slave adding
74 * it first), if so skip allocation and go to configure
75 */
76 if (m_rt)
77 goto stream_config;
78
79 m_rt = kzalloc(sizeof(*m_rt), GFP_KERNEL);
80 if (!m_rt)
81 return NULL;
82
83 /* Initialization of Master runtime handle */
Sanyog Kalebbe73792018-04-26 18:38:13 +053084 INIT_LIST_HEAD(&m_rt->port_list);
Sanyog Kale89e59052018-04-26 18:38:08 +053085 INIT_LIST_HEAD(&m_rt->slave_rt_list);
86 stream->m_rt = m_rt;
87
88 list_add_tail(&m_rt->bus_node, &bus->m_rt_list);
89
90stream_config:
91 m_rt->ch_count = stream_config->ch_count;
92 m_rt->bus = bus;
93 m_rt->stream = stream;
94 m_rt->direction = stream_config->direction;
95
96 return m_rt;
97}
98
99/**
100 * sdw_alloc_slave_rt() - Allocate and initialize Slave runtime handle.
101 *
102 * @slave: Slave handle
103 * @stream_config: Stream configuration
104 * @stream: Stream runtime handle
105 *
106 * This function is to be called with bus_lock held.
107 */
108static struct sdw_slave_runtime
109*sdw_alloc_slave_rt(struct sdw_slave *slave,
110 struct sdw_stream_config *stream_config,
111 struct sdw_stream_runtime *stream)
112{
113 struct sdw_slave_runtime *s_rt = NULL;
114
115 s_rt = kzalloc(sizeof(*s_rt), GFP_KERNEL);
116 if (!s_rt)
117 return NULL;
118
Sanyog Kalebbe73792018-04-26 18:38:13 +0530119 INIT_LIST_HEAD(&s_rt->port_list);
Sanyog Kale89e59052018-04-26 18:38:08 +0530120 s_rt->ch_count = stream_config->ch_count;
121 s_rt->direction = stream_config->direction;
122 s_rt->slave = slave;
123
124 return s_rt;
125}
126
Sanyog Kalebbe73792018-04-26 18:38:13 +0530127static void sdw_master_port_release(struct sdw_bus *bus,
128 struct sdw_master_runtime *m_rt)
129{
130 struct sdw_port_runtime *p_rt, *_p_rt;
131
132 list_for_each_entry_safe(p_rt, _p_rt,
133 &m_rt->port_list, port_node) {
134 list_del(&p_rt->port_node);
135 kfree(p_rt);
136 }
137}
138
139static void sdw_slave_port_release(struct sdw_bus *bus,
140 struct sdw_slave *slave,
141 struct sdw_stream_runtime *stream)
142{
143 struct sdw_port_runtime *p_rt, *_p_rt;
144 struct sdw_master_runtime *m_rt = stream->m_rt;
145 struct sdw_slave_runtime *s_rt;
146
147 list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
148 if (s_rt->slave != slave)
149 continue;
150
151 list_for_each_entry_safe(p_rt, _p_rt,
152 &s_rt->port_list, port_node) {
153 list_del(&p_rt->port_node);
154 kfree(p_rt);
155 }
156 }
157}
158
Sanyog Kale89e59052018-04-26 18:38:08 +0530159/**
160 * sdw_release_slave_stream() - Free Slave(s) runtime handle
161 *
162 * @slave: Slave handle.
163 * @stream: Stream runtime handle.
164 *
165 * This function is to be called with bus_lock held.
166 */
167static void sdw_release_slave_stream(struct sdw_slave *slave,
168 struct sdw_stream_runtime *stream)
169{
170 struct sdw_slave_runtime *s_rt, *_s_rt;
171 struct sdw_master_runtime *m_rt = stream->m_rt;
172
173 /* Retrieve Slave runtime handle */
174 list_for_each_entry_safe(s_rt, _s_rt,
175 &m_rt->slave_rt_list, m_rt_node) {
176
177 if (s_rt->slave == slave) {
178 list_del(&s_rt->m_rt_node);
179 kfree(s_rt);
180 return;
181 }
182 }
183}
184
185/**
186 * sdw_release_master_stream() - Free Master runtime handle
187 *
188 * @stream: Stream runtime handle.
189 *
190 * This function is to be called with bus_lock held
191 * It frees the Master runtime handle and associated Slave(s) runtime
192 * handle. If this is called first then sdw_release_slave_stream() will have
193 * no effect as Slave(s) runtime handle would already be freed up.
194 */
195static void sdw_release_master_stream(struct sdw_stream_runtime *stream)
196{
197 struct sdw_master_runtime *m_rt = stream->m_rt;
198 struct sdw_slave_runtime *s_rt, *_s_rt;
199
200 list_for_each_entry_safe(s_rt, _s_rt,
201 &m_rt->slave_rt_list, m_rt_node)
202 sdw_stream_remove_slave(s_rt->slave, stream);
203
204 list_del(&m_rt->bus_node);
205}
206
207/**
208 * sdw_stream_remove_master() - Remove master from sdw_stream
209 *
210 * @bus: SDW Bus instance
211 * @stream: SoundWire stream
212 *
Sanyog Kalebbe73792018-04-26 18:38:13 +0530213 * This removes and frees port_rt and master_rt from a stream
Sanyog Kale89e59052018-04-26 18:38:08 +0530214 */
215int sdw_stream_remove_master(struct sdw_bus *bus,
216 struct sdw_stream_runtime *stream)
217{
218 mutex_lock(&bus->bus_lock);
219
220 sdw_release_master_stream(stream);
Sanyog Kalebbe73792018-04-26 18:38:13 +0530221 sdw_master_port_release(bus, stream->m_rt);
Sanyog Kale89e59052018-04-26 18:38:08 +0530222 stream->state = SDW_STREAM_RELEASED;
223 kfree(stream->m_rt);
224 stream->m_rt = NULL;
225
226 mutex_unlock(&bus->bus_lock);
227
228 return 0;
229}
230EXPORT_SYMBOL(sdw_stream_remove_master);
231
232/**
233 * sdw_stream_remove_slave() - Remove slave from sdw_stream
234 *
235 * @slave: SDW Slave instance
236 * @stream: SoundWire stream
237 *
Sanyog Kalebbe73792018-04-26 18:38:13 +0530238 * This removes and frees port_rt and slave_rt from a stream
Sanyog Kale89e59052018-04-26 18:38:08 +0530239 */
240int sdw_stream_remove_slave(struct sdw_slave *slave,
241 struct sdw_stream_runtime *stream)
242{
243 mutex_lock(&slave->bus->bus_lock);
244
Sanyog Kalebbe73792018-04-26 18:38:13 +0530245 sdw_slave_port_release(slave->bus, slave, stream);
Sanyog Kale89e59052018-04-26 18:38:08 +0530246 sdw_release_slave_stream(slave, stream);
247
248 mutex_unlock(&slave->bus->bus_lock);
249
250 return 0;
251}
252EXPORT_SYMBOL(sdw_stream_remove_slave);
253
254/**
255 * sdw_config_stream() - Configure the allocated stream
256 *
257 * @dev: SDW device
258 * @stream: SoundWire stream
259 * @stream_config: Stream configuration for audio stream
260 * @is_slave: is API called from Slave or Master
261 *
262 * This function is to be called with bus_lock held.
263 */
264static int sdw_config_stream(struct device *dev,
265 struct sdw_stream_runtime *stream,
266 struct sdw_stream_config *stream_config, bool is_slave)
267{
268 /*
269 * Update the stream rate, channel and bps based on data
270 * source. For more than one data source (multilink),
271 * match the rate, bps, stream type and increment number of channels.
272 *
273 * If rate/bps is zero, it means the values are not set, so skip
274 * comparison and allow the value to be set and stored in stream
275 */
276 if (stream->params.rate &&
277 stream->params.rate != stream_config->frame_rate) {
278 dev_err(dev, "rate not matching, stream:%s", stream->name);
279 return -EINVAL;
280 }
281
282 if (stream->params.bps &&
283 stream->params.bps != stream_config->bps) {
284 dev_err(dev, "bps not matching, stream:%s", stream->name);
285 return -EINVAL;
286 }
287
288 stream->type = stream_config->type;
289 stream->params.rate = stream_config->frame_rate;
290 stream->params.bps = stream_config->bps;
291
292 /* TODO: Update this check during Device-device support */
293 if (is_slave)
294 stream->params.ch_count += stream_config->ch_count;
295
296 return 0;
297}
298
Sanyog Kalebbe73792018-04-26 18:38:13 +0530299static int sdw_is_valid_port_range(struct device *dev,
300 struct sdw_port_runtime *p_rt)
301{
302 if (!SDW_VALID_PORT_RANGE(p_rt->num)) {
303 dev_err(dev,
304 "SoundWire: Invalid port number :%d", p_rt->num);
305 return -EINVAL;
306 }
307
308 return 0;
309}
310
311static struct sdw_port_runtime *sdw_port_alloc(struct device *dev,
312 struct sdw_port_config *port_config,
313 int port_index)
314{
315 struct sdw_port_runtime *p_rt;
316
317 p_rt = kzalloc(sizeof(*p_rt), GFP_KERNEL);
318 if (!p_rt)
319 return NULL;
320
321 p_rt->ch_mask = port_config[port_index].ch_mask;
322 p_rt->num = port_config[port_index].num;
323
324 return p_rt;
325}
326
327static int sdw_master_port_config(struct sdw_bus *bus,
328 struct sdw_master_runtime *m_rt,
329 struct sdw_port_config *port_config,
330 unsigned int num_ports)
331{
332 struct sdw_port_runtime *p_rt;
333 int i;
334
335 /* Iterate for number of ports to perform initialization */
336 for (i = 0; i < num_ports; i++) {
337 p_rt = sdw_port_alloc(bus->dev, port_config, i);
338 if (!p_rt)
339 return -ENOMEM;
340
341 /*
342 * TODO: Check port capabilities for requested
343 * configuration (audio mode support)
344 */
345
346 list_add_tail(&p_rt->port_node, &m_rt->port_list);
347 }
348
349 return 0;
350}
351
352static int sdw_slave_port_config(struct sdw_slave *slave,
353 struct sdw_slave_runtime *s_rt,
354 struct sdw_port_config *port_config,
355 unsigned int num_config)
356{
357 struct sdw_port_runtime *p_rt;
358 int i, ret;
359
360 /* Iterate for number of ports to perform initialization */
361 for (i = 0; i < num_config; i++) {
362 p_rt = sdw_port_alloc(&slave->dev, port_config, i);
363 if (!p_rt)
364 return -ENOMEM;
365
366 /*
367 * TODO: Check valid port range as defined by DisCo/
368 * slave
369 */
370 ret = sdw_is_valid_port_range(&slave->dev, p_rt);
371 if (ret < 0) {
372 kfree(p_rt);
373 return ret;
374 }
375
376 /*
377 * TODO: Check port capabilities for requested
378 * configuration (audio mode support)
379 */
380
381 list_add_tail(&p_rt->port_node, &s_rt->port_list);
382 }
383
384 return 0;
385}
386
Sanyog Kale89e59052018-04-26 18:38:08 +0530387/**
388 * sdw_stream_add_master() - Allocate and add master runtime to a stream
389 *
390 * @bus: SDW Bus instance
391 * @stream_config: Stream configuration for audio stream
Sanyog Kalebbe73792018-04-26 18:38:13 +0530392 * @port_config: Port configuration for audio stream
393 * @num_ports: Number of ports
Sanyog Kale89e59052018-04-26 18:38:08 +0530394 * @stream: SoundWire stream
395 */
396int sdw_stream_add_master(struct sdw_bus *bus,
397 struct sdw_stream_config *stream_config,
Sanyog Kalebbe73792018-04-26 18:38:13 +0530398 struct sdw_port_config *port_config,
399 unsigned int num_ports,
Sanyog Kale89e59052018-04-26 18:38:08 +0530400 struct sdw_stream_runtime *stream)
401{
402 struct sdw_master_runtime *m_rt = NULL;
403 int ret;
404
405 mutex_lock(&bus->bus_lock);
406
407 m_rt = sdw_alloc_master_rt(bus, stream_config, stream);
408 if (!m_rt) {
409 dev_err(bus->dev,
410 "Master runtime config failed for stream:%s",
411 stream->name);
412 ret = -ENOMEM;
413 goto error;
414 }
415
416 ret = sdw_config_stream(bus->dev, stream, stream_config, false);
417 if (ret)
418 goto stream_error;
419
Sanyog Kalebbe73792018-04-26 18:38:13 +0530420 ret = sdw_master_port_config(bus, m_rt, port_config, num_ports);
421 if (ret)
422 goto stream_error;
423
Sanyog Kale89e59052018-04-26 18:38:08 +0530424 stream->state = SDW_STREAM_CONFIGURED;
425
426stream_error:
427 sdw_release_master_stream(stream);
428error:
429 mutex_unlock(&bus->bus_lock);
430 return ret;
431}
432EXPORT_SYMBOL(sdw_stream_add_master);
433
434/**
435 * sdw_stream_add_slave() - Allocate and add master/slave runtime to a stream
436 *
437 * @slave: SDW Slave instance
438 * @stream_config: Stream configuration for audio stream
439 * @stream: SoundWire stream
Sanyog Kalebbe73792018-04-26 18:38:13 +0530440 * @port_config: Port configuration for audio stream
441 * @num_ports: Number of ports
Sanyog Kale89e59052018-04-26 18:38:08 +0530442 */
443int sdw_stream_add_slave(struct sdw_slave *slave,
444 struct sdw_stream_config *stream_config,
Sanyog Kalebbe73792018-04-26 18:38:13 +0530445 struct sdw_port_config *port_config,
446 unsigned int num_ports,
Sanyog Kale89e59052018-04-26 18:38:08 +0530447 struct sdw_stream_runtime *stream)
448{
449 struct sdw_slave_runtime *s_rt;
450 struct sdw_master_runtime *m_rt;
451 int ret;
452
453 mutex_lock(&slave->bus->bus_lock);
454
455 /*
456 * If this API is invoked by Slave first then m_rt is not valid.
457 * So, allocate m_rt and add Slave to it.
458 */
459 m_rt = sdw_alloc_master_rt(slave->bus, stream_config, stream);
460 if (!m_rt) {
461 dev_err(&slave->dev,
462 "alloc master runtime failed for stream:%s",
463 stream->name);
464 ret = -ENOMEM;
465 goto error;
466 }
467
468 s_rt = sdw_alloc_slave_rt(slave, stream_config, stream);
469 if (!s_rt) {
470 dev_err(&slave->dev,
471 "Slave runtime config failed for stream:%s",
472 stream->name);
473 ret = -ENOMEM;
474 goto stream_error;
475 }
476
477 ret = sdw_config_stream(&slave->dev, stream, stream_config, true);
478 if (ret)
479 goto stream_error;
480
481 list_add_tail(&s_rt->m_rt_node, &m_rt->slave_rt_list);
482
Sanyog Kalebbe73792018-04-26 18:38:13 +0530483 ret = sdw_slave_port_config(slave, s_rt, port_config, num_ports);
484 if (ret)
485 goto stream_error;
486
Sanyog Kale89e59052018-04-26 18:38:08 +0530487 stream->state = SDW_STREAM_CONFIGURED;
488 goto error;
489
490stream_error:
491 /*
492 * we hit error so cleanup the stream, release all Slave(s) and
493 * Master runtime
494 */
495 sdw_release_master_stream(stream);
496error:
497 mutex_unlock(&slave->bus->bus_lock);
498 return ret;
499}
500EXPORT_SYMBOL(sdw_stream_add_slave);