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