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