807 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// soc-dai.c4//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(const 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: DAI46 * @clk_id: DAI specific clock ID47 * @freq: new clock frequency in Hz48 * @dir: new clock direction (SND_SOC_CLOCK_IN or SND_SOC_CLOCK_OUT)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 else61 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: DAI71 * @div_id: DAI specific clock divider ID72 * @div: new clock divisor.73 *74 * Configures the clock dividers. This is used to derive the best DAI bit and75 * frame clocks from the system or master clock. It's best to set the DAI bit76 * 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: DAI94 * @pll_id: DAI specific PLL ID95 * @source: DAI specific source for the PLL96 * @freq_in: PLL input clock frequency in Hz97 * @freq_out: requested PLL output clock frequency in Hz98 *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 else111 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: DAI121 * @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(const 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_formats144 */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 else150 return 0;151 }152 153 return max;154}155 156/**157 * snd_soc_dai_get_fmt - get supported audio format.158 * @dai: DAI159 * @priority: priority level of supported audio format.160 *161 * This should return only formats implemented with high162 * quality by the DAI so that the core can configure a163 * format which will work well with other devices.164 * For example devices which don't support both edges of the165 * LRCLK signal in I2S style formats should only list DSP166 * modes. This will mean that sometimes fewer formats167 * are reported here than are supported by set_fmt().168 */169u64 snd_soc_dai_get_fmt(const 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 priority177 *178 * ex)179 * auto_selectable_formats[] = { A, B, C };180 * (A, B, C = SND_SOC_POSSIBLE_DAIFMT_xxx)181 *182 * priority = 1 : A183 * priority = 2 : A | B184 * priority = 3 : A | B | C185 * priority = 4 : A | B | C186 * ...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: DAI203 * @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 operation244 * @dai: The DAI to configure245 * @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 contains251 * the total number of slots of the TDM stream and @slot_with the width of each252 * slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the253 * active slots of the TDM stream for the specified DAI, i.e. which slots the254 * DAI should write to or read from. If a bit is set the corresponding slot is255 * active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to256 * the first slot, bit 1 to the second slot and so on. The first active slot257 * maps to the first channel of the DAI, the second active slot to the second258 * 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 else281 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 map296 * @dai: DAI297 * @tx_num: how many TX channels298 * @tx_slot: pointer to an array which imply the TX slot number channel299 * 0~num-1 uses300 * @rx_num: how many RX channels301 * @rx_slot: pointer to an array which imply the RX slot number channel302 * 0~num-1 uses303 *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, const unsigned int *tx_slot,308 unsigned int rx_num, const 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 map322 * @dai: DAI323 * @tx_num: how many TX channels324 * @tx_slot: pointer to an array which imply the TX slot number channel325 * 0~num-1 uses326 * @rx_num: how many RX channels327 * @rx_slot: pointer to an array which imply the RX slot number channel328 * 0~num-1 uses329 */330int snd_soc_dai_get_channel_map(const 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: DAI347 * @tristate: tristate enable348 *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: DAI366 * @mute: mute enable367 * @direction: stream to mute368 *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 CAPTURE378 * and it had .no_capture_mute flag379 */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 stream471 *472 * Returns true if the DAI supports the indicated stream type.473 */474bool snd_soc_dai_stream_valid(const struct snd_soc_dai *dai, int dir)475{476 const 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 482void snd_soc_dai_action(struct snd_soc_dai *dai,483 int stream, int action)484{485 /* see snd_soc_dai_stream_active() */486 dai->stream[stream].active += action;487 488 /* see snd_soc_component_active() */489 dai->component->active += action;490}491EXPORT_SYMBOL_GPL(snd_soc_dai_action);492 493int snd_soc_dai_active(const struct snd_soc_dai *dai)494{495 int stream, active;496 497 active = 0;498 for_each_pcm_streams(stream)499 active += dai->stream[stream].active;500 501 return active;502}503EXPORT_SYMBOL_GPL(snd_soc_dai_active);504 505int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order)506{507 struct snd_soc_dai *dai;508 int i;509 510 for_each_rtd_dais(rtd, i, dai) {511 if (dai->probed)512 continue;513 514 if (dai->driver->ops) {515 if (dai->driver->ops->probe_order != order)516 continue;517 518 if (dai->driver->ops->probe) {519 int ret = dai->driver->ops->probe(dai);520 521 if (ret < 0)522 return soc_dai_ret(dai, ret);523 }524 }525 dai->probed = 1;526 }527 528 return 0;529}530 531int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order)532{533 struct snd_soc_dai *dai;534 int i, r, ret = 0;535 536 for_each_rtd_dais(rtd, i, dai) {537 if (!dai->probed)538 continue;539 540 if (dai->driver->ops) {541 if (dai->driver->ops->remove_order != order)542 continue;543 544 if (dai->driver->ops->remove) {545 r = dai->driver->ops->remove(dai);546 if (r < 0)547 ret = r; /* use last error */548 }549 }550 dai->probed = 0;551 }552 553 return ret;554}555 556int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd)557{558 struct snd_soc_dai *dai;559 int i;560 561 for_each_rtd_dais(rtd, i, dai) {562 if (dai->driver->ops &&563 dai->driver->ops->pcm_new) {564 int ret = dai->driver->ops->pcm_new(rtd, dai);565 if (ret < 0)566 return soc_dai_ret(dai, ret);567 }568 }569 570 return 0;571}572 573int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream)574{575 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);576 struct snd_soc_dai *dai;577 int i, ret;578 579 for_each_rtd_dais(rtd, i, dai) {580 if (!snd_soc_dai_stream_valid(dai, substream->stream))581 continue;582 if (dai->driver->ops &&583 dai->driver->ops->prepare) {584 ret = dai->driver->ops->prepare(substream, dai);585 if (ret < 0)586 return soc_dai_ret(dai, ret);587 }588 }589 590 return 0;591}592 593static int soc_dai_trigger(struct snd_soc_dai *dai,594 struct snd_pcm_substream *substream, int cmd)595{596 int ret = 0;597 598 if (!snd_soc_dai_stream_valid(dai, substream->stream))599 return 0;600 601 if (dai->driver->ops &&602 dai->driver->ops->trigger)603 ret = dai->driver->ops->trigger(substream, cmd, dai);604 605 return soc_dai_ret(dai, ret);606}607 608int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream,609 int cmd, int rollback)610{611 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);612 struct snd_soc_dai *dai;613 int i, r, ret = 0;614 615 switch (cmd) {616 case SNDRV_PCM_TRIGGER_START:617 case SNDRV_PCM_TRIGGER_RESUME:618 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:619 for_each_rtd_dais(rtd, i, dai) {620 ret = soc_dai_trigger(dai, substream, cmd);621 if (ret < 0)622 break;623 624 if (dai->driver->ops && dai->driver->ops->mute_unmute_on_trigger)625 snd_soc_dai_digital_mute(dai, 0, substream->stream);626 627 soc_dai_mark_push(dai, substream, trigger);628 }629 break;630 case SNDRV_PCM_TRIGGER_STOP:631 case SNDRV_PCM_TRIGGER_SUSPEND:632 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:633 for_each_rtd_dais(rtd, i, dai) {634 if (rollback && !soc_dai_mark_match(dai, substream, trigger))635 continue;636 637 if (dai->driver->ops && dai->driver->ops->mute_unmute_on_trigger)638 snd_soc_dai_digital_mute(dai, 1, substream->stream);639 640 r = soc_dai_trigger(dai, substream, cmd);641 if (r < 0)642 ret = r; /* use last ret */643 soc_dai_mark_pop(dai, substream, trigger);644 }645 }646 647 return ret;648}649 650void snd_soc_pcm_dai_delay(struct snd_pcm_substream *substream,651 snd_pcm_sframes_t *cpu_delay,652 snd_pcm_sframes_t *codec_delay)653{654 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);655 struct snd_soc_dai *dai;656 int i;657 658 /*659 * We're looking for the delay through the full audio path so it needs to660 * be the maximum of the DAIs doing transmit and the maximum of the DAIs661 * doing receive (ie, all CPUs and all CODECs) rather than just the maximum662 * of all DAIs.663 */664 665 /* for CPU */666 for_each_rtd_cpu_dais(rtd, i, dai)667 if (dai->driver->ops &&668 dai->driver->ops->delay)669 *cpu_delay = max(*cpu_delay, dai->driver->ops->delay(substream, dai));670 671 /* for Codec */672 for_each_rtd_codec_dais(rtd, i, dai)673 if (dai->driver->ops &&674 dai->driver->ops->delay)675 *codec_delay = max(*codec_delay, dai->driver->ops->delay(substream, dai));676}677 678int snd_soc_dai_compr_startup(struct snd_soc_dai *dai,679 struct snd_compr_stream *cstream)680{681 int ret = 0;682 683 if (dai->driver->cops &&684 dai->driver->cops->startup)685 ret = dai->driver->cops->startup(cstream, dai);686 687 /* mark cstream if succeeded */688 if (ret == 0)689 soc_dai_mark_push(dai, cstream, compr_startup);690 691 return soc_dai_ret(dai, ret);692}693EXPORT_SYMBOL_GPL(snd_soc_dai_compr_startup);694 695void snd_soc_dai_compr_shutdown(struct snd_soc_dai *dai,696 struct snd_compr_stream *cstream,697 int rollback)698{699 if (rollback && !soc_dai_mark_match(dai, cstream, compr_startup))700 return;701 702 if (dai->driver->cops &&703 dai->driver->cops->shutdown)704 dai->driver->cops->shutdown(cstream, dai);705 706 /* remove marked cstream */707 soc_dai_mark_pop(dai, cstream, compr_startup);708}709EXPORT_SYMBOL_GPL(snd_soc_dai_compr_shutdown);710 711int snd_soc_dai_compr_trigger(struct snd_soc_dai *dai,712 struct snd_compr_stream *cstream, int cmd)713{714 int ret = 0;715 716 if (dai->driver->cops &&717 dai->driver->cops->trigger)718 ret = dai->driver->cops->trigger(cstream, cmd, dai);719 720 return soc_dai_ret(dai, ret);721}722EXPORT_SYMBOL_GPL(snd_soc_dai_compr_trigger);723 724int snd_soc_dai_compr_set_params(struct snd_soc_dai *dai,725 struct snd_compr_stream *cstream,726 struct snd_compr_params *params)727{728 int ret = 0;729 730 if (dai->driver->cops &&731 dai->driver->cops->set_params)732 ret = dai->driver->cops->set_params(cstream, params, dai);733 734 return soc_dai_ret(dai, ret);735}736EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_params);737 738int snd_soc_dai_compr_get_params(struct snd_soc_dai *dai,739 struct snd_compr_stream *cstream,740 struct snd_codec *params)741{742 int ret = 0;743 744 if (dai->driver->cops &&745 dai->driver->cops->get_params)746 ret = dai->driver->cops->get_params(cstream, params, dai);747 748 return soc_dai_ret(dai, ret);749}750EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_params);751 752int snd_soc_dai_compr_ack(struct snd_soc_dai *dai,753 struct snd_compr_stream *cstream,754 size_t bytes)755{756 int ret = 0;757 758 if (dai->driver->cops &&759 dai->driver->cops->ack)760 ret = dai->driver->cops->ack(cstream, bytes, dai);761 762 return soc_dai_ret(dai, ret);763}764EXPORT_SYMBOL_GPL(snd_soc_dai_compr_ack);765 766int snd_soc_dai_compr_pointer(struct snd_soc_dai *dai,767 struct snd_compr_stream *cstream,768 struct snd_compr_tstamp *tstamp)769{770 int ret = 0;771 772 if (dai->driver->cops &&773 dai->driver->cops->pointer)774 ret = dai->driver->cops->pointer(cstream, tstamp, dai);775 776 return soc_dai_ret(dai, ret);777}778EXPORT_SYMBOL_GPL(snd_soc_dai_compr_pointer);779 780int snd_soc_dai_compr_set_metadata(struct snd_soc_dai *dai,781 struct snd_compr_stream *cstream,782 struct snd_compr_metadata *metadata)783{784 int ret = 0;785 786 if (dai->driver->cops &&787 dai->driver->cops->set_metadata)788 ret = dai->driver->cops->set_metadata(cstream, metadata, dai);789 790 return soc_dai_ret(dai, ret);791}792EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_metadata);793 794int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai,795 struct snd_compr_stream *cstream,796 struct snd_compr_metadata *metadata)797{798 int ret = 0;799 800 if (dai->driver->cops &&801 dai->driver->cops->get_metadata)802 ret = dai->driver->cops->get_metadata(cstream, metadata, dai);803 804 return soc_dai_ret(dai, ret);805}806EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_metadata);807