xref: /openbmc/linux/sound/soc/soc-dai.c (revision 4f872154)
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(struct snd_soc_dai *dai,
15 			       const char *func, int ret)
16 {
17 	/* Positive, Zero values are not errors */
18 	if (ret >= 0)
19 		return ret;
20 
21 	/* Negative values might be errors */
22 	switch (ret) {
23 	case -EPROBE_DEFER:
24 	case -ENOTSUPP:
25 		break;
26 	default:
27 		dev_err(dai->dev,
28 			"ASoC: error at %s on %s: %d\n",
29 			func, dai->name, ret);
30 	}
31 
32 	return ret;
33 }
34 
35 /**
36  * snd_soc_dai_set_sysclk - configure DAI system or master clock.
37  * @dai: DAI
38  * @clk_id: DAI specific clock ID
39  * @freq: new clock frequency in Hz
40  * @dir: new clock direction - input/output.
41  *
42  * Configures the DAI master (MCLK) or system (SYSCLK) clocking.
43  */
44 int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
45 			   unsigned int freq, int dir)
46 {
47 	int ret;
48 
49 	if (dai->driver->ops &&
50 	    dai->driver->ops->set_sysclk)
51 		ret = dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
52 	else
53 		ret = snd_soc_component_set_sysclk(dai->component, clk_id, 0,
54 						   freq, dir);
55 
56 	return soc_dai_ret(dai, ret);
57 }
58 EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
59 
60 /**
61  * snd_soc_dai_set_clkdiv - configure DAI clock dividers.
62  * @dai: DAI
63  * @div_id: DAI specific clock divider ID
64  * @div: new clock divisor.
65  *
66  * Configures the clock dividers. This is used to derive the best DAI bit and
67  * frame clocks from the system or master clock. It's best to set the DAI bit
68  * and frame clocks as low as possible to save system power.
69  */
70 int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
71 			   int div_id, int div)
72 {
73 	int ret = -EINVAL;
74 
75 	if (dai->driver->ops &&
76 	    dai->driver->ops->set_clkdiv)
77 		ret = dai->driver->ops->set_clkdiv(dai, div_id, div);
78 
79 	return soc_dai_ret(dai, ret);
80 }
81 EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
82 
83 /**
84  * snd_soc_dai_set_pll - configure DAI PLL.
85  * @dai: DAI
86  * @pll_id: DAI specific PLL ID
87  * @source: DAI specific source for the PLL
88  * @freq_in: PLL input clock frequency in Hz
89  * @freq_out: requested PLL output clock frequency in Hz
90  *
91  * Configures and enables PLL to generate output clock based on input clock.
92  */
93 int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
94 			unsigned int freq_in, unsigned int freq_out)
95 {
96 	int ret;
97 
98 	if (dai->driver->ops &&
99 	    dai->driver->ops->set_pll)
100 		ret = dai->driver->ops->set_pll(dai, pll_id, source,
101 						freq_in, freq_out);
102 	else
103 		ret = snd_soc_component_set_pll(dai->component, pll_id, source,
104 						freq_in, freq_out);
105 
106 	return soc_dai_ret(dai, ret);
107 }
108 EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
109 
110 /**
111  * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio.
112  * @dai: DAI
113  * @ratio: Ratio of BCLK to Sample rate.
114  *
115  * Configures the DAI for a preset BCLK to sample rate ratio.
116  */
117 int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
118 {
119 	int ret = -EINVAL;
120 
121 	if (dai->driver->ops &&
122 	    dai->driver->ops->set_bclk_ratio)
123 		ret = dai->driver->ops->set_bclk_ratio(dai, ratio);
124 
125 	return soc_dai_ret(dai, ret);
126 }
127 EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio);
128 
129 /**
130  * snd_soc_dai_set_fmt - configure DAI hardware audio format.
131  * @dai: DAI
132  * @fmt: SND_SOC_DAIFMT_* format value.
133  *
134  * Configures the DAI hardware format and clocking.
135  */
136 int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
137 {
138 	int ret = -ENOTSUPP;
139 
140 	if (dai->driver->ops &&
141 	    dai->driver->ops->set_fmt)
142 		ret = dai->driver->ops->set_fmt(dai, fmt);
143 
144 	return soc_dai_ret(dai, ret);
145 }
146 EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
147 
148 /**
149  * snd_soc_xlate_tdm_slot - generate tx/rx slot mask.
150  * @slots: Number of slots in use.
151  * @tx_mask: bitmask representing active TX slots.
152  * @rx_mask: bitmask representing active RX slots.
153  *
154  * Generates the TDM tx and rx slot default masks for DAI.
155  */
156 static int snd_soc_xlate_tdm_slot_mask(unsigned int slots,
157 				       unsigned int *tx_mask,
158 				       unsigned int *rx_mask)
159 {
160 	if (*tx_mask || *rx_mask)
161 		return 0;
162 
163 	if (!slots)
164 		return -EINVAL;
165 
166 	*tx_mask = (1 << slots) - 1;
167 	*rx_mask = (1 << slots) - 1;
168 
169 	return 0;
170 }
171 
172 /**
173  * snd_soc_dai_set_tdm_slot() - Configures a DAI for TDM operation
174  * @dai: The DAI to configure
175  * @tx_mask: bitmask representing active TX slots.
176  * @rx_mask: bitmask representing active RX slots.
177  * @slots: Number of slots in use.
178  * @slot_width: Width in bits for each slot.
179  *
180  * This function configures the specified DAI for TDM operation. @slot contains
181  * the total number of slots of the TDM stream and @slot_with the width of each
182  * slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the
183  * active slots of the TDM stream for the specified DAI, i.e. which slots the
184  * DAI should write to or read from. If a bit is set the corresponding slot is
185  * active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to
186  * the first slot, bit 1 to the second slot and so on. The first active slot
187  * maps to the first channel of the DAI, the second active slot to the second
188  * channel and so on.
189  *
190  * TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask,
191  * @rx_mask and @slot_width will be ignored.
192  *
193  * Returns 0 on success, a negative error code otherwise.
194  */
195 int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
196 			     unsigned int tx_mask, unsigned int rx_mask,
197 			     int slots, int slot_width)
198 {
199 	int ret = -ENOTSUPP;
200 
201 	if (dai->driver->ops &&
202 	    dai->driver->ops->xlate_tdm_slot_mask)
203 		dai->driver->ops->xlate_tdm_slot_mask(slots,
204 						      &tx_mask, &rx_mask);
205 	else
206 		snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
207 
208 	dai->tx_mask = tx_mask;
209 	dai->rx_mask = rx_mask;
210 
211 	if (dai->driver->ops &&
212 	    dai->driver->ops->set_tdm_slot)
213 		ret = dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
214 						      slots, slot_width);
215 	return soc_dai_ret(dai, ret);
216 }
217 EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
218 
219 /**
220  * snd_soc_dai_set_channel_map - configure DAI audio channel map
221  * @dai: DAI
222  * @tx_num: how many TX channels
223  * @tx_slot: pointer to an array which imply the TX slot number channel
224  *           0~num-1 uses
225  * @rx_num: how many RX channels
226  * @rx_slot: pointer to an array which imply the RX slot number channel
227  *           0~num-1 uses
228  *
229  * configure the relationship between channel number and TDM slot number.
230  */
231 int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
232 				unsigned int tx_num, unsigned int *tx_slot,
233 				unsigned int rx_num, unsigned int *rx_slot)
234 {
235 	int ret = -ENOTSUPP;
236 
237 	if (dai->driver->ops &&
238 	    dai->driver->ops->set_channel_map)
239 		ret = dai->driver->ops->set_channel_map(dai, tx_num, tx_slot,
240 							rx_num, rx_slot);
241 	return soc_dai_ret(dai, ret);
242 }
243 EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
244 
245 /**
246  * snd_soc_dai_get_channel_map - Get DAI audio channel map
247  * @dai: DAI
248  * @tx_num: how many TX channels
249  * @tx_slot: pointer to an array which imply the TX slot number channel
250  *           0~num-1 uses
251  * @rx_num: how many RX channels
252  * @rx_slot: pointer to an array which imply the RX slot number channel
253  *           0~num-1 uses
254  */
255 int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai,
256 				unsigned int *tx_num, unsigned int *tx_slot,
257 				unsigned int *rx_num, unsigned int *rx_slot)
258 {
259 	int ret = -ENOTSUPP;
260 
261 	if (dai->driver->ops &&
262 	    dai->driver->ops->get_channel_map)
263 		ret = dai->driver->ops->get_channel_map(dai, tx_num, tx_slot,
264 							rx_num, rx_slot);
265 	return soc_dai_ret(dai, ret);
266 }
267 EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map);
268 
269 /**
270  * snd_soc_dai_set_tristate - configure DAI system or master clock.
271  * @dai: DAI
272  * @tristate: tristate enable
273  *
274  * Tristates the DAI so that others can use it.
275  */
276 int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
277 {
278 	int ret = -EINVAL;
279 
280 	if (dai->driver->ops &&
281 	    dai->driver->ops->set_tristate)
282 		ret = dai->driver->ops->set_tristate(dai, tristate);
283 
284 	return soc_dai_ret(dai, ret);
285 }
286 EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
287 
288 /**
289  * snd_soc_dai_digital_mute - configure DAI system or master clock.
290  * @dai: DAI
291  * @mute: mute enable
292  * @direction: stream to mute
293  *
294  * Mutes the DAI DAC.
295  */
296 int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
297 			     int direction)
298 {
299 	int ret = -ENOTSUPP;
300 
301 	if (dai->driver->ops &&
302 	    dai->driver->ops->mute_stream)
303 		ret = dai->driver->ops->mute_stream(dai, mute, direction);
304 	else if (direction == SNDRV_PCM_STREAM_PLAYBACK &&
305 		 dai->driver->ops &&
306 		 dai->driver->ops->digital_mute)
307 		ret = dai->driver->ops->digital_mute(dai, mute);
308 
309 	return soc_dai_ret(dai, ret);
310 }
311 EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
312 
313 int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
314 			  struct snd_pcm_substream *substream,
315 			  struct snd_pcm_hw_params *params)
316 {
317 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
318 	int ret = 0;
319 
320 	/* perform any topology hw_params fixups before DAI  */
321 	ret = snd_soc_link_be_hw_params_fixup(rtd, params);
322 	if (ret < 0)
323 		goto end;
324 
325 	if (dai->driver->ops &&
326 	    dai->driver->ops->hw_params)
327 		ret = dai->driver->ops->hw_params(substream, params, dai);
328 end:
329 	return soc_dai_ret(dai, ret);
330 }
331 
332 void snd_soc_dai_hw_free(struct snd_soc_dai *dai,
333 			 struct snd_pcm_substream *substream)
334 {
335 	if (dai->driver->ops &&
336 	    dai->driver->ops->hw_free)
337 		dai->driver->ops->hw_free(substream, dai);
338 }
339 
340 int snd_soc_dai_startup(struct snd_soc_dai *dai,
341 			struct snd_pcm_substream *substream)
342 {
343 	int ret = 0;
344 
345 	if (dai->driver->ops &&
346 	    dai->driver->ops->startup)
347 		ret = dai->driver->ops->startup(substream, dai);
348 
349 	return soc_dai_ret(dai, ret);
350 }
351 
352 void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
353 			 struct snd_pcm_substream *substream)
354 {
355 	if (dai->driver->ops &&
356 	    dai->driver->ops->shutdown)
357 		dai->driver->ops->shutdown(substream, dai);
358 }
359 
360 snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai,
361 				    struct snd_pcm_substream *substream)
362 {
363 	int delay = 0;
364 
365 	if (dai->driver->ops &&
366 	    dai->driver->ops->delay)
367 		delay = dai->driver->ops->delay(substream, dai);
368 
369 	return delay;
370 }
371 
372 int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
373 			     struct snd_soc_pcm_runtime *rtd, int num)
374 {
375 	int ret = -ENOTSUPP;
376 	if (dai->driver->compress_new)
377 		ret = dai->driver->compress_new(rtd, num);
378 	return soc_dai_ret(dai, ret);
379 }
380 
381 /*
382  * snd_soc_dai_stream_valid() - check if a DAI supports the given stream
383  *
384  * Returns true if the DAI supports the indicated stream type.
385  */
386 bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int dir)
387 {
388 	struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir);
389 
390 	/* If the codec specifies any channels at all, it supports the stream */
391 	return stream->channels_min;
392 }
393 
394 /*
395  * snd_soc_dai_link_set_capabilities() - set dai_link properties based on its DAIs
396  */
397 void snd_soc_dai_link_set_capabilities(struct snd_soc_dai_link *dai_link)
398 {
399 	struct snd_soc_dai_link_component *cpu;
400 	struct snd_soc_dai_link_component *codec;
401 	struct snd_soc_dai *dai;
402 	bool supported[SNDRV_PCM_STREAM_LAST + 1];
403 	bool supported_cpu;
404 	bool supported_codec;
405 	int direction;
406 	int i;
407 
408 	for_each_pcm_streams(direction) {
409 		supported_cpu = false;
410 		supported_codec = false;
411 
412 		for_each_link_cpus(dai_link, i, cpu) {
413 			dai = snd_soc_find_dai(cpu);
414 			if (dai && snd_soc_dai_stream_valid(dai, direction)) {
415 				supported_cpu = true;
416 				break;
417 			}
418 		}
419 		for_each_link_codecs(dai_link, i, codec) {
420 			dai = snd_soc_find_dai(codec);
421 			if (dai && snd_soc_dai_stream_valid(dai, direction)) {
422 				supported_codec = true;
423 				break;
424 			}
425 		}
426 		supported[direction] = supported_cpu && supported_codec;
427 	}
428 
429 	dai_link->dpcm_playback = supported[SNDRV_PCM_STREAM_PLAYBACK];
430 	dai_link->dpcm_capture  = supported[SNDRV_PCM_STREAM_CAPTURE];
431 }
432 EXPORT_SYMBOL_GPL(snd_soc_dai_link_set_capabilities);
433 
434 void snd_soc_dai_action(struct snd_soc_dai *dai,
435 			int stream, int action)
436 {
437 	/* see snd_soc_dai_stream_active() */
438 	dai->stream_active[stream]	+= action;
439 
440 	/* see snd_soc_component_active() */
441 	dai->component->active		+= action;
442 }
443 EXPORT_SYMBOL_GPL(snd_soc_dai_action);
444 
445 int snd_soc_dai_active(struct snd_soc_dai *dai)
446 {
447 	int stream, active;
448 
449 	active = 0;
450 	for_each_pcm_streams(stream)
451 		active += dai->stream_active[stream];
452 
453 	return active;
454 }
455 EXPORT_SYMBOL_GPL(snd_soc_dai_active);
456 
457 int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order)
458 {
459 	struct snd_soc_dai *dai;
460 	int i;
461 
462 	for_each_rtd_dais(rtd, i, dai) {
463 		if (dai->driver->probe_order != order)
464 			continue;
465 
466 		if (dai->driver->probe) {
467 			int ret = dai->driver->probe(dai);
468 
469 			if (ret < 0)
470 				return soc_dai_ret(dai, ret);
471 		}
472 
473 		dai->probed = 1;
474 	}
475 
476 	return 0;
477 }
478 
479 int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order)
480 {
481 	struct snd_soc_dai *dai;
482 	int i, r, ret = 0;
483 
484 	for_each_rtd_dais(rtd, i, dai) {
485 		if (dai->driver->remove_order != order)
486 			continue;
487 
488 		if (dai->probed &&
489 		    dai->driver->remove) {
490 			r = dai->driver->remove(dai);
491 			if (r < 0)
492 				ret = r; /* use last error */
493 		}
494 
495 		dai->probed = 0;
496 	}
497 
498 	return ret;
499 }
500 
501 int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd)
502 {
503 	struct snd_soc_dai *dai;
504 	int i, ret = 0;
505 
506 	for_each_rtd_dais(rtd, i, dai) {
507 		if (dai->driver->pcm_new) {
508 			ret = dai->driver->pcm_new(rtd, dai);
509 			if (ret < 0)
510 				return soc_dai_ret(dai, ret);
511 		}
512 	}
513 
514 	return 0;
515 }
516 
517 int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream)
518 {
519 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
520 	struct snd_soc_dai *dai;
521 	int i, ret;
522 
523 	for_each_rtd_dais(rtd, i, dai) {
524 		if (dai->driver->ops &&
525 		    dai->driver->ops->prepare) {
526 			ret = dai->driver->ops->prepare(substream, dai);
527 			if (ret < 0)
528 				return soc_dai_ret(dai, ret);
529 		}
530 	}
531 
532 	return 0;
533 }
534 
535 int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream,
536 			    int cmd)
537 {
538 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
539 	struct snd_soc_dai *dai;
540 	int i, ret;
541 
542 	for_each_rtd_dais(rtd, i, dai) {
543 		if (dai->driver->ops &&
544 		    dai->driver->ops->trigger) {
545 			ret = dai->driver->ops->trigger(substream, cmd, dai);
546 			if (ret < 0)
547 				return soc_dai_ret(dai, ret);
548 		}
549 	}
550 
551 	return 0;
552 }
553 
554 int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream,
555 				    int cmd)
556 {
557 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
558 	struct snd_soc_dai *dai;
559 	int i, ret;
560 
561 	for_each_rtd_dais(rtd, i, dai) {
562 		if (dai->driver->ops &&
563 		    dai->driver->ops->bespoke_trigger) {
564 			ret = dai->driver->ops->bespoke_trigger(substream,
565 								cmd, dai);
566 			if (ret < 0)
567 				return soc_dai_ret(dai, ret);
568 		}
569 	}
570 
571 	return 0;
572 }
573 
574 int snd_soc_dai_compr_startup(struct snd_soc_dai *dai,
575 			      struct snd_compr_stream *cstream)
576 {
577 	int ret = 0;
578 
579 	if (dai->driver->cops &&
580 	    dai->driver->cops->startup)
581 		ret = dai->driver->cops->startup(cstream, dai);
582 
583 	return soc_dai_ret(dai, ret);
584 }
585 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_startup);
586 
587 void snd_soc_dai_compr_shutdown(struct snd_soc_dai *dai,
588 				struct snd_compr_stream *cstream)
589 {
590 	if (dai->driver->cops &&
591 	    dai->driver->cops->shutdown)
592 		dai->driver->cops->shutdown(cstream, dai);
593 }
594 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_shutdown);
595 
596 int snd_soc_dai_compr_trigger(struct snd_soc_dai *dai,
597 			      struct snd_compr_stream *cstream, int cmd)
598 {
599 	int ret = 0;
600 
601 	if (dai->driver->cops &&
602 	    dai->driver->cops->trigger)
603 		ret = dai->driver->cops->trigger(cstream, cmd, dai);
604 
605 	return soc_dai_ret(dai, ret);
606 }
607 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_trigger);
608 
609 int snd_soc_dai_compr_set_params(struct snd_soc_dai *dai,
610 				 struct snd_compr_stream *cstream,
611 				 struct snd_compr_params *params)
612 {
613 	int ret = 0;
614 
615 	if (dai->driver->cops &&
616 	    dai->driver->cops->set_params)
617 		ret = dai->driver->cops->set_params(cstream, params, dai);
618 
619 	return soc_dai_ret(dai, ret);
620 }
621 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_params);
622 
623 int snd_soc_dai_compr_get_params(struct snd_soc_dai *dai,
624 				 struct snd_compr_stream *cstream,
625 				 struct snd_codec *params)
626 {
627 	int ret = 0;
628 
629 	if (dai->driver->cops &&
630 	    dai->driver->cops->get_params)
631 		ret = dai->driver->cops->get_params(cstream, params, dai);
632 
633 	return soc_dai_ret(dai, ret);
634 }
635 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_params);
636 
637 int snd_soc_dai_compr_ack(struct snd_soc_dai *dai,
638 			  struct snd_compr_stream *cstream,
639 			  size_t bytes)
640 {
641 	int ret = 0;
642 
643 	if (dai->driver->cops &&
644 	    dai->driver->cops->ack)
645 		ret = dai->driver->cops->ack(cstream, bytes, dai);
646 
647 	return soc_dai_ret(dai, ret);
648 }
649 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_ack);
650 
651 int snd_soc_dai_compr_pointer(struct snd_soc_dai *dai,
652 			      struct snd_compr_stream *cstream,
653 			      struct snd_compr_tstamp *tstamp)
654 {
655 	int ret = 0;
656 
657 	if (dai->driver->cops &&
658 	    dai->driver->cops->pointer)
659 		ret = dai->driver->cops->pointer(cstream, tstamp, dai);
660 
661 	return soc_dai_ret(dai, ret);
662 }
663 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_pointer);
664 
665 int snd_soc_dai_compr_set_metadata(struct snd_soc_dai *dai,
666 				   struct snd_compr_stream *cstream,
667 				   struct snd_compr_metadata *metadata)
668 {
669 	int ret = 0;
670 
671 	if (dai->driver->cops &&
672 	    dai->driver->cops->set_metadata)
673 		ret = dai->driver->cops->set_metadata(cstream, metadata, dai);
674 
675 	return soc_dai_ret(dai, ret);
676 }
677 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_metadata);
678 
679 int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai,
680 				   struct snd_compr_stream *cstream,
681 				   struct snd_compr_metadata *metadata)
682 {
683 	int ret = 0;
684 
685 	if (dai->driver->cops &&
686 	    dai->driver->cops->get_metadata)
687 		ret = dai->driver->cops->get_metadata(cstream, metadata, dai);
688 
689 	return soc_dai_ret(dai, ret);
690 }
691 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_metadata);
692