linux/sound/soc/soc-compress.c
<<
>>
Prefs
   1/*
   2 * soc-compress.c  --  ALSA SoC Compress
   3 *
   4 * Copyright (C) 2012 Intel Corp.
   5 *
   6 * Authors: Namarta Kohli <namartax.kohli@intel.com>
   7 *          Ramesh Babu K V <ramesh.babu@linux.intel.com>
   8 *          Vinod Koul <vinod.koul@linux.intel.com>
   9 *
  10 *  This program is free software; you can redistribute  it and/or modify it
  11 *  under  the terms of  the GNU General  Public License as published by the
  12 *  Free Software Foundation;  either version 2 of the  License, or (at your
  13 *  option) any later version.
  14 *
  15 */
  16
  17#include <linux/kernel.h>
  18#include <linux/init.h>
  19#include <linux/delay.h>
  20#include <linux/slab.h>
  21#include <linux/workqueue.h>
  22#include <sound/core.h>
  23#include <sound/compress_params.h>
  24#include <sound/compress_driver.h>
  25#include <sound/soc.h>
  26#include <sound/initval.h>
  27#include <sound/soc-dpcm.h>
  28
  29static int soc_compr_open(struct snd_compr_stream *cstream)
  30{
  31        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
  32        struct snd_soc_platform *platform = rtd->platform;
  33        int ret = 0;
  34
  35        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
  36
  37        if (platform->driver->compr_ops && platform->driver->compr_ops->open) {
  38                ret = platform->driver->compr_ops->open(cstream);
  39                if (ret < 0) {
  40                        pr_err("compress asoc: can't open platform %s\n",
  41                                platform->component.name);
  42                        goto out;
  43                }
  44        }
  45
  46        if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->startup) {
  47                ret = rtd->dai_link->compr_ops->startup(cstream);
  48                if (ret < 0) {
  49                        pr_err("compress asoc: %s startup failed\n", rtd->dai_link->name);
  50                        goto machine_err;
  51                }
  52        }
  53
  54        snd_soc_runtime_activate(rtd, cstream->direction);
  55
  56        mutex_unlock(&rtd->pcm_mutex);
  57
  58        return 0;
  59
  60machine_err:
  61        if (platform->driver->compr_ops && platform->driver->compr_ops->free)
  62                platform->driver->compr_ops->free(cstream);
  63out:
  64        mutex_unlock(&rtd->pcm_mutex);
  65        return ret;
  66}
  67
  68static int soc_compr_open_fe(struct snd_compr_stream *cstream)
  69{
  70        struct snd_soc_pcm_runtime *fe = cstream->private_data;
  71        struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;
  72        struct snd_soc_platform *platform = fe->platform;
  73        struct snd_soc_dpcm *dpcm;
  74        struct snd_soc_dapm_widget_list *list;
  75        int stream;
  76        int ret = 0;
  77
  78        if (cstream->direction == SND_COMPRESS_PLAYBACK)
  79                stream = SNDRV_PCM_STREAM_PLAYBACK;
  80        else
  81                stream = SNDRV_PCM_STREAM_CAPTURE;
  82
  83        mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
  84
  85        if (platform->driver->compr_ops && platform->driver->compr_ops->open) {
  86                ret = platform->driver->compr_ops->open(cstream);
  87                if (ret < 0) {
  88                        pr_err("compress asoc: can't open platform %s\n",
  89                                platform->component.name);
  90                        goto out;
  91                }
  92        }
  93
  94        if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->startup) {
  95                ret = fe->dai_link->compr_ops->startup(cstream);
  96                if (ret < 0) {
  97                        pr_err("compress asoc: %s startup failed\n", fe->dai_link->name);
  98                        goto machine_err;
  99                }
 100        }
 101
 102        fe->dpcm[stream].runtime = fe_substream->runtime;
 103
 104        ret = dpcm_path_get(fe, stream, &list);
 105        if (ret < 0)
 106                goto fe_err;
 107        else if (ret == 0)
 108                dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
 109                        fe->dai_link->name, stream ? "capture" : "playback");
 110
 111        /* calculate valid and active FE <-> BE dpcms */
 112        dpcm_process_paths(fe, stream, &list, 1);
 113
 114        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
 115
 116        ret = dpcm_be_dai_startup(fe, stream);
 117        if (ret < 0) {
 118                /* clean up all links */
 119                list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
 120                        dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
 121
 122                dpcm_be_disconnect(fe, stream);
 123                fe->dpcm[stream].runtime = NULL;
 124                goto fe_err;
 125        }
 126
 127        dpcm_clear_pending_state(fe, stream);
 128        dpcm_path_put(&list);
 129
 130        fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
 131        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
 132
 133        snd_soc_runtime_activate(fe, stream);
 134
 135        mutex_unlock(&fe->card->mutex);
 136
 137        return 0;
 138
 139fe_err:
 140        if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
 141                fe->dai_link->compr_ops->shutdown(cstream);
 142machine_err:
 143        if (platform->driver->compr_ops && platform->driver->compr_ops->free)
 144                platform->driver->compr_ops->free(cstream);
 145out:
 146        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
 147        mutex_unlock(&fe->card->mutex);
 148        return ret;
 149}
 150
 151/*
 152 * Power down the audio subsystem pmdown_time msecs after close is called.
 153 * This is to ensure there are no pops or clicks in between any music tracks
 154 * due to DAPM power cycling.
 155 */
 156static void close_delayed_work(struct work_struct *work)
 157{
 158        struct snd_soc_pcm_runtime *rtd =
 159                        container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
 160        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 161
 162        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 163
 164        dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n",
 165                 codec_dai->driver->playback.stream_name,
 166                 codec_dai->playback_active ? "active" : "inactive",
 167                 rtd->pop_wait ? "yes" : "no");
 168
 169        /* are we waiting on this codec DAI stream */
 170        if (rtd->pop_wait == 1) {
 171                rtd->pop_wait = 0;
 172                snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
 173                                          SND_SOC_DAPM_STREAM_STOP);
 174        }
 175
 176        mutex_unlock(&rtd->pcm_mutex);
 177}
 178
 179static int soc_compr_free(struct snd_compr_stream *cstream)
 180{
 181        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 182        struct snd_soc_platform *platform = rtd->platform;
 183        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 184        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 185        int stream;
 186
 187        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 188
 189        if (cstream->direction == SND_COMPRESS_PLAYBACK)
 190                stream = SNDRV_PCM_STREAM_PLAYBACK;
 191        else
 192                stream = SNDRV_PCM_STREAM_CAPTURE;
 193
 194        snd_soc_runtime_deactivate(rtd, stream);
 195
 196        snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
 197
 198        if (!cpu_dai->active)
 199                cpu_dai->rate = 0;
 200
 201        if (!codec_dai->active)
 202                codec_dai->rate = 0;
 203
 204
 205        if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown)
 206                rtd->dai_link->compr_ops->shutdown(cstream);
 207
 208        if (platform->driver->compr_ops && platform->driver->compr_ops->free)
 209                platform->driver->compr_ops->free(cstream);
 210
 211        if (cstream->direction == SND_COMPRESS_PLAYBACK) {
 212                if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
 213                        snd_soc_dapm_stream_event(rtd,
 214                                        SNDRV_PCM_STREAM_PLAYBACK,
 215                                        SND_SOC_DAPM_STREAM_STOP);
 216                } else {
 217                        rtd->pop_wait = 1;
 218                        queue_delayed_work(system_power_efficient_wq,
 219                                           &rtd->delayed_work,
 220                                           msecs_to_jiffies(rtd->pmdown_time));
 221                }
 222        } else {
 223                /* capture streams can be powered down now */
 224                snd_soc_dapm_stream_event(rtd,
 225                        SNDRV_PCM_STREAM_CAPTURE,
 226                        SND_SOC_DAPM_STREAM_STOP);
 227        }
 228
 229        mutex_unlock(&rtd->pcm_mutex);
 230        return 0;
 231}
 232
 233static int soc_compr_free_fe(struct snd_compr_stream *cstream)
 234{
 235        struct snd_soc_pcm_runtime *fe = cstream->private_data;
 236        struct snd_soc_platform *platform = fe->platform;
 237        struct snd_soc_dpcm *dpcm;
 238        int stream, ret;
 239
 240        mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
 241
 242        if (cstream->direction == SND_COMPRESS_PLAYBACK)
 243                stream = SNDRV_PCM_STREAM_PLAYBACK;
 244        else
 245                stream = SNDRV_PCM_STREAM_CAPTURE;
 246
 247        snd_soc_runtime_deactivate(fe, stream);
 248
 249        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
 250
 251        ret = dpcm_be_dai_hw_free(fe, stream);
 252        if (ret < 0)
 253                dev_err(fe->dev, "compressed hw_free failed %d\n", ret);
 254
 255        ret = dpcm_be_dai_shutdown(fe, stream);
 256
 257        /* mark FE's links ready to prune */
 258        list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
 259                dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
 260
 261        if (stream == SNDRV_PCM_STREAM_PLAYBACK)
 262                dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
 263        else
 264                dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
 265
 266        fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
 267        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
 268
 269        dpcm_be_disconnect(fe, stream);
 270
 271        fe->dpcm[stream].runtime = NULL;
 272
 273        if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
 274                fe->dai_link->compr_ops->shutdown(cstream);
 275
 276        if (platform->driver->compr_ops && platform->driver->compr_ops->free)
 277                platform->driver->compr_ops->free(cstream);
 278
 279        mutex_unlock(&fe->card->mutex);
 280        return 0;
 281}
 282
 283static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
 284{
 285
 286        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 287        struct snd_soc_platform *platform = rtd->platform;
 288        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 289        int ret = 0;
 290
 291        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 292
 293        if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
 294                ret = platform->driver->compr_ops->trigger(cstream, cmd);
 295                if (ret < 0)
 296                        goto out;
 297        }
 298
 299        switch (cmd) {
 300        case SNDRV_PCM_TRIGGER_START:
 301                snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction);
 302                break;
 303        case SNDRV_PCM_TRIGGER_STOP:
 304                snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
 305                break;
 306        }
 307
 308out:
 309        mutex_unlock(&rtd->pcm_mutex);
 310        return ret;
 311}
 312
 313static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
 314{
 315        struct snd_soc_pcm_runtime *fe = cstream->private_data;
 316        struct snd_soc_platform *platform = fe->platform;
 317        int ret = 0, stream;
 318
 319        if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN ||
 320                cmd == SND_COMPR_TRIGGER_DRAIN) {
 321
 322                if (platform->driver->compr_ops &&
 323                    platform->driver->compr_ops->trigger)
 324                        return platform->driver->compr_ops->trigger(cstream,
 325                                                                    cmd);
 326        }
 327
 328        if (cstream->direction == SND_COMPRESS_PLAYBACK)
 329                stream = SNDRV_PCM_STREAM_PLAYBACK;
 330        else
 331                stream = SNDRV_PCM_STREAM_CAPTURE;
 332
 333
 334        mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
 335
 336        if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
 337                ret = platform->driver->compr_ops->trigger(cstream, cmd);
 338                if (ret < 0)
 339                        goto out;
 340        }
 341
 342        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
 343
 344        ret = dpcm_be_dai_trigger(fe, stream, cmd);
 345
 346        switch (cmd) {
 347        case SNDRV_PCM_TRIGGER_START:
 348        case SNDRV_PCM_TRIGGER_RESUME:
 349        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 350                fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
 351                break;
 352        case SNDRV_PCM_TRIGGER_STOP:
 353        case SNDRV_PCM_TRIGGER_SUSPEND:
 354                fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
 355                break;
 356        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 357                fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
 358                break;
 359        }
 360
 361out:
 362        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
 363        mutex_unlock(&fe->card->mutex);
 364        return ret;
 365}
 366
 367static int soc_compr_set_params(struct snd_compr_stream *cstream,
 368                                        struct snd_compr_params *params)
 369{
 370        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 371        struct snd_soc_platform *platform = rtd->platform;
 372        int ret = 0;
 373
 374        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 375
 376        /* first we call set_params for the platform driver
 377         * this should configure the soc side
 378         * if the machine has compressed ops then we call that as well
 379         * expectation is that platform and machine will configure everything
 380         * for this compress path, like configuring pcm port for codec
 381         */
 382        if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
 383                ret = platform->driver->compr_ops->set_params(cstream, params);
 384                if (ret < 0)
 385                        goto err;
 386        }
 387
 388        if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) {
 389                ret = rtd->dai_link->compr_ops->set_params(cstream);
 390                if (ret < 0)
 391                        goto err;
 392        }
 393
 394        if (cstream->direction == SND_COMPRESS_PLAYBACK)
 395                snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
 396                                        SND_SOC_DAPM_STREAM_START);
 397        else
 398                snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
 399                                        SND_SOC_DAPM_STREAM_START);
 400
 401        /* cancel any delayed stream shutdown that is pending */
 402        rtd->pop_wait = 0;
 403        mutex_unlock(&rtd->pcm_mutex);
 404
 405        cancel_delayed_work_sync(&rtd->delayed_work);
 406
 407        return ret;
 408
 409err:
 410        mutex_unlock(&rtd->pcm_mutex);
 411        return ret;
 412}
 413
 414static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
 415                                        struct snd_compr_params *params)
 416{
 417        struct snd_soc_pcm_runtime *fe = cstream->private_data;
 418        struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;
 419        struct snd_soc_platform *platform = fe->platform;
 420        int ret = 0, stream;
 421
 422        if (cstream->direction == SND_COMPRESS_PLAYBACK)
 423                stream = SNDRV_PCM_STREAM_PLAYBACK;
 424        else
 425                stream = SNDRV_PCM_STREAM_CAPTURE;
 426
 427        mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
 428
 429        if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
 430                ret = platform->driver->compr_ops->set_params(cstream, params);
 431                if (ret < 0)
 432                        goto out;
 433        }
 434
 435        if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) {
 436                ret = fe->dai_link->compr_ops->set_params(cstream);
 437                if (ret < 0)
 438                        goto out;
 439        }
 440
 441        /*
 442         * Create an empty hw_params for the BE as the machine driver must
 443         * fix this up to match DSP decoder and ASRC configuration.
 444         * I.e. machine driver fixup for compressed BE is mandatory.
 445         */
 446        memset(&fe->dpcm[fe_substream->stream].hw_params, 0,
 447                sizeof(struct snd_pcm_hw_params));
 448
 449        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
 450
 451        ret = dpcm_be_dai_hw_params(fe, stream);
 452        if (ret < 0)
 453                goto out;
 454
 455        ret = dpcm_be_dai_prepare(fe, stream);
 456        if (ret < 0)
 457                goto out;
 458
 459        if (stream == SNDRV_PCM_STREAM_PLAYBACK)
 460                dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
 461        else
 462                dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
 463
 464        fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
 465
 466out:
 467        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
 468        mutex_unlock(&fe->card->mutex);
 469        return ret;
 470}
 471
 472static int soc_compr_get_params(struct snd_compr_stream *cstream,
 473                                        struct snd_codec *params)
 474{
 475        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 476        struct snd_soc_platform *platform = rtd->platform;
 477        int ret = 0;
 478
 479        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 480
 481        if (platform->driver->compr_ops && platform->driver->compr_ops->get_params)
 482                ret = platform->driver->compr_ops->get_params(cstream, params);
 483
 484        mutex_unlock(&rtd->pcm_mutex);
 485        return ret;
 486}
 487
 488static int soc_compr_get_caps(struct snd_compr_stream *cstream,
 489                                struct snd_compr_caps *caps)
 490{
 491        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 492        struct snd_soc_platform *platform = rtd->platform;
 493        int ret = 0;
 494
 495        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 496
 497        if (platform->driver->compr_ops && platform->driver->compr_ops->get_caps)
 498                ret = platform->driver->compr_ops->get_caps(cstream, caps);
 499
 500        mutex_unlock(&rtd->pcm_mutex);
 501        return ret;
 502}
 503
 504static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream,
 505                                struct snd_compr_codec_caps *codec)
 506{
 507        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 508        struct snd_soc_platform *platform = rtd->platform;
 509        int ret = 0;
 510
 511        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 512
 513        if (platform->driver->compr_ops && platform->driver->compr_ops->get_codec_caps)
 514                ret = platform->driver->compr_ops->get_codec_caps(cstream, codec);
 515
 516        mutex_unlock(&rtd->pcm_mutex);
 517        return ret;
 518}
 519
 520static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
 521{
 522        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 523        struct snd_soc_platform *platform = rtd->platform;
 524        int ret = 0;
 525
 526        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 527
 528        if (platform->driver->compr_ops && platform->driver->compr_ops->ack)
 529                ret = platform->driver->compr_ops->ack(cstream, bytes);
 530
 531        mutex_unlock(&rtd->pcm_mutex);
 532        return ret;
 533}
 534
 535static int soc_compr_pointer(struct snd_compr_stream *cstream,
 536                        struct snd_compr_tstamp *tstamp)
 537{
 538        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 539        struct snd_soc_platform *platform = rtd->platform;
 540
 541        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 542
 543        if (platform->driver->compr_ops && platform->driver->compr_ops->pointer)
 544                 platform->driver->compr_ops->pointer(cstream, tstamp);
 545
 546        mutex_unlock(&rtd->pcm_mutex);
 547        return 0;
 548}
 549
 550static int soc_compr_copy(struct snd_compr_stream *cstream,
 551                          char __user *buf, size_t count)
 552{
 553        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 554        struct snd_soc_platform *platform = rtd->platform;
 555        int ret = 0;
 556
 557        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 558
 559        if (platform->driver->compr_ops && platform->driver->compr_ops->copy)
 560                ret = platform->driver->compr_ops->copy(cstream, buf, count);
 561
 562        mutex_unlock(&rtd->pcm_mutex);
 563        return ret;
 564}
 565
 566static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
 567                                struct snd_compr_metadata *metadata)
 568{
 569        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 570        struct snd_soc_platform *platform = rtd->platform;
 571        int ret = 0;
 572
 573        if (platform->driver->compr_ops && platform->driver->compr_ops->set_metadata)
 574                ret = platform->driver->compr_ops->set_metadata(cstream, metadata);
 575
 576        return ret;
 577}
 578
 579static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
 580                                struct snd_compr_metadata *metadata)
 581{
 582        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 583        struct snd_soc_platform *platform = rtd->platform;
 584        int ret = 0;
 585
 586        if (platform->driver->compr_ops && platform->driver->compr_ops->get_metadata)
 587                ret = platform->driver->compr_ops->get_metadata(cstream, metadata);
 588
 589        return ret;
 590}
 591
 592/* ASoC Compress operations */
 593static struct snd_compr_ops soc_compr_ops = {
 594        .open           = soc_compr_open,
 595        .free           = soc_compr_free,
 596        .set_params     = soc_compr_set_params,
 597        .set_metadata   = soc_compr_set_metadata,
 598        .get_metadata   = soc_compr_get_metadata,
 599        .get_params     = soc_compr_get_params,
 600        .trigger        = soc_compr_trigger,
 601        .pointer        = soc_compr_pointer,
 602        .ack            = soc_compr_ack,
 603        .get_caps       = soc_compr_get_caps,
 604        .get_codec_caps = soc_compr_get_codec_caps
 605};
 606
 607/* ASoC Dynamic Compress operations */
 608static struct snd_compr_ops soc_compr_dyn_ops = {
 609        .open           = soc_compr_open_fe,
 610        .free           = soc_compr_free_fe,
 611        .set_params     = soc_compr_set_params_fe,
 612        .get_params     = soc_compr_get_params,
 613        .set_metadata   = soc_compr_set_metadata,
 614        .get_metadata   = soc_compr_get_metadata,
 615        .trigger        = soc_compr_trigger_fe,
 616        .pointer        = soc_compr_pointer,
 617        .ack            = soc_compr_ack,
 618        .get_caps       = soc_compr_get_caps,
 619        .get_codec_caps = soc_compr_get_codec_caps
 620};
 621
 622/* create a new compress */
 623int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
 624{
 625        struct snd_soc_codec *codec = rtd->codec;
 626        struct snd_soc_platform *platform = rtd->platform;
 627        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 628        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 629        struct snd_compr *compr;
 630        struct snd_pcm *be_pcm;
 631        char new_name[64];
 632        int ret = 0, direction = 0;
 633
 634        if (rtd->num_codecs > 1) {
 635                dev_err(rtd->card->dev, "Multicodec not supported for compressed stream\n");
 636                return -EINVAL;
 637        }
 638
 639        /* check client and interface hw capabilities */
 640        snprintf(new_name, sizeof(new_name), "%s %s-%d",
 641                        rtd->dai_link->stream_name, codec_dai->name, num);
 642
 643        if (codec_dai->driver->playback.channels_min)
 644                direction = SND_COMPRESS_PLAYBACK;
 645        else if (codec_dai->driver->capture.channels_min)
 646                direction = SND_COMPRESS_CAPTURE;
 647        else
 648                return -EINVAL;
 649
 650        compr = kzalloc(sizeof(*compr), GFP_KERNEL);
 651        if (compr == NULL) {
 652                snd_printk(KERN_ERR "Cannot allocate compr\n");
 653                return -ENOMEM;
 654        }
 655
 656        compr->ops = devm_kzalloc(rtd->card->dev, sizeof(soc_compr_ops),
 657                                  GFP_KERNEL);
 658        if (compr->ops == NULL) {
 659                dev_err(rtd->card->dev, "Cannot allocate compressed ops\n");
 660                ret = -ENOMEM;
 661                goto compr_err;
 662        }
 663
 664        if (rtd->dai_link->dynamic) {
 665                snprintf(new_name, sizeof(new_name), "(%s)",
 666                        rtd->dai_link->stream_name);
 667
 668                ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
 669                                1, 0, &be_pcm);
 670                if (ret < 0) {
 671                        dev_err(rtd->card->dev, "ASoC: can't create compressed for %s\n",
 672                                rtd->dai_link->name);
 673                        goto compr_err;
 674                }
 675
 676                rtd->pcm = be_pcm;
 677                rtd->fe_compr = 1;
 678                be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
 679                be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
 680                memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops));
 681        } else
 682                memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));
 683
 684        /* Add copy callback for not memory mapped DSPs */
 685        if (platform->driver->compr_ops && platform->driver->compr_ops->copy)
 686                compr->ops->copy = soc_compr_copy;
 687
 688        mutex_init(&compr->lock);
 689        ret = snd_compress_new(rtd->card->snd_card, num, direction, compr);
 690        if (ret < 0) {
 691                pr_err("compress asoc: can't create compress for codec %s\n",
 692                        codec->component.name);
 693                goto compr_err;
 694        }
 695
 696        /* DAPM dai link stream work */
 697        INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
 698
 699        rtd->compr = compr;
 700        compr->private_data = rtd;
 701
 702        printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name,
 703                cpu_dai->name);
 704        return ret;
 705
 706compr_err:
 707        kfree(compr);
 708        return ret;
 709}
 710