xref: /openbmc/linux/sound/soc/soc-dai.c (revision ce746d43)
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 	/*
302 	 * ignore if direction was CAPTURE
303 	 * and it had .no_capture_mute flag
304 	 */
305 	if (dai->driver->ops &&
306 	    dai->driver->ops->mute_stream &&
307 	    (direction == SNDRV_PCM_STREAM_PLAYBACK ||
308 	     !dai->driver->ops->no_capture_mute))
309 		ret = dai->driver->ops->mute_stream(dai, mute, direction);
310 
311 	return soc_dai_ret(dai, ret);
312 }
313 EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
314 
315 int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
316 			  struct snd_pcm_substream *substream,
317 			  struct snd_pcm_hw_params *params)
318 {
319 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
320 	int ret = 0;
321 
322 	/* perform any topology hw_params fixups before DAI  */
323 	ret = snd_soc_link_be_hw_params_fixup(rtd, params);
324 	if (ret < 0)
325 		goto end;
326 
327 	if (dai->driver->ops &&
328 	    dai->driver->ops->hw_params)
329 		ret = dai->driver->ops->hw_params(substream, params, dai);
330 end:
331 	return soc_dai_ret(dai, ret);
332 }
333 
334 void snd_soc_dai_hw_free(struct snd_soc_dai *dai,
335 			 struct snd_pcm_substream *substream)
336 {
337 	if (dai->driver->ops &&
338 	    dai->driver->ops->hw_free)
339 		dai->driver->ops->hw_free(substream, dai);
340 }
341 
342 int snd_soc_dai_startup(struct snd_soc_dai *dai,
343 			struct snd_pcm_substream *substream)
344 {
345 	int ret = 0;
346 
347 	if (dai->driver->ops &&
348 	    dai->driver->ops->startup)
349 		ret = dai->driver->ops->startup(substream, dai);
350 
351 	return soc_dai_ret(dai, ret);
352 }
353 
354 void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
355 			 struct snd_pcm_substream *substream)
356 {
357 	if (dai->driver->ops &&
358 	    dai->driver->ops->shutdown)
359 		dai->driver->ops->shutdown(substream, dai);
360 }
361 
362 snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai,
363 				    struct snd_pcm_substream *substream)
364 {
365 	int delay = 0;
366 
367 	if (dai->driver->ops &&
368 	    dai->driver->ops->delay)
369 		delay = dai->driver->ops->delay(substream, dai);
370 
371 	return delay;
372 }
373 
374 int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
375 			     struct snd_soc_pcm_runtime *rtd, int num)
376 {
377 	int ret = -ENOTSUPP;
378 	if (dai->driver->compress_new)
379 		ret = dai->driver->compress_new(rtd, num);
380 	return soc_dai_ret(dai, ret);
381 }
382 
383 /*
384  * snd_soc_dai_stream_valid() - check if a DAI supports the given stream
385  *
386  * Returns true if the DAI supports the indicated stream type.
387  */
388 bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int dir)
389 {
390 	struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir);
391 
392 	/* If the codec specifies any channels at all, it supports the stream */
393 	return stream->channels_min;
394 }
395 
396 /*
397  * snd_soc_dai_link_set_capabilities() - set dai_link properties based on its DAIs
398  */
399 void snd_soc_dai_link_set_capabilities(struct snd_soc_dai_link *dai_link)
400 {
401 	struct snd_soc_dai_link_component *cpu;
402 	struct snd_soc_dai_link_component *codec;
403 	struct snd_soc_dai *dai;
404 	bool supported[SNDRV_PCM_STREAM_LAST + 1];
405 	bool supported_cpu;
406 	bool supported_codec;
407 	int direction;
408 	int i;
409 
410 	for_each_pcm_streams(direction) {
411 		supported_cpu = false;
412 		supported_codec = false;
413 
414 		for_each_link_cpus(dai_link, i, cpu) {
415 			dai = snd_soc_find_dai(cpu);
416 			if (dai && snd_soc_dai_stream_valid(dai, direction)) {
417 				supported_cpu = true;
418 				break;
419 			}
420 		}
421 		for_each_link_codecs(dai_link, i, codec) {
422 			dai = snd_soc_find_dai(codec);
423 			if (dai && snd_soc_dai_stream_valid(dai, direction)) {
424 				supported_codec = true;
425 				break;
426 			}
427 		}
428 		supported[direction] = supported_cpu && supported_codec;
429 	}
430 
431 	dai_link->dpcm_playback = supported[SNDRV_PCM_STREAM_PLAYBACK];
432 	dai_link->dpcm_capture  = supported[SNDRV_PCM_STREAM_CAPTURE];
433 }
434 EXPORT_SYMBOL_GPL(snd_soc_dai_link_set_capabilities);
435 
436 void snd_soc_dai_action(struct snd_soc_dai *dai,
437 			int stream, int action)
438 {
439 	/* see snd_soc_dai_stream_active() */
440 	dai->stream_active[stream]	+= action;
441 
442 	/* see snd_soc_component_active() */
443 	dai->component->active		+= action;
444 }
445 EXPORT_SYMBOL_GPL(snd_soc_dai_action);
446 
447 int snd_soc_dai_active(struct snd_soc_dai *dai)
448 {
449 	int stream, active;
450 
451 	active = 0;
452 	for_each_pcm_streams(stream)
453 		active += dai->stream_active[stream];
454 
455 	return active;
456 }
457 EXPORT_SYMBOL_GPL(snd_soc_dai_active);
458 
459 int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order)
460 {
461 	struct snd_soc_dai *dai;
462 	int i;
463 
464 	for_each_rtd_dais(rtd, i, dai) {
465 		if (dai->driver->probe_order != order)
466 			continue;
467 
468 		if (dai->driver->probe) {
469 			int ret = dai->driver->probe(dai);
470 
471 			if (ret < 0)
472 				return soc_dai_ret(dai, ret);
473 		}
474 
475 		dai->probed = 1;
476 	}
477 
478 	return 0;
479 }
480 
481 int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order)
482 {
483 	struct snd_soc_dai *dai;
484 	int i, r, ret = 0;
485 
486 	for_each_rtd_dais(rtd, i, dai) {
487 		if (dai->driver->remove_order != order)
488 			continue;
489 
490 		if (dai->probed &&
491 		    dai->driver->remove) {
492 			r = dai->driver->remove(dai);
493 			if (r < 0)
494 				ret = r; /* use last error */
495 		}
496 
497 		dai->probed = 0;
498 	}
499 
500 	return ret;
501 }
502 
503 int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd)
504 {
505 	struct snd_soc_dai *dai;
506 	int i, ret = 0;
507 
508 	for_each_rtd_dais(rtd, i, dai) {
509 		if (dai->driver->pcm_new) {
510 			ret = dai->driver->pcm_new(rtd, dai);
511 			if (ret < 0)
512 				return soc_dai_ret(dai, ret);
513 		}
514 	}
515 
516 	return 0;
517 }
518 
519 int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream)
520 {
521 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
522 	struct snd_soc_dai *dai;
523 	int i, ret;
524 
525 	for_each_rtd_dais(rtd, i, dai) {
526 		if (dai->driver->ops &&
527 		    dai->driver->ops->prepare) {
528 			ret = dai->driver->ops->prepare(substream, dai);
529 			if (ret < 0)
530 				return soc_dai_ret(dai, ret);
531 		}
532 	}
533 
534 	return 0;
535 }
536 
537 int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream,
538 			    int cmd)
539 {
540 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
541 	struct snd_soc_dai *dai;
542 	int i, ret;
543 
544 	for_each_rtd_dais(rtd, i, dai) {
545 		if (dai->driver->ops &&
546 		    dai->driver->ops->trigger) {
547 			ret = dai->driver->ops->trigger(substream, cmd, dai);
548 			if (ret < 0)
549 				return soc_dai_ret(dai, ret);
550 		}
551 	}
552 
553 	return 0;
554 }
555 
556 int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream,
557 				    int cmd)
558 {
559 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
560 	struct snd_soc_dai *dai;
561 	int i, ret;
562 
563 	for_each_rtd_dais(rtd, i, dai) {
564 		if (dai->driver->ops &&
565 		    dai->driver->ops->bespoke_trigger) {
566 			ret = dai->driver->ops->bespoke_trigger(substream,
567 								cmd, dai);
568 			if (ret < 0)
569 				return soc_dai_ret(dai, ret);
570 		}
571 	}
572 
573 	return 0;
574 }
575 
576 int snd_soc_dai_compr_startup(struct snd_soc_dai *dai,
577 			      struct snd_compr_stream *cstream)
578 {
579 	int ret = 0;
580 
581 	if (dai->driver->cops &&
582 	    dai->driver->cops->startup)
583 		ret = dai->driver->cops->startup(cstream, dai);
584 
585 	return soc_dai_ret(dai, ret);
586 }
587 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_startup);
588 
589 void snd_soc_dai_compr_shutdown(struct snd_soc_dai *dai,
590 				struct snd_compr_stream *cstream)
591 {
592 	if (dai->driver->cops &&
593 	    dai->driver->cops->shutdown)
594 		dai->driver->cops->shutdown(cstream, dai);
595 }
596 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_shutdown);
597 
598 int snd_soc_dai_compr_trigger(struct snd_soc_dai *dai,
599 			      struct snd_compr_stream *cstream, int cmd)
600 {
601 	int ret = 0;
602 
603 	if (dai->driver->cops &&
604 	    dai->driver->cops->trigger)
605 		ret = dai->driver->cops->trigger(cstream, cmd, dai);
606 
607 	return soc_dai_ret(dai, ret);
608 }
609 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_trigger);
610 
611 int snd_soc_dai_compr_set_params(struct snd_soc_dai *dai,
612 				 struct snd_compr_stream *cstream,
613 				 struct snd_compr_params *params)
614 {
615 	int ret = 0;
616 
617 	if (dai->driver->cops &&
618 	    dai->driver->cops->set_params)
619 		ret = dai->driver->cops->set_params(cstream, params, dai);
620 
621 	return soc_dai_ret(dai, ret);
622 }
623 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_params);
624 
625 int snd_soc_dai_compr_get_params(struct snd_soc_dai *dai,
626 				 struct snd_compr_stream *cstream,
627 				 struct snd_codec *params)
628 {
629 	int ret = 0;
630 
631 	if (dai->driver->cops &&
632 	    dai->driver->cops->get_params)
633 		ret = dai->driver->cops->get_params(cstream, params, dai);
634 
635 	return soc_dai_ret(dai, ret);
636 }
637 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_params);
638 
639 int snd_soc_dai_compr_ack(struct snd_soc_dai *dai,
640 			  struct snd_compr_stream *cstream,
641 			  size_t bytes)
642 {
643 	int ret = 0;
644 
645 	if (dai->driver->cops &&
646 	    dai->driver->cops->ack)
647 		ret = dai->driver->cops->ack(cstream, bytes, dai);
648 
649 	return soc_dai_ret(dai, ret);
650 }
651 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_ack);
652 
653 int snd_soc_dai_compr_pointer(struct snd_soc_dai *dai,
654 			      struct snd_compr_stream *cstream,
655 			      struct snd_compr_tstamp *tstamp)
656 {
657 	int ret = 0;
658 
659 	if (dai->driver->cops &&
660 	    dai->driver->cops->pointer)
661 		ret = dai->driver->cops->pointer(cstream, tstamp, dai);
662 
663 	return soc_dai_ret(dai, ret);
664 }
665 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_pointer);
666 
667 int snd_soc_dai_compr_set_metadata(struct snd_soc_dai *dai,
668 				   struct snd_compr_stream *cstream,
669 				   struct snd_compr_metadata *metadata)
670 {
671 	int ret = 0;
672 
673 	if (dai->driver->cops &&
674 	    dai->driver->cops->set_metadata)
675 		ret = dai->driver->cops->set_metadata(cstream, metadata, dai);
676 
677 	return soc_dai_ret(dai, ret);
678 }
679 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_metadata);
680 
681 int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai,
682 				   struct snd_compr_stream *cstream,
683 				   struct snd_compr_metadata *metadata)
684 {
685 	int ret = 0;
686 
687 	if (dai->driver->cops &&
688 	    dai->driver->cops->get_metadata)
689 		ret = dai->driver->cops->get_metadata(cstream, metadata, dai);
690 
691 	return soc_dai_ret(dai, ret);
692 }
693 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_metadata);
694