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