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