1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // soc-dai.c
4 //
5 // Copyright (C) 2019 Renesas Electronics Corp.
6 // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
7 //
8
9 #include <sound/soc.h>
10 #include <sound/soc-dai.h>
11 #include <sound/soc-link.h>
12
13 #define soc_dai_ret(dai, ret) _soc_dai_ret(dai, __func__, ret)
_soc_dai_ret(const struct snd_soc_dai * dai,const char * func,int ret)14 static inline int _soc_dai_ret(const struct snd_soc_dai *dai,
15 const char *func, int ret)
16 {
17 return snd_soc_ret(dai->dev, ret,
18 "at %s() on %s\n", func, dai->name);
19 }
20
21 /*
22 * We might want to check substream by using list.
23 * In such case, we can update these macros.
24 */
25 #define soc_dai_mark_push(dai, substream, tgt) ((dai)->mark_##tgt = substream)
26 #define soc_dai_mark_pop(dai, tgt) ((dai)->mark_##tgt = NULL)
27 #define soc_dai_mark_match(dai, substream, tgt) ((dai)->mark_##tgt == substream)
28
29 /**
30 * snd_soc_dai_set_sysclk - configure DAI system or master clock.
31 * @dai: DAI
32 * @clk_id: DAI specific clock ID
33 * @freq: new clock frequency in Hz
34 * @dir: new clock direction (SND_SOC_CLOCK_IN or SND_SOC_CLOCK_OUT)
35 *
36 * Configures the DAI master (MCLK) or system (SYSCLK) clocking.
37 */
snd_soc_dai_set_sysclk(struct snd_soc_dai * dai,int clk_id,unsigned int freq,int dir)38 int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
39 unsigned int freq, int dir)
40 {
41 int ret;
42
43 if (dai->driver->ops &&
44 dai->driver->ops->set_sysclk)
45 ret = dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
46 else
47 ret = snd_soc_component_set_sysclk(dai->component, clk_id, 0,
48 freq, dir);
49
50 return soc_dai_ret(dai, ret);
51 }
52 EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
53
54 /**
55 * snd_soc_dai_set_clkdiv - configure DAI clock dividers.
56 * @dai: DAI
57 * @div_id: DAI specific clock divider ID
58 * @div: new clock divisor.
59 *
60 * Configures the clock dividers. This is used to derive the best DAI bit and
61 * frame clocks from the system or master clock. It's best to set the DAI bit
62 * and frame clocks as low as possible to save system power.
63 */
snd_soc_dai_set_clkdiv(struct snd_soc_dai * dai,int div_id,int div)64 int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
65 int div_id, int div)
66 {
67 int ret = -EINVAL;
68
69 if (dai->driver->ops &&
70 dai->driver->ops->set_clkdiv)
71 ret = dai->driver->ops->set_clkdiv(dai, div_id, div);
72
73 return soc_dai_ret(dai, ret);
74 }
75 EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
76
77 /**
78 * snd_soc_dai_set_pll - configure DAI PLL.
79 * @dai: DAI
80 * @pll_id: DAI specific PLL ID
81 * @source: DAI specific source for the PLL
82 * @freq_in: PLL input clock frequency in Hz
83 * @freq_out: requested PLL output clock frequency in Hz
84 *
85 * Configures and enables PLL to generate output clock based on input clock.
86 */
snd_soc_dai_set_pll(struct snd_soc_dai * dai,int pll_id,int source,unsigned int freq_in,unsigned int freq_out)87 int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
88 unsigned int freq_in, unsigned int freq_out)
89 {
90 int ret;
91
92 if (dai->driver->ops &&
93 dai->driver->ops->set_pll)
94 ret = dai->driver->ops->set_pll(dai, pll_id, source,
95 freq_in, freq_out);
96 else
97 ret = snd_soc_component_set_pll(dai->component, pll_id, source,
98 freq_in, freq_out);
99
100 return soc_dai_ret(dai, ret);
101 }
102 EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
103
104 /**
105 * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio.
106 * @dai: DAI
107 * @ratio: Ratio of BCLK to Sample rate.
108 *
109 * Configures the DAI for a preset BCLK to sample rate ratio.
110 */
snd_soc_dai_set_bclk_ratio(struct snd_soc_dai * dai,unsigned int ratio)111 int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
112 {
113 int ret = -ENOTSUPP;
114
115 if (dai->driver->ops &&
116 dai->driver->ops->set_bclk_ratio)
117 ret = dai->driver->ops->set_bclk_ratio(dai, ratio);
118
119 return soc_dai_ret(dai, ret);
120 }
121 EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio);
122
snd_soc_dai_get_fmt_max_priority(const struct snd_soc_pcm_runtime * rtd)123 int snd_soc_dai_get_fmt_max_priority(const struct snd_soc_pcm_runtime *rtd)
124 {
125 struct snd_soc_dai *dai;
126 int i, max = 0;
127
128 /*
129 * return max num if *ALL* DAIs have .auto_selectable_formats
130 */
131 for_each_rtd_dais(rtd, i, dai) {
132 if (dai->driver->ops &&
133 dai->driver->ops->num_auto_selectable_formats)
134 max = max(max, dai->driver->ops->num_auto_selectable_formats);
135 else
136 return 0;
137 }
138
139 return max;
140 }
141
142 /**
143 * snd_soc_dai_get_fmt - get supported audio format.
144 * @dai: DAI
145 * @priority: priority level of supported audio format.
146 *
147 * This should return only formats implemented with high
148 * quality by the DAI so that the core can configure a
149 * format which will work well with other devices.
150 * For example devices which don't support both edges of the
151 * LRCLK signal in I2S style formats should only list DSP
152 * modes. This will mean that sometimes fewer formats
153 * are reported here than are supported by set_fmt().
154 */
snd_soc_dai_get_fmt(const struct snd_soc_dai * dai,int priority)155 u64 snd_soc_dai_get_fmt(const struct snd_soc_dai *dai, int priority)
156 {
157 const struct snd_soc_dai_ops *ops = dai->driver->ops;
158 u64 fmt = 0;
159 int i, max = 0, until = priority;
160
161 /*
162 * Collect auto_selectable_formats until priority
163 *
164 * ex)
165 * auto_selectable_formats[] = { A, B, C };
166 * (A, B, C = SND_SOC_POSSIBLE_DAIFMT_xxx)
167 *
168 * priority = 1 : A
169 * priority = 2 : A | B
170 * priority = 3 : A | B | C
171 * priority = 4 : A | B | C
172 * ...
173 */
174 if (ops)
175 max = ops->num_auto_selectable_formats;
176
177 if (max < until)
178 until = max;
179
180 for (i = 0; i < until; i++)
181 fmt |= ops->auto_selectable_formats[i];
182
183 return fmt;
184 }
185
186 /**
187 * snd_soc_dai_set_fmt - configure DAI hardware audio format.
188 * @dai: DAI
189 * @fmt: SND_SOC_DAIFMT_* format value.
190 *
191 * Configures the DAI hardware format and clocking.
192 */
snd_soc_dai_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)193 int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
194 {
195 int ret = -ENOTSUPP;
196
197 if (dai->driver->ops && dai->driver->ops->set_fmt)
198 ret = dai->driver->ops->set_fmt(dai, fmt);
199
200 return soc_dai_ret(dai, ret);
201 }
202 EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
203
204 /**
205 * snd_soc_xlate_tdm_slot_mask - generate tx/rx slot mask.
206 * @slots: Number of slots in use.
207 * @tx_mask: bitmask representing active TX slots.
208 * @rx_mask: bitmask representing active RX slots.
209 *
210 * Generates the TDM tx and rx slot default masks for DAI.
211 */
snd_soc_xlate_tdm_slot_mask(unsigned int slots,unsigned int * tx_mask,unsigned int * rx_mask)212 static int snd_soc_xlate_tdm_slot_mask(unsigned int slots,
213 unsigned int *tx_mask,
214 unsigned int *rx_mask)
215 {
216 if (*tx_mask || *rx_mask)
217 return 0;
218
219 if (!slots)
220 return -EINVAL;
221
222 *tx_mask = (1 << slots) - 1;
223 *rx_mask = (1 << slots) - 1;
224
225 return 0;
226 }
227
228 /**
229 * snd_soc_dai_set_tdm_slot() - Configures a DAI for TDM operation
230 * @dai: The DAI to configure
231 * @tx_mask: bitmask representing active TX slots.
232 * @rx_mask: bitmask representing active RX slots.
233 * @slots: Number of slots in use.
234 * @slot_width: Width in bits for each slot.
235 *
236 * This function configures the specified DAI for TDM operation. @slot contains
237 * the total number of slots of the TDM stream and @slot_with the width of each
238 * slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the
239 * active slots of the TDM stream for the specified DAI, i.e. which slots the
240 * DAI should write to or read from. If a bit is set the corresponding slot is
241 * active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to
242 * the first slot, bit 1 to the second slot and so on. The first active slot
243 * maps to the first channel of the DAI, the second active slot to the second
244 * channel and so on.
245 *
246 * TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask,
247 * @rx_mask and @slot_width will be ignored.
248 *
249 * Returns 0 on success, a negative error code otherwise.
250 */
snd_soc_dai_set_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)251 int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
252 unsigned int tx_mask, unsigned int rx_mask,
253 int slots, int slot_width)
254 {
255 int ret = -ENOTSUPP;
256 int stream;
257 unsigned int *tdm_mask[] = {
258 &tx_mask,
259 &rx_mask,
260 };
261
262 if (dai->driver->ops &&
263 dai->driver->ops->xlate_tdm_slot_mask)
264 ret = dai->driver->ops->xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
265 else
266 ret = snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
267 if (ret)
268 goto err;
269
270 for_each_pcm_streams(stream)
271 snd_soc_dai_tdm_mask_set(dai, stream, *tdm_mask[stream]);
272
273 if (dai->driver->ops &&
274 dai->driver->ops->set_tdm_slot)
275 ret = dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
276 slots, slot_width);
277 err:
278 return soc_dai_ret(dai, ret);
279 }
280 EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
281
282 /**
283 * snd_soc_dai_set_channel_map - configure DAI audio channel map
284 * @dai: DAI
285 * @tx_num: how many TX channels
286 * @tx_slot: pointer to an array which imply the TX slot number channel
287 * 0~num-1 uses
288 * @rx_num: how many RX channels
289 * @rx_slot: pointer to an array which imply the RX slot number channel
290 * 0~num-1 uses
291 *
292 * configure the relationship between channel number and TDM slot number.
293 */
snd_soc_dai_set_channel_map(struct snd_soc_dai * dai,unsigned int tx_num,const unsigned int * tx_slot,unsigned int rx_num,const unsigned int * rx_slot)294 int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
295 unsigned int tx_num, const unsigned int *tx_slot,
296 unsigned int rx_num, const unsigned int *rx_slot)
297 {
298 int ret = -ENOTSUPP;
299
300 if (dai->driver->ops &&
301 dai->driver->ops->set_channel_map)
302 ret = dai->driver->ops->set_channel_map(dai, tx_num, tx_slot,
303 rx_num, rx_slot);
304 return soc_dai_ret(dai, ret);
305 }
306 EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
307
308 /**
309 * snd_soc_dai_get_channel_map - Get DAI audio channel map
310 * @dai: DAI
311 * @tx_num: how many TX channels
312 * @tx_slot: pointer to an array which imply the TX slot number channel
313 * 0~num-1 uses
314 * @rx_num: how many RX channels
315 * @rx_slot: pointer to an array which imply the RX slot number channel
316 * 0~num-1 uses
317 */
snd_soc_dai_get_channel_map(const struct snd_soc_dai * dai,unsigned int * tx_num,unsigned int * tx_slot,unsigned int * rx_num,unsigned int * rx_slot)318 int snd_soc_dai_get_channel_map(const struct snd_soc_dai *dai,
319 unsigned int *tx_num, unsigned int *tx_slot,
320 unsigned int *rx_num, unsigned int *rx_slot)
321 {
322 int ret = -ENOTSUPP;
323
324 if (dai->driver->ops &&
325 dai->driver->ops->get_channel_map)
326 ret = dai->driver->ops->get_channel_map(dai, tx_num, tx_slot,
327 rx_num, rx_slot);
328 return soc_dai_ret(dai, ret);
329 }
330 EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map);
331
332 /**
333 * snd_soc_dai_set_tristate - configure DAI system or master clock.
334 * @dai: DAI
335 * @tristate: tristate enable
336 *
337 * Tristates the DAI so that others can use it.
338 */
snd_soc_dai_set_tristate(struct snd_soc_dai * dai,int tristate)339 int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
340 {
341 int ret = -EINVAL;
342
343 if (dai->driver->ops &&
344 dai->driver->ops->set_tristate)
345 ret = dai->driver->ops->set_tristate(dai, tristate);
346
347 return soc_dai_ret(dai, ret);
348 }
349 EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
350
snd_soc_dai_prepare(struct snd_soc_dai * dai,struct snd_pcm_substream * substream)351 int snd_soc_dai_prepare(struct snd_soc_dai *dai,
352 struct snd_pcm_substream *substream)
353 {
354 int ret = 0;
355
356 if (!snd_soc_dai_stream_valid(dai, substream->stream))
357 return 0;
358
359 if (dai->driver->ops &&
360 dai->driver->ops->prepare)
361 ret = dai->driver->ops->prepare(substream, dai);
362
363 return soc_dai_ret(dai, ret);
364 }
365 EXPORT_SYMBOL_GPL(snd_soc_dai_prepare);
366
snd_soc_dai_mute_is_ctrled_at_trigger(struct snd_soc_dai * dai)367 int snd_soc_dai_mute_is_ctrled_at_trigger(struct snd_soc_dai *dai)
368 {
369 if (dai->driver->ops)
370 return dai->driver->ops->mute_unmute_on_trigger;
371
372 return 0;
373 }
374
375 /**
376 * snd_soc_dai_digital_mute - configure DAI system or master clock.
377 * @dai: DAI
378 * @mute: mute enable
379 * @direction: stream to mute
380 *
381 * Mutes the DAI DAC.
382 */
snd_soc_dai_digital_mute(struct snd_soc_dai * dai,int mute,int direction)383 int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
384 int direction)
385 {
386 int ret = -ENOTSUPP;
387
388 /*
389 * ignore if direction was CAPTURE
390 * and it had .no_capture_mute flag
391 */
392 if (dai->driver->ops &&
393 dai->driver->ops->mute_stream &&
394 (direction == SNDRV_PCM_STREAM_PLAYBACK ||
395 !dai->driver->ops->no_capture_mute))
396 ret = dai->driver->ops->mute_stream(dai, mute, direction);
397
398 return soc_dai_ret(dai, ret);
399 }
400 EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
401
snd_soc_dai_hw_params(struct snd_soc_dai * dai,struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)402 int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
403 struct snd_pcm_substream *substream,
404 struct snd_pcm_hw_params *params)
405 {
406 int ret = 0;
407
408 if (dai->driver->ops &&
409 dai->driver->ops->hw_params)
410 ret = dai->driver->ops->hw_params(substream, params, dai);
411
412 /* mark substream if succeeded */
413 if (ret == 0)
414 soc_dai_mark_push(dai, substream, hw_params);
415
416 return soc_dai_ret(dai, ret);
417 }
418
snd_soc_dai_hw_free(struct snd_soc_dai * dai,struct snd_pcm_substream * substream,int rollback)419 void snd_soc_dai_hw_free(struct snd_soc_dai *dai,
420 struct snd_pcm_substream *substream,
421 int rollback)
422 {
423 if (rollback && !soc_dai_mark_match(dai, substream, hw_params))
424 return;
425
426 if (dai->driver->ops &&
427 dai->driver->ops->hw_free)
428 dai->driver->ops->hw_free(substream, dai);
429
430 /* remove marked substream */
431 soc_dai_mark_pop(dai, hw_params);
432 }
433
snd_soc_dai_startup(struct snd_soc_dai * dai,struct snd_pcm_substream * substream)434 int snd_soc_dai_startup(struct snd_soc_dai *dai,
435 struct snd_pcm_substream *substream)
436 {
437 int ret = 0;
438
439 if (!snd_soc_dai_stream_valid(dai, substream->stream))
440 return 0;
441
442 if (dai->driver->ops &&
443 dai->driver->ops->startup)
444 ret = dai->driver->ops->startup(substream, dai);
445
446 /* mark substream if succeeded */
447 if (ret == 0)
448 soc_dai_mark_push(dai, substream, startup);
449
450 return soc_dai_ret(dai, ret);
451 }
452
snd_soc_dai_shutdown(struct snd_soc_dai * dai,struct snd_pcm_substream * substream,int rollback)453 void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
454 struct snd_pcm_substream *substream,
455 int rollback)
456 {
457 if (!snd_soc_dai_stream_valid(dai, substream->stream))
458 return;
459
460 if (rollback && !soc_dai_mark_match(dai, substream, startup))
461 return;
462
463 if (dai->driver->ops &&
464 dai->driver->ops->shutdown)
465 dai->driver->ops->shutdown(substream, dai);
466
467 /* remove marked substream */
468 soc_dai_mark_pop(dai, startup);
469 }
470
snd_soc_dai_compress_new(struct snd_soc_dai * dai,struct snd_soc_pcm_runtime * rtd)471 int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
472 struct snd_soc_pcm_runtime *rtd)
473 {
474 int ret = -ENOTSUPP;
475 if (dai->driver->ops &&
476 dai->driver->ops->compress_new)
477 ret = dai->driver->ops->compress_new(rtd);
478 return soc_dai_ret(dai, ret);
479 }
480
481 /*
482 * snd_soc_dai_stream_valid() - check if a DAI supports the given stream
483 *
484 * Returns true if the DAI supports the indicated stream type.
485 */
snd_soc_dai_stream_valid(const struct snd_soc_dai * dai,int dir)486 bool snd_soc_dai_stream_valid(const struct snd_soc_dai *dai, int dir)
487 {
488 const struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir);
489
490 /* If the codec specifies any channels at all, it supports the stream */
491 return stream->channels_min;
492 }
493
snd_soc_dai_action(struct snd_soc_dai * dai,int stream,int action)494 void snd_soc_dai_action(struct snd_soc_dai *dai,
495 int stream, int action)
496 {
497 /* see snd_soc_dai_stream_active() */
498 dai->stream[stream].active += action;
499
500 /* see snd_soc_component_active() */
501 dai->component->active += action;
502 }
503 EXPORT_SYMBOL_GPL(snd_soc_dai_action);
504
snd_soc_dai_active(const struct snd_soc_dai * dai)505 int snd_soc_dai_active(const struct snd_soc_dai *dai)
506 {
507 int stream, active;
508
509 active = 0;
510 for_each_pcm_streams(stream)
511 active += dai->stream[stream].active;
512
513 return active;
514 }
515 EXPORT_SYMBOL_GPL(snd_soc_dai_active);
516
snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime * rtd,int order)517 int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order)
518 {
519 struct snd_soc_dai *dai;
520 int i;
521
522 for_each_rtd_dais(rtd, i, dai) {
523 if (dai->probed)
524 continue;
525
526 if (dai->driver->ops) {
527 if (dai->driver->ops->probe_order != order)
528 continue;
529
530 if (dai->driver->ops->probe) {
531 int ret = dai->driver->ops->probe(dai);
532
533 if (ret < 0)
534 return soc_dai_ret(dai, ret);
535 }
536 }
537 dai->probed = 1;
538 }
539
540 return 0;
541 }
542
snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime * rtd,int order)543 int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order)
544 {
545 struct snd_soc_dai *dai;
546 int i, r, ret = 0;
547
548 for_each_rtd_dais(rtd, i, dai) {
549 if (!dai->probed)
550 continue;
551
552 if (dai->driver->ops) {
553 if (dai->driver->ops->remove_order != order)
554 continue;
555
556 if (dai->driver->ops->remove) {
557 r = dai->driver->ops->remove(dai);
558 if (r < 0)
559 ret = r; /* use last error */
560 }
561 }
562 dai->probed = 0;
563 }
564
565 return ret;
566 }
567
snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime * rtd)568 int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd)
569 {
570 struct snd_soc_dai *dai;
571 int i;
572
573 for_each_rtd_dais(rtd, i, dai) {
574 if (dai->driver->ops &&
575 dai->driver->ops->pcm_new) {
576 int ret = dai->driver->ops->pcm_new(rtd, dai);
577 if (ret < 0)
578 return soc_dai_ret(dai, ret);
579 }
580 }
581
582 return 0;
583 }
584
snd_soc_pcm_dai_prepare(struct snd_pcm_substream * substream)585 int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream)
586 {
587 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
588 struct snd_soc_dai *dai;
589 int i, ret;
590
591 for_each_rtd_dais(rtd, i, dai) {
592 ret = snd_soc_dai_prepare(dai, substream);
593 if (ret < 0)
594 return ret;
595 }
596
597 return 0;
598 }
599
soc_dai_trigger(struct snd_soc_dai * dai,struct snd_pcm_substream * substream,int cmd)600 static int soc_dai_trigger(struct snd_soc_dai *dai,
601 struct snd_pcm_substream *substream, int cmd)
602 {
603 int ret = 0;
604
605 if (!snd_soc_dai_stream_valid(dai, substream->stream))
606 return 0;
607
608 if (dai->driver->ops &&
609 dai->driver->ops->trigger)
610 ret = dai->driver->ops->trigger(substream, cmd, dai);
611
612 return soc_dai_ret(dai, ret);
613 }
614
snd_soc_pcm_dai_trigger(struct snd_pcm_substream * substream,int cmd,int rollback)615 int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream,
616 int cmd, int rollback)
617 {
618 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
619 struct snd_soc_dai *dai;
620 int i, r, ret = 0;
621
622 switch (cmd) {
623 case SNDRV_PCM_TRIGGER_START:
624 case SNDRV_PCM_TRIGGER_RESUME:
625 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
626 for_each_rtd_dais(rtd, i, dai) {
627 ret = soc_dai_trigger(dai, substream, cmd);
628 if (ret < 0)
629 break;
630
631 if (snd_soc_dai_mute_is_ctrled_at_trigger(dai))
632 snd_soc_dai_digital_mute(dai, 0, substream->stream);
633
634 soc_dai_mark_push(dai, substream, trigger);
635 }
636 break;
637 case SNDRV_PCM_TRIGGER_STOP:
638 case SNDRV_PCM_TRIGGER_SUSPEND:
639 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
640 for_each_rtd_dais(rtd, i, dai) {
641 if (rollback && !soc_dai_mark_match(dai, substream, trigger))
642 continue;
643
644 if (snd_soc_dai_mute_is_ctrled_at_trigger(dai))
645 snd_soc_dai_digital_mute(dai, 1, substream->stream);
646
647 r = soc_dai_trigger(dai, substream, cmd);
648 if (r < 0)
649 ret = r; /* use last ret */
650 soc_dai_mark_pop(dai, trigger);
651 }
652 }
653
654 return ret;
655 }
656
snd_soc_pcm_dai_delay(struct snd_pcm_substream * substream,snd_pcm_sframes_t * cpu_delay,snd_pcm_sframes_t * codec_delay)657 void snd_soc_pcm_dai_delay(struct snd_pcm_substream *substream,
658 snd_pcm_sframes_t *cpu_delay,
659 snd_pcm_sframes_t *codec_delay)
660 {
661 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
662 struct snd_soc_dai *dai;
663 int i;
664
665 /*
666 * We're looking for the delay through the full audio path so it needs to
667 * be the maximum of the DAIs doing transmit and the maximum of the DAIs
668 * doing receive (ie, all CPUs and all CODECs) rather than just the maximum
669 * of all DAIs.
670 */
671
672 /* for CPU */
673 for_each_rtd_cpu_dais(rtd, i, dai)
674 if (dai->driver->ops &&
675 dai->driver->ops->delay)
676 *cpu_delay = max(*cpu_delay, dai->driver->ops->delay(substream, dai));
677
678 /* for Codec */
679 for_each_rtd_codec_dais(rtd, i, dai)
680 if (dai->driver->ops &&
681 dai->driver->ops->delay)
682 *codec_delay = max(*codec_delay, dai->driver->ops->delay(substream, dai));
683 }
684
snd_soc_dai_compr_startup(struct snd_soc_dai * dai,struct snd_compr_stream * cstream)685 int snd_soc_dai_compr_startup(struct snd_soc_dai *dai,
686 struct snd_compr_stream *cstream)
687 {
688 int ret = 0;
689
690 if (dai->driver->cops &&
691 dai->driver->cops->startup)
692 ret = dai->driver->cops->startup(cstream, dai);
693
694 /* mark cstream if succeeded */
695 if (ret == 0)
696 soc_dai_mark_push(dai, cstream, compr_startup);
697
698 return soc_dai_ret(dai, ret);
699 }
700 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_startup);
701
snd_soc_dai_compr_shutdown(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,int rollback)702 void snd_soc_dai_compr_shutdown(struct snd_soc_dai *dai,
703 struct snd_compr_stream *cstream,
704 int rollback)
705 {
706 if (rollback && !soc_dai_mark_match(dai, cstream, compr_startup))
707 return;
708
709 if (dai->driver->cops &&
710 dai->driver->cops->shutdown)
711 dai->driver->cops->shutdown(cstream, dai);
712
713 /* remove marked cstream */
714 soc_dai_mark_pop(dai, compr_startup);
715 }
716 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_shutdown);
717
snd_soc_dai_compr_trigger(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,int cmd)718 int snd_soc_dai_compr_trigger(struct snd_soc_dai *dai,
719 struct snd_compr_stream *cstream, int cmd)
720 {
721 int ret = 0;
722
723 if (dai->driver->cops &&
724 dai->driver->cops->trigger)
725 ret = dai->driver->cops->trigger(cstream, cmd, dai);
726
727 return soc_dai_ret(dai, ret);
728 }
729 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_trigger);
730
snd_soc_dai_compr_set_params(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,struct snd_compr_params * params)731 int snd_soc_dai_compr_set_params(struct snd_soc_dai *dai,
732 struct snd_compr_stream *cstream,
733 struct snd_compr_params *params)
734 {
735 int ret = 0;
736
737 if (dai->driver->cops &&
738 dai->driver->cops->set_params)
739 ret = dai->driver->cops->set_params(cstream, params, dai);
740
741 return soc_dai_ret(dai, ret);
742 }
743 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_params);
744
snd_soc_dai_compr_get_params(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,struct snd_codec * params)745 int snd_soc_dai_compr_get_params(struct snd_soc_dai *dai,
746 struct snd_compr_stream *cstream,
747 struct snd_codec *params)
748 {
749 int ret = 0;
750
751 if (dai->driver->cops &&
752 dai->driver->cops->get_params)
753 ret = dai->driver->cops->get_params(cstream, params, dai);
754
755 return soc_dai_ret(dai, ret);
756 }
757 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_params);
758
snd_soc_dai_compr_ack(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,size_t bytes)759 int snd_soc_dai_compr_ack(struct snd_soc_dai *dai,
760 struct snd_compr_stream *cstream,
761 size_t bytes)
762 {
763 int ret = 0;
764
765 if (dai->driver->cops &&
766 dai->driver->cops->ack)
767 ret = dai->driver->cops->ack(cstream, bytes, dai);
768
769 return soc_dai_ret(dai, ret);
770 }
771 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_ack);
772
snd_soc_dai_compr_pointer(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,struct snd_compr_tstamp * tstamp)773 int snd_soc_dai_compr_pointer(struct snd_soc_dai *dai,
774 struct snd_compr_stream *cstream,
775 struct snd_compr_tstamp *tstamp)
776 {
777 int ret = 0;
778
779 if (dai->driver->cops &&
780 dai->driver->cops->pointer)
781 ret = dai->driver->cops->pointer(cstream, tstamp, dai);
782
783 return soc_dai_ret(dai, ret);
784 }
785 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_pointer);
786
snd_soc_dai_compr_set_metadata(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,struct snd_compr_metadata * metadata)787 int snd_soc_dai_compr_set_metadata(struct snd_soc_dai *dai,
788 struct snd_compr_stream *cstream,
789 struct snd_compr_metadata *metadata)
790 {
791 int ret = 0;
792
793 if (dai->driver->cops &&
794 dai->driver->cops->set_metadata)
795 ret = dai->driver->cops->set_metadata(cstream, metadata, dai);
796
797 return soc_dai_ret(dai, ret);
798 }
799 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_metadata);
800
snd_soc_dai_compr_get_metadata(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,struct snd_compr_metadata * metadata)801 int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai,
802 struct snd_compr_stream *cstream,
803 struct snd_compr_metadata *metadata)
804 {
805 int ret = 0;
806
807 if (dai->driver->cops &&
808 dai->driver->cops->get_metadata)
809 ret = dai->driver->cops->get_metadata(cstream, metadata, dai);
810
811 return soc_dai_ret(dai, ret);
812 }
813 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_metadata);
814