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 * snd_soc_dai_set_sysclk - configure DAI system or master clock.
  37 * @dai: DAI
  38 * @clk_id: DAI specific clock ID
  39 * @freq: new clock frequency in Hz
  40 * @dir: new clock direction - input/output.
  41 *
  42 * Configures the DAI master (MCLK) or system (SYSCLK) clocking.
  43 */
  44int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
  45                           unsigned int freq, int dir)
  46{
  47        int ret;
  48
  49        if (dai->driver->ops &&
  50            dai->driver->ops->set_sysclk)
  51                ret = dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
  52        else
  53                ret = snd_soc_component_set_sysclk(dai->component, clk_id, 0,
  54                                                   freq, dir);
  55
  56        return soc_dai_ret(dai, ret);
  57}
  58EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
  59
  60/**
  61 * snd_soc_dai_set_clkdiv - configure DAI clock dividers.
  62 * @dai: DAI
  63 * @div_id: DAI specific clock divider ID
  64 * @div: new clock divisor.
  65 *
  66 * Configures the clock dividers. This is used to derive the best DAI bit and
  67 * frame clocks from the system or master clock. It's best to set the DAI bit
  68 * and frame clocks as low as possible to save system power.
  69 */
  70int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
  71                           int div_id, int div)
  72{
  73        int ret = -EINVAL;
  74
  75        if (dai->driver->ops &&
  76            dai->driver->ops->set_clkdiv)
  77                ret = dai->driver->ops->set_clkdiv(dai, div_id, div);
  78
  79        return soc_dai_ret(dai, ret);
  80}
  81EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
  82
  83/**
  84 * snd_soc_dai_set_pll - configure DAI PLL.
  85 * @dai: DAI
  86 * @pll_id: DAI specific PLL ID
  87 * @source: DAI specific source for the PLL
  88 * @freq_in: PLL input clock frequency in Hz
  89 * @freq_out: requested PLL output clock frequency in Hz
  90 *
  91 * Configures and enables PLL to generate output clock based on input clock.
  92 */
  93int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
  94                        unsigned int freq_in, unsigned int freq_out)
  95{
  96        int ret;
  97
  98        if (dai->driver->ops &&
  99            dai->driver->ops->set_pll)
 100                ret = dai->driver->ops->set_pll(dai, pll_id, source,
 101                                                freq_in, freq_out);
 102        else
 103                ret = snd_soc_component_set_pll(dai->component, pll_id, source,
 104                                                freq_in, freq_out);
 105
 106        return soc_dai_ret(dai, ret);
 107}
 108EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
 109
 110/**
 111 * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio.
 112 * @dai: DAI
 113 * @ratio: Ratio of BCLK to Sample rate.
 114 *
 115 * Configures the DAI for a preset BCLK to sample rate ratio.
 116 */
 117int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
 118{
 119        int ret = -EINVAL;
 120
 121        if (dai->driver->ops &&
 122            dai->driver->ops->set_bclk_ratio)
 123                ret = dai->driver->ops->set_bclk_ratio(dai, ratio);
 124
 125        return soc_dai_ret(dai, ret);
 126}
 127EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio);
 128
 129/**
 130 * snd_soc_dai_set_fmt - configure DAI hardware audio format.
 131 * @dai: DAI
 132 * @fmt: SND_SOC_DAIFMT_* format value.
 133 *
 134 * Configures the DAI hardware format and clocking.
 135 */
 136int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 137{
 138        int ret = -ENOTSUPP;
 139
 140        if (dai->driver->ops &&
 141            dai->driver->ops->set_fmt)
 142                ret = dai->driver->ops->set_fmt(dai, fmt);
 143
 144        return soc_dai_ret(dai, ret);
 145}
 146EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
 147
 148/**
 149 * snd_soc_xlate_tdm_slot - generate tx/rx slot mask.
 150 * @slots: Number of slots in use.
 151 * @tx_mask: bitmask representing active TX slots.
 152 * @rx_mask: bitmask representing active RX slots.
 153 *
 154 * Generates the TDM tx and rx slot default masks for DAI.
 155 */
 156static int snd_soc_xlate_tdm_slot_mask(unsigned int slots,
 157                                       unsigned int *tx_mask,
 158                                       unsigned int *rx_mask)
 159{
 160        if (*tx_mask || *rx_mask)
 161                return 0;
 162
 163        if (!slots)
 164                return -EINVAL;
 165
 166        *tx_mask = (1 << slots) - 1;
 167        *rx_mask = (1 << slots) - 1;
 168
 169        return 0;
 170}
 171
 172/**
 173 * snd_soc_dai_set_tdm_slot() - Configures a DAI for TDM operation
 174 * @dai: The DAI to configure
 175 * @tx_mask: bitmask representing active TX slots.
 176 * @rx_mask: bitmask representing active RX slots.
 177 * @slots: Number of slots in use.
 178 * @slot_width: Width in bits for each slot.
 179 *
 180 * This function configures the specified DAI for TDM operation. @slot contains
 181 * the total number of slots of the TDM stream and @slot_with the width of each
 182 * slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the
 183 * active slots of the TDM stream for the specified DAI, i.e. which slots the
 184 * DAI should write to or read from. If a bit is set the corresponding slot is
 185 * active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to
 186 * the first slot, bit 1 to the second slot and so on. The first active slot
 187 * maps to the first channel of the DAI, the second active slot to the second
 188 * channel and so on.
 189 *
 190 * TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask,
 191 * @rx_mask and @slot_width will be ignored.
 192 *
 193 * Returns 0 on success, a negative error code otherwise.
 194 */
 195int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
 196                             unsigned int tx_mask, unsigned int rx_mask,
 197                             int slots, int slot_width)
 198{
 199        int ret = -ENOTSUPP;
 200
 201        if (dai->driver->ops &&
 202            dai->driver->ops->xlate_tdm_slot_mask)
 203                dai->driver->ops->xlate_tdm_slot_mask(slots,
 204                                                      &tx_mask, &rx_mask);
 205        else
 206                snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
 207
 208        dai->tx_mask = tx_mask;
 209        dai->rx_mask = rx_mask;
 210
 211        if (dai->driver->ops &&
 212            dai->driver->ops->set_tdm_slot)
 213                ret = dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
 214                                                      slots, slot_width);
 215        return soc_dai_ret(dai, ret);
 216}
 217EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
 218
 219/**
 220 * snd_soc_dai_set_channel_map - configure DAI audio channel map
 221 * @dai: DAI
 222 * @tx_num: how many TX channels
 223 * @tx_slot: pointer to an array which imply the TX slot number channel
 224 *           0~num-1 uses
 225 * @rx_num: how many RX channels
 226 * @rx_slot: pointer to an array which imply the RX slot number channel
 227 *           0~num-1 uses
 228 *
 229 * configure the relationship between channel number and TDM slot number.
 230 */
 231int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
 232                                unsigned int tx_num, unsigned int *tx_slot,
 233                                unsigned int rx_num, unsigned int *rx_slot)
 234{
 235        int ret = -ENOTSUPP;
 236
 237        if (dai->driver->ops &&
 238            dai->driver->ops->set_channel_map)
 239                ret = dai->driver->ops->set_channel_map(dai, tx_num, tx_slot,
 240                                                        rx_num, rx_slot);
 241        return soc_dai_ret(dai, ret);
 242}
 243EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
 244
 245/**
 246 * snd_soc_dai_get_channel_map - Get DAI audio channel map
 247 * @dai: DAI
 248 * @tx_num: how many TX channels
 249 * @tx_slot: pointer to an array which imply the TX slot number channel
 250 *           0~num-1 uses
 251 * @rx_num: how many RX channels
 252 * @rx_slot: pointer to an array which imply the RX slot number channel
 253 *           0~num-1 uses
 254 */
 255int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai,
 256                                unsigned int *tx_num, unsigned int *tx_slot,
 257                                unsigned int *rx_num, unsigned int *rx_slot)
 258{
 259        int ret = -ENOTSUPP;
 260
 261        if (dai->driver->ops &&
 262            dai->driver->ops->get_channel_map)
 263                ret = dai->driver->ops->get_channel_map(dai, tx_num, tx_slot,
 264                                                        rx_num, rx_slot);
 265        return soc_dai_ret(dai, ret);
 266}
 267EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map);
 268
 269/**
 270 * snd_soc_dai_set_tristate - configure DAI system or master clock.
 271 * @dai: DAI
 272 * @tristate: tristate enable
 273 *
 274 * Tristates the DAI so that others can use it.
 275 */
 276int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
 277{
 278        int ret = -EINVAL;
 279
 280        if (dai->driver->ops &&
 281            dai->driver->ops->set_tristate)
 282                ret = dai->driver->ops->set_tristate(dai, tristate);
 283
 284        return soc_dai_ret(dai, ret);
 285}
 286EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
 287
 288/**
 289 * snd_soc_dai_digital_mute - configure DAI system or master clock.
 290 * @dai: DAI
 291 * @mute: mute enable
 292 * @direction: stream to mute
 293 *
 294 * Mutes the DAI DAC.
 295 */
 296int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
 297                             int direction)
 298{
 299        int ret = -ENOTSUPP;
 300
 301        /*
 302         * ignore if direction was CAPTURE
 303         * and it had .no_capture_mute flag
 304         */
 305        if (dai->driver->ops &&
 306            dai->driver->ops->mute_stream &&
 307            (direction == SNDRV_PCM_STREAM_PLAYBACK ||
 308             !dai->driver->ops->no_capture_mute))
 309                ret = dai->driver->ops->mute_stream(dai, mute, direction);
 310
 311        return soc_dai_ret(dai, ret);
 312}
 313EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
 314
 315int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
 316                          struct snd_pcm_substream *substream,
 317                          struct snd_pcm_hw_params *params)
 318{
 319        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 320        int ret = 0;
 321
 322        /* perform any topology hw_params fixups before DAI  */
 323        ret = snd_soc_link_be_hw_params_fixup(rtd, params);
 324        if (ret < 0)
 325                goto end;
 326
 327        if (dai->driver->ops &&
 328            dai->driver->ops->hw_params)
 329                ret = dai->driver->ops->hw_params(substream, params, dai);
 330end:
 331        return soc_dai_ret(dai, ret);
 332}
 333
 334void snd_soc_dai_hw_free(struct snd_soc_dai *dai,
 335                         struct snd_pcm_substream *substream)
 336{
 337        if (dai->driver->ops &&
 338            dai->driver->ops->hw_free)
 339                dai->driver->ops->hw_free(substream, dai);
 340}
 341
 342int snd_soc_dai_startup(struct snd_soc_dai *dai,
 343                        struct snd_pcm_substream *substream)
 344{
 345        int ret = 0;
 346
 347        if (dai->driver->ops &&
 348            dai->driver->ops->startup)
 349                ret = dai->driver->ops->startup(substream, dai);
 350
 351        return soc_dai_ret(dai, ret);
 352}
 353
 354void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
 355                         struct snd_pcm_substream *substream)
 356{
 357        if (dai->driver->ops &&
 358            dai->driver->ops->shutdown)
 359                dai->driver->ops->shutdown(substream, dai);
 360}
 361
 362snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai,
 363                                    struct snd_pcm_substream *substream)
 364{
 365        int delay = 0;
 366
 367        if (dai->driver->ops &&
 368            dai->driver->ops->delay)
 369                delay = dai->driver->ops->delay(substream, dai);
 370
 371        return delay;
 372}
 373
 374int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
 375                             struct snd_soc_pcm_runtime *rtd, int num)
 376{
 377        int ret = -ENOTSUPP;
 378        if (dai->driver->compress_new)
 379                ret = dai->driver->compress_new(rtd, num);
 380        return soc_dai_ret(dai, ret);
 381}
 382
 383/*
 384 * snd_soc_dai_stream_valid() - check if a DAI supports the given stream
 385 *
 386 * Returns true if the DAI supports the indicated stream type.
 387 */
 388bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int dir)
 389{
 390        struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir);
 391
 392        /* If the codec specifies any channels at all, it supports the stream */
 393        return stream->channels_min;
 394}
 395
 396/*
 397 * snd_soc_dai_link_set_capabilities() - set dai_link properties based on its DAIs
 398 */
 399void snd_soc_dai_link_set_capabilities(struct snd_soc_dai_link *dai_link)
 400{
 401        struct snd_soc_dai_link_component *cpu;
 402        struct snd_soc_dai_link_component *codec;
 403        struct snd_soc_dai *dai;
 404        bool supported[SNDRV_PCM_STREAM_LAST + 1];
 405        bool supported_cpu;
 406        bool supported_codec;
 407        int direction;
 408        int i;
 409
 410        for_each_pcm_streams(direction) {
 411                supported_cpu = false;
 412                supported_codec = false;
 413
 414                for_each_link_cpus(dai_link, i, cpu) {
 415                        dai = snd_soc_find_dai_with_mutex(cpu);
 416                        if (dai && snd_soc_dai_stream_valid(dai, direction)) {
 417                                supported_cpu = true;
 418                                break;
 419                        }
 420                }
 421                for_each_link_codecs(dai_link, i, codec) {
 422                        dai = snd_soc_find_dai_with_mutex(codec);
 423                        if (dai && snd_soc_dai_stream_valid(dai, direction)) {
 424                                supported_codec = true;
 425                                break;
 426                        }
 427                }
 428                supported[direction] = supported_cpu && supported_codec;
 429        }
 430
 431        dai_link->dpcm_playback = supported[SNDRV_PCM_STREAM_PLAYBACK];
 432        dai_link->dpcm_capture  = supported[SNDRV_PCM_STREAM_CAPTURE];
 433}
 434EXPORT_SYMBOL_GPL(snd_soc_dai_link_set_capabilities);
 435
 436void snd_soc_dai_action(struct snd_soc_dai *dai,
 437                        int stream, int action)
 438{
 439        /* see snd_soc_dai_stream_active() */
 440        dai->stream_active[stream]      += action;
 441
 442        /* see snd_soc_component_active() */
 443        dai->component->active          += action;
 444}
 445EXPORT_SYMBOL_GPL(snd_soc_dai_action);
 446
 447int snd_soc_dai_active(struct snd_soc_dai *dai)
 448{
 449        int stream, active;
 450
 451        active = 0;
 452        for_each_pcm_streams(stream)
 453                active += dai->stream_active[stream];
 454
 455        return active;
 456}
 457EXPORT_SYMBOL_GPL(snd_soc_dai_active);
 458
 459int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order)
 460{
 461        struct snd_soc_dai *dai;
 462        int i;
 463
 464        for_each_rtd_dais(rtd, i, dai) {
 465                if (dai->driver->probe_order != order)
 466                        continue;
 467
 468                if (dai->driver->probe) {
 469                        int ret = dai->driver->probe(dai);
 470
 471                        if (ret < 0)
 472                                return soc_dai_ret(dai, ret);
 473                }
 474
 475                dai->probed = 1;
 476        }
 477
 478        return 0;
 479}
 480
 481int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order)
 482{
 483        struct snd_soc_dai *dai;
 484        int i, r, ret = 0;
 485
 486        for_each_rtd_dais(rtd, i, dai) {
 487                if (dai->driver->remove_order != order)
 488                        continue;
 489
 490                if (dai->probed &&
 491                    dai->driver->remove) {
 492                        r = dai->driver->remove(dai);
 493                        if (r < 0)
 494                                ret = r; /* use last error */
 495                }
 496
 497                dai->probed = 0;
 498        }
 499
 500        return ret;
 501}
 502
 503int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd)
 504{
 505        struct snd_soc_dai *dai;
 506        int i, ret = 0;
 507
 508        for_each_rtd_dais(rtd, i, dai) {
 509                if (dai->driver->pcm_new) {
 510                        ret = dai->driver->pcm_new(rtd, dai);
 511                        if (ret < 0)
 512                                return soc_dai_ret(dai, ret);
 513                }
 514        }
 515
 516        return 0;
 517}
 518
 519int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream)
 520{
 521        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 522        struct snd_soc_dai *dai;
 523        int i, ret;
 524
 525        for_each_rtd_dais(rtd, i, dai) {
 526                if (dai->driver->ops &&
 527                    dai->driver->ops->prepare) {
 528                        ret = dai->driver->ops->prepare(substream, dai);
 529                        if (ret < 0)
 530                                return soc_dai_ret(dai, ret);
 531                }
 532        }
 533
 534        return 0;
 535}
 536
 537int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream,
 538                            int cmd)
 539{
 540        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 541        struct snd_soc_dai *dai;
 542        int i, ret;
 543
 544        for_each_rtd_dais(rtd, i, dai) {
 545                if (dai->driver->ops &&
 546                    dai->driver->ops->trigger) {
 547                        ret = dai->driver->ops->trigger(substream, cmd, dai);
 548                        if (ret < 0)
 549                                return soc_dai_ret(dai, ret);
 550                }
 551        }
 552
 553        return 0;
 554}
 555
 556int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream,
 557                                    int cmd)
 558{
 559        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 560        struct snd_soc_dai *dai;
 561        int i, ret;
 562
 563        for_each_rtd_dais(rtd, i, dai) {
 564                if (dai->driver->ops &&
 565                    dai->driver->ops->bespoke_trigger) {
 566                        ret = dai->driver->ops->bespoke_trigger(substream,
 567                                                                cmd, dai);
 568                        if (ret < 0)
 569                                return soc_dai_ret(dai, ret);
 570                }
 571        }
 572
 573        return 0;
 574}
 575
 576int snd_soc_dai_compr_startup(struct snd_soc_dai *dai,
 577                              struct snd_compr_stream *cstream)
 578{
 579        int ret = 0;
 580
 581        if (dai->driver->cops &&
 582            dai->driver->cops->startup)
 583                ret = dai->driver->cops->startup(cstream, dai);
 584
 585        return soc_dai_ret(dai, ret);
 586}
 587EXPORT_SYMBOL_GPL(snd_soc_dai_compr_startup);
 588
 589void snd_soc_dai_compr_shutdown(struct snd_soc_dai *dai,
 590                                struct snd_compr_stream *cstream)
 591{
 592        if (dai->driver->cops &&
 593            dai->driver->cops->shutdown)
 594                dai->driver->cops->shutdown(cstream, dai);
 595}
 596EXPORT_SYMBOL_GPL(snd_soc_dai_compr_shutdown);
 597
 598int snd_soc_dai_compr_trigger(struct snd_soc_dai *dai,
 599                              struct snd_compr_stream *cstream, int cmd)
 600{
 601        int ret = 0;
 602
 603        if (dai->driver->cops &&
 604            dai->driver->cops->trigger)
 605                ret = dai->driver->cops->trigger(cstream, cmd, dai);
 606
 607        return soc_dai_ret(dai, ret);
 608}
 609EXPORT_SYMBOL_GPL(snd_soc_dai_compr_trigger);
 610
 611int snd_soc_dai_compr_set_params(struct snd_soc_dai *dai,
 612                                 struct snd_compr_stream *cstream,
 613                                 struct snd_compr_params *params)
 614{
 615        int ret = 0;
 616
 617        if (dai->driver->cops &&
 618            dai->driver->cops->set_params)
 619                ret = dai->driver->cops->set_params(cstream, params, dai);
 620
 621        return soc_dai_ret(dai, ret);
 622}
 623EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_params);
 624
 625int snd_soc_dai_compr_get_params(struct snd_soc_dai *dai,
 626                                 struct snd_compr_stream *cstream,
 627                                 struct snd_codec *params)
 628{
 629        int ret = 0;
 630
 631        if (dai->driver->cops &&
 632            dai->driver->cops->get_params)
 633                ret = dai->driver->cops->get_params(cstream, params, dai);
 634
 635        return soc_dai_ret(dai, ret);
 636}
 637EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_params);
 638
 639int snd_soc_dai_compr_ack(struct snd_soc_dai *dai,
 640                          struct snd_compr_stream *cstream,
 641                          size_t bytes)
 642{
 643        int ret = 0;
 644
 645        if (dai->driver->cops &&
 646            dai->driver->cops->ack)
 647                ret = dai->driver->cops->ack(cstream, bytes, dai);
 648
 649        return soc_dai_ret(dai, ret);
 650}
 651EXPORT_SYMBOL_GPL(snd_soc_dai_compr_ack);
 652
 653int snd_soc_dai_compr_pointer(struct snd_soc_dai *dai,
 654                              struct snd_compr_stream *cstream,
 655                              struct snd_compr_tstamp *tstamp)
 656{
 657        int ret = 0;
 658
 659        if (dai->driver->cops &&
 660            dai->driver->cops->pointer)
 661                ret = dai->driver->cops->pointer(cstream, tstamp, dai);
 662
 663        return soc_dai_ret(dai, ret);
 664}
 665EXPORT_SYMBOL_GPL(snd_soc_dai_compr_pointer);
 666
 667int snd_soc_dai_compr_set_metadata(struct snd_soc_dai *dai,
 668                                   struct snd_compr_stream *cstream,
 669                                   struct snd_compr_metadata *metadata)
 670{
 671        int ret = 0;
 672
 673        if (dai->driver->cops &&
 674            dai->driver->cops->set_metadata)
 675                ret = dai->driver->cops->set_metadata(cstream, metadata, dai);
 676
 677        return soc_dai_ret(dai, ret);
 678}
 679EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_metadata);
 680
 681int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai,
 682                                   struct snd_compr_stream *cstream,
 683                                   struct snd_compr_metadata *metadata)
 684{
 685        int ret = 0;
 686
 687        if (dai->driver->cops &&
 688            dai->driver->cops->get_metadata)
 689                ret = dai->driver->cops->get_metadata(cstream, metadata, dai);
 690
 691        return soc_dai_ret(dai, ret);
 692}
 693EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_metadata);
 694