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 if (ops && ops->auto_selectable_formats)
181 for (i = 0; i < until; i++)
182 fmt |= ops->auto_selectable_formats[i];
183
184 return fmt;
185 }
186
187 /**
188 * snd_soc_dai_set_fmt - configure DAI hardware audio format.
189 * @dai: DAI
190 * @fmt: SND_SOC_DAIFMT_* format value.
191 *
192 * Configures the DAI hardware format and clocking.
193 */
snd_soc_dai_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)194 int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
195 {
196 int ret = -ENOTSUPP;
197
198 if (dai->driver->ops && dai->driver->ops->set_fmt)
199 ret = dai->driver->ops->set_fmt(dai, fmt);
200
201 return soc_dai_ret(dai, ret);
202 }
203 EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
204
205 /**
206 * snd_soc_xlate_tdm_slot_mask - generate tx/rx slot mask.
207 * @slots: Number of slots in use.
208 * @tx_mask: bitmask representing active TX slots.
209 * @rx_mask: bitmask representing active RX slots.
210 *
211 * Generates the TDM tx and rx slot default masks for DAI.
212 */
snd_soc_xlate_tdm_slot_mask(unsigned int slots,unsigned int * tx_mask,unsigned int * rx_mask)213 static int snd_soc_xlate_tdm_slot_mask(unsigned int slots,
214 unsigned int *tx_mask,
215 unsigned int *rx_mask)
216 {
217 if (*tx_mask || *rx_mask)
218 return 0;
219
220 if (!slots)
221 return -EINVAL;
222
223 *tx_mask = (1 << slots) - 1;
224 *rx_mask = (1 << slots) - 1;
225
226 return 0;
227 }
228
229 /**
230 * snd_soc_dai_set_tdm_slot() - Configures a DAI for TDM operation
231 * @dai: The DAI to configure
232 * @tx_mask: bitmask representing active TX slots.
233 * @rx_mask: bitmask representing active RX slots.
234 * @slots: Number of slots in use.
235 * @slot_width: Width in bits for each slot.
236 *
237 * This function configures the specified DAI for TDM operation. @slot contains
238 * the total number of slots of the TDM stream and @slot_with the width of each
239 * slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the
240 * active slots of the TDM stream for the specified DAI, i.e. which slots the
241 * DAI should write to or read from. If a bit is set the corresponding slot is
242 * active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to
243 * the first slot, bit 1 to the second slot and so on. The first active slot
244 * maps to the first channel of the DAI, the second active slot to the second
245 * channel and so on.
246 *
247 * TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask,
248 * @rx_mask and @slot_width will be ignored.
249 *
250 * Returns 0 on success, a negative error code otherwise.
251 */
snd_soc_dai_set_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)252 int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
253 unsigned int tx_mask, unsigned int rx_mask,
254 int slots, int slot_width)
255 {
256 int ret = -ENOTSUPP;
257 int stream;
258 unsigned int *tdm_mask[] = {
259 &tx_mask,
260 &rx_mask,
261 };
262
263 if (slots) {
264 if (dai->driver->ops &&
265 dai->driver->ops->xlate_tdm_slot_mask)
266 ret = dai->driver->ops->xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
267 else
268 ret = snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
269 if (ret)
270 goto err;
271 }
272
273 for_each_pcm_streams(stream)
274 snd_soc_dai_tdm_mask_set(dai, stream, *tdm_mask[stream]);
275
276 if (dai->driver->ops &&
277 dai->driver->ops->set_tdm_slot)
278 ret = dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
279 slots, slot_width);
280 err:
281 return soc_dai_ret(dai, ret);
282 }
283 EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
284
285 /**
286 * snd_soc_dai_set_channel_map - configure DAI audio channel map
287 * @dai: DAI
288 * @tx_num: how many TX channels
289 * @tx_slot: pointer to an array which imply the TX slot number channel
290 * 0~num-1 uses
291 * @rx_num: how many RX channels
292 * @rx_slot: pointer to an array which imply the RX slot number channel
293 * 0~num-1 uses
294 *
295 * configure the relationship between channel number and TDM slot number.
296 */
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)297 int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
298 unsigned int tx_num, const unsigned int *tx_slot,
299 unsigned int rx_num, const unsigned int *rx_slot)
300 {
301 int ret = -ENOTSUPP;
302
303 if (dai->driver->ops &&
304 dai->driver->ops->set_channel_map)
305 ret = dai->driver->ops->set_channel_map(dai, tx_num, tx_slot,
306 rx_num, rx_slot);
307 return soc_dai_ret(dai, ret);
308 }
309 EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
310
311 /**
312 * snd_soc_dai_get_channel_map - Get DAI audio channel map
313 * @dai: DAI
314 * @tx_num: how many TX channels
315 * @tx_slot: pointer to an array which imply the TX slot number channel
316 * 0~num-1 uses
317 * @rx_num: how many RX channels
318 * @rx_slot: pointer to an array which imply the RX slot number channel
319 * 0~num-1 uses
320 */
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)321 int snd_soc_dai_get_channel_map(const struct snd_soc_dai *dai,
322 unsigned int *tx_num, unsigned int *tx_slot,
323 unsigned int *rx_num, unsigned int *rx_slot)
324 {
325 int ret = -ENOTSUPP;
326
327 if (dai->driver->ops &&
328 dai->driver->ops->get_channel_map)
329 ret = dai->driver->ops->get_channel_map(dai, tx_num, tx_slot,
330 rx_num, rx_slot);
331 return soc_dai_ret(dai, ret);
332 }
333 EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map);
334
335 /**
336 * snd_soc_dai_set_tristate - configure DAI system or master clock.
337 * @dai: DAI
338 * @tristate: tristate enable
339 *
340 * Tristates the DAI so that others can use it.
341 */
snd_soc_dai_set_tristate(struct snd_soc_dai * dai,int tristate)342 int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
343 {
344 int ret = -EINVAL;
345
346 if (dai->driver->ops &&
347 dai->driver->ops->set_tristate)
348 ret = dai->driver->ops->set_tristate(dai, tristate);
349
350 return soc_dai_ret(dai, ret);
351 }
352 EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
353
snd_soc_dai_prepare(struct snd_soc_dai * dai,struct snd_pcm_substream * substream)354 int snd_soc_dai_prepare(struct snd_soc_dai *dai,
355 struct snd_pcm_substream *substream)
356 {
357 int ret = 0;
358
359 if (!snd_soc_dai_stream_valid(dai, substream->stream))
360 return 0;
361
362 if (dai->driver->ops &&
363 dai->driver->ops->prepare)
364 ret = dai->driver->ops->prepare(substream, dai);
365
366 return soc_dai_ret(dai, ret);
367 }
368 EXPORT_SYMBOL_GPL(snd_soc_dai_prepare);
369
snd_soc_dai_mute_is_ctrled_at_trigger(struct snd_soc_dai * dai)370 int snd_soc_dai_mute_is_ctrled_at_trigger(struct snd_soc_dai *dai)
371 {
372 if (dai->driver->ops)
373 return dai->driver->ops->mute_unmute_on_trigger;
374
375 return 0;
376 }
377
378 /**
379 * snd_soc_dai_digital_mute - configure DAI system or master clock.
380 * @dai: DAI
381 * @mute: mute enable
382 * @direction: stream to mute
383 *
384 * Mutes the DAI DAC.
385 */
snd_soc_dai_digital_mute(struct snd_soc_dai * dai,int mute,int direction)386 int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
387 int direction)
388 {
389 int ret = -ENOTSUPP;
390
391 /*
392 * ignore if direction was CAPTURE
393 * and it had .no_capture_mute flag
394 */
395 if (dai->driver->ops &&
396 dai->driver->ops->mute_stream &&
397 (direction == SNDRV_PCM_STREAM_PLAYBACK ||
398 !dai->driver->ops->no_capture_mute))
399 ret = dai->driver->ops->mute_stream(dai, mute, direction);
400
401 return soc_dai_ret(dai, ret);
402 }
403 EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
404
snd_soc_dai_hw_params(struct snd_soc_dai * dai,struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)405 int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
406 struct snd_pcm_substream *substream,
407 struct snd_pcm_hw_params *params)
408 {
409 int ret = 0;
410
411 if (dai->driver->ops &&
412 dai->driver->ops->hw_params)
413 ret = dai->driver->ops->hw_params(substream, params, dai);
414
415 /* mark substream if succeeded */
416 if (ret == 0)
417 soc_dai_mark_push(dai, substream, hw_params);
418
419 return soc_dai_ret(dai, ret);
420 }
421
snd_soc_dai_hw_free(struct snd_soc_dai * dai,struct snd_pcm_substream * substream,int rollback)422 void snd_soc_dai_hw_free(struct snd_soc_dai *dai,
423 struct snd_pcm_substream *substream,
424 int rollback)
425 {
426 if (rollback && !soc_dai_mark_match(dai, substream, hw_params))
427 return;
428
429 if (dai->driver->ops &&
430 dai->driver->ops->hw_free)
431 dai->driver->ops->hw_free(substream, dai);
432
433 /* remove marked substream */
434 soc_dai_mark_pop(dai, hw_params);
435 }
436
snd_soc_dai_startup(struct snd_soc_dai * dai,struct snd_pcm_substream * substream)437 int snd_soc_dai_startup(struct snd_soc_dai *dai,
438 struct snd_pcm_substream *substream)
439 {
440 int ret = 0;
441
442 if (!snd_soc_dai_stream_valid(dai, substream->stream))
443 return 0;
444
445 if (dai->driver->ops &&
446 dai->driver->ops->startup)
447 ret = dai->driver->ops->startup(substream, dai);
448
449 /* mark substream if succeeded */
450 if (ret == 0)
451 soc_dai_mark_push(dai, substream, startup);
452
453 return soc_dai_ret(dai, ret);
454 }
455
snd_soc_dai_shutdown(struct snd_soc_dai * dai,struct snd_pcm_substream * substream,int rollback)456 void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
457 struct snd_pcm_substream *substream,
458 int rollback)
459 {
460 if (!snd_soc_dai_stream_valid(dai, substream->stream))
461 return;
462
463 if (rollback && !soc_dai_mark_match(dai, substream, startup))
464 return;
465
466 if (dai->driver->ops &&
467 dai->driver->ops->shutdown)
468 dai->driver->ops->shutdown(substream, dai);
469
470 /* remove marked substream */
471 soc_dai_mark_pop(dai, startup);
472 }
473
snd_soc_dai_compress_new(struct snd_soc_dai * dai,struct snd_soc_pcm_runtime * rtd)474 int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
475 struct snd_soc_pcm_runtime *rtd)
476 {
477 int ret = -ENOTSUPP;
478 if (dai->driver->ops &&
479 dai->driver->ops->compress_new)
480 ret = dai->driver->ops->compress_new(rtd);
481 return soc_dai_ret(dai, ret);
482 }
483
484 /*
485 * snd_soc_dai_stream_valid() - check if a DAI supports the given stream
486 *
487 * Returns true if the DAI supports the indicated stream type.
488 */
snd_soc_dai_stream_valid(const struct snd_soc_dai * dai,int dir)489 bool snd_soc_dai_stream_valid(const struct snd_soc_dai *dai, int dir)
490 {
491 const struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir);
492
493 /* If the codec specifies any channels at all, it supports the stream */
494 return stream->channels_min;
495 }
496
snd_soc_dai_action(struct snd_soc_dai * dai,int stream,int action)497 void snd_soc_dai_action(struct snd_soc_dai *dai,
498 int stream, int action)
499 {
500 /* see snd_soc_dai_stream_active() */
501 dai->stream[stream].active += action;
502
503 /* see snd_soc_component_active() */
504 dai->component->active += action;
505 }
506 EXPORT_SYMBOL_GPL(snd_soc_dai_action);
507
snd_soc_dai_active(const struct snd_soc_dai * dai)508 int snd_soc_dai_active(const struct snd_soc_dai *dai)
509 {
510 int stream, active;
511
512 active = 0;
513 for_each_pcm_streams(stream)
514 active += dai->stream[stream].active;
515
516 return active;
517 }
518 EXPORT_SYMBOL_GPL(snd_soc_dai_active);
519
snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime * rtd,int order)520 int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order)
521 {
522 struct snd_soc_dai *dai;
523 int i;
524
525 for_each_rtd_dais(rtd, i, dai) {
526 if (dai->probed)
527 continue;
528
529 if (dai->driver->ops) {
530 if (dai->driver->ops->probe_order != order)
531 continue;
532
533 if (dai->driver->ops->probe) {
534 int ret = dai->driver->ops->probe(dai);
535
536 if (ret < 0)
537 return soc_dai_ret(dai, ret);
538 }
539 }
540 dai->probed = 1;
541 }
542
543 return 0;
544 }
545
snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime * rtd,int order)546 int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order)
547 {
548 struct snd_soc_dai *dai;
549 int i, r, ret = 0;
550
551 for_each_rtd_dais(rtd, i, dai) {
552 if (!dai->probed)
553 continue;
554
555 if (dai->driver->ops) {
556 if (dai->driver->ops->remove_order != order)
557 continue;
558
559 if (dai->driver->ops->remove) {
560 r = dai->driver->ops->remove(dai);
561 if (r < 0)
562 ret = r; /* use last error */
563 }
564 }
565 dai->probed = 0;
566 }
567
568 return ret;
569 }
570
snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime * rtd)571 int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd)
572 {
573 struct snd_soc_dai *dai;
574 int i;
575
576 for_each_rtd_dais(rtd, i, dai) {
577 if (dai->driver->ops &&
578 dai->driver->ops->pcm_new) {
579 int ret = dai->driver->ops->pcm_new(rtd, dai);
580 if (ret < 0)
581 return soc_dai_ret(dai, ret);
582 }
583 }
584
585 return 0;
586 }
587
snd_soc_pcm_dai_prepare(struct snd_pcm_substream * substream)588 int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream)
589 {
590 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
591 struct snd_soc_dai *dai;
592 int i, ret;
593
594 for_each_rtd_dais(rtd, i, dai) {
595 ret = snd_soc_dai_prepare(dai, substream);
596 if (ret < 0)
597 return ret;
598 }
599
600 return 0;
601 }
602
soc_dai_trigger(struct snd_soc_dai * dai,struct snd_pcm_substream * substream,int cmd)603 static int soc_dai_trigger(struct snd_soc_dai *dai,
604 struct snd_pcm_substream *substream, int cmd)
605 {
606 int ret = 0;
607
608 if (!snd_soc_dai_stream_valid(dai, substream->stream))
609 return 0;
610
611 if (dai->driver->ops &&
612 dai->driver->ops->trigger)
613 ret = dai->driver->ops->trigger(substream, cmd, dai);
614
615 return soc_dai_ret(dai, ret);
616 }
617
snd_soc_pcm_dai_trigger(struct snd_pcm_substream * substream,int cmd,int rollback)618 int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream,
619 int cmd, int rollback)
620 {
621 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
622 struct snd_soc_dai *dai;
623 int i, r, ret = 0;
624
625 switch (cmd) {
626 case SNDRV_PCM_TRIGGER_START:
627 case SNDRV_PCM_TRIGGER_RESUME:
628 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
629 for_each_rtd_dais(rtd, i, dai) {
630 ret = soc_dai_trigger(dai, substream, cmd);
631 if (ret < 0)
632 break;
633
634 if (snd_soc_dai_mute_is_ctrled_at_trigger(dai))
635 snd_soc_dai_digital_mute(dai, 0, substream->stream);
636
637 soc_dai_mark_push(dai, substream, trigger);
638 }
639 break;
640 case SNDRV_PCM_TRIGGER_STOP:
641 case SNDRV_PCM_TRIGGER_SUSPEND:
642 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
643 for_each_rtd_dais(rtd, i, dai) {
644 if (rollback && !soc_dai_mark_match(dai, substream, trigger))
645 continue;
646
647 if (snd_soc_dai_mute_is_ctrled_at_trigger(dai))
648 snd_soc_dai_digital_mute(dai, 1, substream->stream);
649
650 r = soc_dai_trigger(dai, substream, cmd);
651 if (r < 0)
652 ret = r; /* use last ret */
653 soc_dai_mark_pop(dai, trigger);
654 }
655 }
656
657 return ret;
658 }
659
snd_soc_pcm_dai_delay(struct snd_pcm_substream * substream,snd_pcm_sframes_t * cpu_delay,snd_pcm_sframes_t * codec_delay)660 void snd_soc_pcm_dai_delay(struct snd_pcm_substream *substream,
661 snd_pcm_sframes_t *cpu_delay,
662 snd_pcm_sframes_t *codec_delay)
663 {
664 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
665 struct snd_soc_dai *dai;
666 int i;
667
668 /*
669 * We're looking for the delay through the full audio path so it needs to
670 * be the maximum of the DAIs doing transmit and the maximum of the DAIs
671 * doing receive (ie, all CPUs and all CODECs) rather than just the maximum
672 * of all DAIs.
673 */
674
675 /* for CPU */
676 for_each_rtd_cpu_dais(rtd, i, dai)
677 if (dai->driver->ops &&
678 dai->driver->ops->delay)
679 *cpu_delay = max(*cpu_delay, dai->driver->ops->delay(substream, dai));
680
681 /* for Codec */
682 for_each_rtd_codec_dais(rtd, i, dai)
683 if (dai->driver->ops &&
684 dai->driver->ops->delay)
685 *codec_delay = max(*codec_delay, dai->driver->ops->delay(substream, dai));
686 }
687
snd_soc_dai_compr_startup(struct snd_soc_dai * dai,struct snd_compr_stream * cstream)688 int snd_soc_dai_compr_startup(struct snd_soc_dai *dai,
689 struct snd_compr_stream *cstream)
690 {
691 int ret = 0;
692
693 if (dai->driver->cops &&
694 dai->driver->cops->startup)
695 ret = dai->driver->cops->startup(cstream, dai);
696
697 /* mark cstream if succeeded */
698 if (ret == 0)
699 soc_dai_mark_push(dai, cstream, compr_startup);
700
701 return soc_dai_ret(dai, ret);
702 }
703 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_startup);
704
snd_soc_dai_compr_shutdown(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,int rollback)705 void snd_soc_dai_compr_shutdown(struct snd_soc_dai *dai,
706 struct snd_compr_stream *cstream,
707 int rollback)
708 {
709 if (rollback && !soc_dai_mark_match(dai, cstream, compr_startup))
710 return;
711
712 if (dai->driver->cops &&
713 dai->driver->cops->shutdown)
714 dai->driver->cops->shutdown(cstream, dai);
715
716 /* remove marked cstream */
717 soc_dai_mark_pop(dai, compr_startup);
718 }
719 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_shutdown);
720
snd_soc_dai_compr_trigger(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,int cmd)721 int snd_soc_dai_compr_trigger(struct snd_soc_dai *dai,
722 struct snd_compr_stream *cstream, int cmd)
723 {
724 int ret = 0;
725
726 if (dai->driver->cops &&
727 dai->driver->cops->trigger)
728 ret = dai->driver->cops->trigger(cstream, cmd, dai);
729
730 return soc_dai_ret(dai, ret);
731 }
732 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_trigger);
733
snd_soc_dai_compr_set_params(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,struct snd_compr_params * params)734 int snd_soc_dai_compr_set_params(struct snd_soc_dai *dai,
735 struct snd_compr_stream *cstream,
736 struct snd_compr_params *params)
737 {
738 int ret = 0;
739
740 if (dai->driver->cops &&
741 dai->driver->cops->set_params)
742 ret = dai->driver->cops->set_params(cstream, params, dai);
743
744 return soc_dai_ret(dai, ret);
745 }
746 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_params);
747
snd_soc_dai_compr_get_params(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,struct snd_codec * params)748 int snd_soc_dai_compr_get_params(struct snd_soc_dai *dai,
749 struct snd_compr_stream *cstream,
750 struct snd_codec *params)
751 {
752 int ret = 0;
753
754 if (dai->driver->cops &&
755 dai->driver->cops->get_params)
756 ret = dai->driver->cops->get_params(cstream, params, dai);
757
758 return soc_dai_ret(dai, ret);
759 }
760 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_params);
761
snd_soc_dai_compr_ack(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,size_t bytes)762 int snd_soc_dai_compr_ack(struct snd_soc_dai *dai,
763 struct snd_compr_stream *cstream,
764 size_t bytes)
765 {
766 int ret = 0;
767
768 if (dai->driver->cops &&
769 dai->driver->cops->ack)
770 ret = dai->driver->cops->ack(cstream, bytes, dai);
771
772 return soc_dai_ret(dai, ret);
773 }
774 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_ack);
775
snd_soc_dai_compr_pointer(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,struct snd_compr_tstamp64 * tstamp)776 int snd_soc_dai_compr_pointer(struct snd_soc_dai *dai,
777 struct snd_compr_stream *cstream,
778 struct snd_compr_tstamp64 *tstamp)
779 {
780 int ret = 0;
781
782 if (dai->driver->cops &&
783 dai->driver->cops->pointer)
784 ret = dai->driver->cops->pointer(cstream, tstamp, dai);
785
786 return soc_dai_ret(dai, ret);
787 }
788 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_pointer);
789
snd_soc_dai_compr_set_metadata(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,struct snd_compr_metadata * metadata)790 int snd_soc_dai_compr_set_metadata(struct snd_soc_dai *dai,
791 struct snd_compr_stream *cstream,
792 struct snd_compr_metadata *metadata)
793 {
794 int ret = 0;
795
796 if (dai->driver->cops &&
797 dai->driver->cops->set_metadata)
798 ret = dai->driver->cops->set_metadata(cstream, metadata, dai);
799
800 return soc_dai_ret(dai, ret);
801 }
802 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_metadata);
803
snd_soc_dai_compr_get_metadata(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,struct snd_compr_metadata * metadata)804 int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai,
805 struct snd_compr_stream *cstream,
806 struct snd_compr_metadata *metadata)
807 {
808 int ret = 0;
809
810 if (dai->driver->cops &&
811 dai->driver->cops->get_metadata)
812 ret = dai->driver->cops->get_metadata(cstream, metadata, dai);
813
814 return soc_dai_ret(dai, ret);
815 }
816 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_metadata);
817