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