xref: /linux/sound/soc/soc-dai.c (revision d30c1683aaecb93d2ab95685dc4300a33d3cea7a)
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)
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  */
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  */
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  */
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  */
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 
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 
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 
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  */
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 
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 
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 
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 
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 
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  */
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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