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 path_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
 139path_err:
 140        dpcm_path_put(&list);
 141fe_err:
 142        if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
 143                fe->dai_link->compr_ops->shutdown(cstream);
 144machine_err:
 145        if (platform->driver->compr_ops && platform->driver->compr_ops->free)
 146                platform->driver->compr_ops->free(cstream);
 147out:
 148        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
 149        mutex_unlock(&fe->card->mutex);
 150        return ret;
 151}
 152
 153/*
 154 * Power down the audio subsystem pmdown_time msecs after close is called.
 155 * This is to ensure there are no pops or clicks in between any music tracks
 156 * due to DAPM power cycling.
 157 */
 158static void close_delayed_work(struct work_struct *work)
 159{
 160        struct snd_soc_pcm_runtime *rtd =
 161                        container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
 162        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 163
 164        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 165
 166        dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n",
 167                 codec_dai->driver->playback.stream_name,
 168                 codec_dai->playback_active ? "active" : "inactive",
 169                 rtd->pop_wait ? "yes" : "no");
 170
 171        /* are we waiting on this codec DAI stream */
 172        if (rtd->pop_wait == 1) {
 173                rtd->pop_wait = 0;
 174                snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
 175                                          SND_SOC_DAPM_STREAM_STOP);
 176        }
 177
 178        mutex_unlock(&rtd->pcm_mutex);
 179}
 180
 181static int soc_compr_free(struct snd_compr_stream *cstream)
 182{
 183        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 184        struct snd_soc_platform *platform = rtd->platform;
 185        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 186        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 187        int stream;
 188
 189        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 190
 191        if (cstream->direction == SND_COMPRESS_PLAYBACK)
 192                stream = SNDRV_PCM_STREAM_PLAYBACK;
 193        else
 194                stream = SNDRV_PCM_STREAM_CAPTURE;
 195
 196        snd_soc_runtime_deactivate(rtd, stream);
 197
 198        snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
 199
 200        if (!cpu_dai->active)
 201                cpu_dai->rate = 0;
 202
 203        if (!codec_dai->active)
 204                codec_dai->rate = 0;
 205
 206
 207        if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown)
 208                rtd->dai_link->compr_ops->shutdown(cstream);
 209
 210        if (platform->driver->compr_ops && platform->driver->compr_ops->free)
 211                platform->driver->compr_ops->free(cstream);
 212
 213        if (cstream->direction == SND_COMPRESS_PLAYBACK) {
 214                if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
 215                        snd_soc_dapm_stream_event(rtd,
 216                                        SNDRV_PCM_STREAM_PLAYBACK,
 217                                        SND_SOC_DAPM_STREAM_STOP);
 218                } else {
 219                        rtd->pop_wait = 1;
 220                        queue_delayed_work(system_power_efficient_wq,
 221                                           &rtd->delayed_work,
 222                                           msecs_to_jiffies(rtd->pmdown_time));
 223                }
 224        } else {
 225                /* capture streams can be powered down now */
 226                snd_soc_dapm_stream_event(rtd,
 227                        SNDRV_PCM_STREAM_CAPTURE,
 228                        SND_SOC_DAPM_STREAM_STOP);
 229        }
 230
 231        mutex_unlock(&rtd->pcm_mutex);
 232        return 0;
 233}
 234
 235static int soc_compr_free_fe(struct snd_compr_stream *cstream)
 236{
 237        struct snd_soc_pcm_runtime *fe = cstream->private_data;
 238        struct snd_soc_platform *platform = fe->platform;
 239        struct snd_soc_dpcm *dpcm;
 240        int stream, ret;
 241
 242        mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
 243
 244        if (cstream->direction == SND_COMPRESS_PLAYBACK)
 245                stream = SNDRV_PCM_STREAM_PLAYBACK;
 246        else
 247                stream = SNDRV_PCM_STREAM_CAPTURE;
 248
 249        snd_soc_runtime_deactivate(fe, stream);
 250
 251        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
 252
 253        ret = dpcm_be_dai_hw_free(fe, stream);
 254        if (ret < 0)
 255                dev_err(fe->dev, "compressed hw_free failed %d\n", ret);
 256
 257        ret = dpcm_be_dai_shutdown(fe, stream);
 258
 259        /* mark FE's links ready to prune */
 260        list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
 261                dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
 262
 263        dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
 264
 265        fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
 266        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
 267
 268        dpcm_be_disconnect(fe, stream);
 269
 270        fe->dpcm[stream].runtime = NULL;
 271
 272        if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
 273                fe->dai_link->compr_ops->shutdown(cstream);
 274
 275        if (platform->driver->compr_ops && platform->driver->compr_ops->free)
 276                platform->driver->compr_ops->free(cstream);
 277
 278        mutex_unlock(&fe->card->mutex);
 279        return 0;
 280}
 281
 282static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
 283{
 284
 285        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 286        struct snd_soc_platform *platform = rtd->platform;
 287        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 288        int ret = 0;
 289
 290        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 291
 292        if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
 293                ret = platform->driver->compr_ops->trigger(cstream, cmd);
 294                if (ret < 0)
 295                        goto out;
 296        }
 297
 298        switch (cmd) {
 299        case SNDRV_PCM_TRIGGER_START:
 300                snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction);
 301                break;
 302        case SNDRV_PCM_TRIGGER_STOP:
 303                snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
 304                break;
 305        }
 306
 307out:
 308        mutex_unlock(&rtd->pcm_mutex);
 309        return ret;
 310}
 311
 312static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
 313{
 314        struct snd_soc_pcm_runtime *fe = cstream->private_data;
 315        struct snd_soc_platform *platform = fe->platform;
 316        int ret = 0, stream;
 317
 318        if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN ||
 319                cmd == SND_COMPR_TRIGGER_DRAIN) {
 320
 321                if (platform->driver->compr_ops &&
 322                    platform->driver->compr_ops->trigger)
 323                        return platform->driver->compr_ops->trigger(cstream,
 324                                                                    cmd);
 325        }
 326
 327        if (cstream->direction == SND_COMPRESS_PLAYBACK)
 328                stream = SNDRV_PCM_STREAM_PLAYBACK;
 329        else
 330                stream = SNDRV_PCM_STREAM_CAPTURE;
 331
 332
 333        mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
 334
 335        if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
 336                ret = platform->driver->compr_ops->trigger(cstream, cmd);
 337                if (ret < 0)
 338                        goto out;
 339        }
 340
 341        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
 342
 343        ret = dpcm_be_dai_trigger(fe, stream, cmd);
 344
 345        switch (cmd) {
 346        case SNDRV_PCM_TRIGGER_START:
 347        case SNDRV_PCM_TRIGGER_RESUME:
 348        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 349                fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
 350                break;
 351        case SNDRV_PCM_TRIGGER_STOP:
 352        case SNDRV_PCM_TRIGGER_SUSPEND:
 353                fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
 354                break;
 355        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 356                fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
 357                break;
 358        }
 359
 360out:
 361        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
 362        mutex_unlock(&fe->card->mutex);
 363        return ret;
 364}
 365
 366static int soc_compr_set_params(struct snd_compr_stream *cstream,
 367                                        struct snd_compr_params *params)
 368{
 369        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 370        struct snd_soc_platform *platform = rtd->platform;
 371        int ret = 0;
 372
 373        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 374
 375        /* first we call set_params for the platform driver
 376         * this should configure the soc side
 377         * if the machine has compressed ops then we call that as well
 378         * expectation is that platform and machine will configure everything
 379         * for this compress path, like configuring pcm port for codec
 380         */
 381        if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
 382                ret = platform->driver->compr_ops->set_params(cstream, params);
 383                if (ret < 0)
 384                        goto err;
 385        }
 386
 387        if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) {
 388                ret = rtd->dai_link->compr_ops->set_params(cstream);
 389                if (ret < 0)
 390                        goto err;
 391        }
 392
 393        if (cstream->direction == SND_COMPRESS_PLAYBACK)
 394                snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
 395                                        SND_SOC_DAPM_STREAM_START);
 396        else
 397                snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
 398                                        SND_SOC_DAPM_STREAM_START);
 399
 400        /* cancel any delayed stream shutdown that is pending */
 401        rtd->pop_wait = 0;
 402        mutex_unlock(&rtd->pcm_mutex);
 403
 404        cancel_delayed_work_sync(&rtd->delayed_work);
 405
 406        return ret;
 407
 408err:
 409        mutex_unlock(&rtd->pcm_mutex);
 410        return ret;
 411}
 412
 413static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
 414                                        struct snd_compr_params *params)
 415{
 416        struct snd_soc_pcm_runtime *fe = cstream->private_data;
 417        struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;
 418        struct snd_soc_platform *platform = fe->platform;
 419        int ret = 0, stream;
 420
 421        if (cstream->direction == SND_COMPRESS_PLAYBACK)
 422                stream = SNDRV_PCM_STREAM_PLAYBACK;
 423        else
 424                stream = SNDRV_PCM_STREAM_CAPTURE;
 425
 426        mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
 427
 428        if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
 429                ret = platform->driver->compr_ops->set_params(cstream, params);
 430                if (ret < 0)
 431                        goto out;
 432        }
 433
 434        if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) {
 435                ret = fe->dai_link->compr_ops->set_params(cstream);
 436                if (ret < 0)
 437                        goto out;
 438        }
 439
 440        /*
 441         * Create an empty hw_params for the BE as the machine driver must
 442         * fix this up to match DSP decoder and ASRC configuration.
 443         * I.e. machine driver fixup for compressed BE is mandatory.
 444         */
 445        memset(&fe->dpcm[fe_substream->stream].hw_params, 0,
 446                sizeof(struct snd_pcm_hw_params));
 447
 448        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
 449
 450        ret = dpcm_be_dai_hw_params(fe, stream);
 451        if (ret < 0)
 452                goto out;
 453
 454        ret = dpcm_be_dai_prepare(fe, stream);
 455        if (ret < 0)
 456                goto out;
 457
 458        dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
 459        fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
 460
 461out:
 462        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
 463        mutex_unlock(&fe->card->mutex);
 464        return ret;
 465}
 466
 467static int soc_compr_get_params(struct snd_compr_stream *cstream,
 468                                        struct snd_codec *params)
 469{
 470        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 471        struct snd_soc_platform *platform = rtd->platform;
 472        int ret = 0;
 473
 474        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 475
 476        if (platform->driver->compr_ops && platform->driver->compr_ops->get_params)
 477                ret = platform->driver->compr_ops->get_params(cstream, params);
 478
 479        mutex_unlock(&rtd->pcm_mutex);
 480        return ret;
 481}
 482
 483static int soc_compr_get_caps(struct snd_compr_stream *cstream,
 484                                struct snd_compr_caps *caps)
 485{
 486        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 487        struct snd_soc_platform *platform = rtd->platform;
 488        int ret = 0;
 489
 490        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 491
 492        if (platform->driver->compr_ops && platform->driver->compr_ops->get_caps)
 493                ret = platform->driver->compr_ops->get_caps(cstream, caps);
 494
 495        mutex_unlock(&rtd->pcm_mutex);
 496        return ret;
 497}
 498
 499static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream,
 500                                struct snd_compr_codec_caps *codec)
 501{
 502        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 503        struct snd_soc_platform *platform = rtd->platform;
 504        int ret = 0;
 505
 506        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 507
 508        if (platform->driver->compr_ops && platform->driver->compr_ops->get_codec_caps)
 509                ret = platform->driver->compr_ops->get_codec_caps(cstream, codec);
 510
 511        mutex_unlock(&rtd->pcm_mutex);
 512        return ret;
 513}
 514
 515static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
 516{
 517        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 518        struct snd_soc_platform *platform = rtd->platform;
 519        int ret = 0;
 520
 521        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 522
 523        if (platform->driver->compr_ops && platform->driver->compr_ops->ack)
 524                ret = platform->driver->compr_ops->ack(cstream, bytes);
 525
 526        mutex_unlock(&rtd->pcm_mutex);
 527        return ret;
 528}
 529
 530static int soc_compr_pointer(struct snd_compr_stream *cstream,
 531                        struct snd_compr_tstamp *tstamp)
 532{
 533        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 534        struct snd_soc_platform *platform = rtd->platform;
 535        int ret = 0;
 536
 537        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 538
 539        if (platform->driver->compr_ops && platform->driver->compr_ops->pointer)
 540                ret = platform->driver->compr_ops->pointer(cstream, tstamp);
 541
 542        mutex_unlock(&rtd->pcm_mutex);
 543        return ret;
 544}
 545
 546static int soc_compr_copy(struct snd_compr_stream *cstream,
 547                          char __user *buf, size_t count)
 548{
 549        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 550        struct snd_soc_platform *platform = rtd->platform;
 551        int ret = 0;
 552
 553        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 554
 555        if (platform->driver->compr_ops && platform->driver->compr_ops->copy)
 556                ret = platform->driver->compr_ops->copy(cstream, buf, count);
 557
 558        mutex_unlock(&rtd->pcm_mutex);
 559        return ret;
 560}
 561
 562static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
 563                                struct snd_compr_metadata *metadata)
 564{
 565        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 566        struct snd_soc_platform *platform = rtd->platform;
 567        int ret = 0;
 568
 569        if (platform->driver->compr_ops && platform->driver->compr_ops->set_metadata)
 570                ret = platform->driver->compr_ops->set_metadata(cstream, metadata);
 571
 572        return ret;
 573}
 574
 575static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
 576                                struct snd_compr_metadata *metadata)
 577{
 578        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 579        struct snd_soc_platform *platform = rtd->platform;
 580        int ret = 0;
 581
 582        if (platform->driver->compr_ops && platform->driver->compr_ops->get_metadata)
 583                ret = platform->driver->compr_ops->get_metadata(cstream, metadata);
 584
 585        return ret;
 586}
 587
 588/* ASoC Compress operations */
 589static struct snd_compr_ops soc_compr_ops = {
 590        .open           = soc_compr_open,
 591        .free           = soc_compr_free,
 592        .set_params     = soc_compr_set_params,
 593        .set_metadata   = soc_compr_set_metadata,
 594        .get_metadata   = soc_compr_get_metadata,
 595        .get_params     = soc_compr_get_params,
 596        .trigger        = soc_compr_trigger,
 597        .pointer        = soc_compr_pointer,
 598        .ack            = soc_compr_ack,
 599        .get_caps       = soc_compr_get_caps,
 600        .get_codec_caps = soc_compr_get_codec_caps
 601};
 602
 603/* ASoC Dynamic Compress operations */
 604static struct snd_compr_ops soc_compr_dyn_ops = {
 605        .open           = soc_compr_open_fe,
 606        .free           = soc_compr_free_fe,
 607        .set_params     = soc_compr_set_params_fe,
 608        .get_params     = soc_compr_get_params,
 609        .set_metadata   = soc_compr_set_metadata,
 610        .get_metadata   = soc_compr_get_metadata,
 611        .trigger        = soc_compr_trigger_fe,
 612        .pointer        = soc_compr_pointer,
 613        .ack            = soc_compr_ack,
 614        .get_caps       = soc_compr_get_caps,
 615        .get_codec_caps = soc_compr_get_codec_caps
 616};
 617
 618/**
 619 * snd_soc_new_compress - create a new compress.
 620 *
 621 * @rtd: The runtime for which we will create compress
 622 * @num: the device index number (zero based - shared with normal PCMs)
 623 *
 624 * Return: 0 for success, else error.
 625 */
 626int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
 627{
 628        struct snd_soc_codec *codec = rtd->codec;
 629        struct snd_soc_platform *platform = rtd->platform;
 630        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 631        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 632        struct snd_compr *compr;
 633        struct snd_pcm *be_pcm;
 634        char new_name[64];
 635        int ret = 0, direction = 0;
 636        int playback = 0, capture = 0;
 637
 638        if (rtd->num_codecs > 1) {
 639                dev_err(rtd->card->dev, "Multicodec not supported for compressed stream\n");
 640                return -EINVAL;
 641        }
 642
 643        /* check client and interface hw capabilities */
 644        snprintf(new_name, sizeof(new_name), "%s %s-%d",
 645                        rtd->dai_link->stream_name, codec_dai->name, num);
 646
 647        if (codec_dai->driver->playback.channels_min)
 648                playback = 1;
 649        if (codec_dai->driver->capture.channels_min)
 650                capture = 1;
 651
 652        capture = capture && cpu_dai->driver->capture.channels_min;
 653        playback = playback && cpu_dai->driver->playback.channels_min;
 654
 655        /*
 656         * Compress devices are unidirectional so only one of the directions
 657         * should be set, check for that (xor)
 658         */
 659        if (playback + capture != 1) {
 660                dev_err(rtd->card->dev, "Invalid direction for compress P %d, C %d\n",
 661                                playback, capture);
 662                return -EINVAL;
 663        }
 664
 665        if(playback)
 666                direction = SND_COMPRESS_PLAYBACK;
 667        else
 668                direction = SND_COMPRESS_CAPTURE;
 669
 670        compr = kzalloc(sizeof(*compr), GFP_KERNEL);
 671        if (compr == NULL) {
 672                snd_printk(KERN_ERR "Cannot allocate compr\n");
 673                return -ENOMEM;
 674        }
 675
 676        compr->ops = devm_kzalloc(rtd->card->dev, sizeof(soc_compr_ops),
 677                                  GFP_KERNEL);
 678        if (compr->ops == NULL) {
 679                dev_err(rtd->card->dev, "Cannot allocate compressed ops\n");
 680                ret = -ENOMEM;
 681                goto compr_err;
 682        }
 683
 684        if (rtd->dai_link->dynamic) {
 685                snprintf(new_name, sizeof(new_name), "(%s)",
 686                        rtd->dai_link->stream_name);
 687
 688                ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
 689                                rtd->dai_link->dpcm_playback,
 690                                rtd->dai_link->dpcm_capture, &be_pcm);
 691                if (ret < 0) {
 692                        dev_err(rtd->card->dev, "ASoC: can't create compressed for %s\n",
 693                                rtd->dai_link->name);
 694                        goto compr_err;
 695                }
 696
 697                rtd->pcm = be_pcm;
 698                rtd->fe_compr = 1;
 699                if (rtd->dai_link->dpcm_playback)
 700                        be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
 701                else if (rtd->dai_link->dpcm_capture)
 702                        be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
 703                memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops));
 704        } else
 705                memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));
 706
 707        /* Add copy callback for not memory mapped DSPs */
 708        if (platform->driver->compr_ops && platform->driver->compr_ops->copy)
 709                compr->ops->copy = soc_compr_copy;
 710
 711        mutex_init(&compr->lock);
 712
 713        snprintf(new_name, sizeof(new_name), "%s %s-%d",
 714                 rtd->dai_link->stream_name,
 715                 rtd->codec_dai->name, num);
 716
 717        ret = snd_compress_new(rtd->card->snd_card, num, direction,
 718                                new_name, compr);
 719        if (ret < 0) {
 720                pr_err("compress asoc: can't create compress for codec %s\n",
 721                        codec->component.name);
 722                goto compr_err;
 723        }
 724
 725        /* DAPM dai link stream work */
 726        INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
 727
 728        rtd->compr = compr;
 729        compr->private_data = rtd;
 730
 731        printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name,
 732                cpu_dai->name);
 733        return ret;
 734
 735compr_err:
 736        kfree(compr);
 737        return ret;
 738}
 739EXPORT_SYMBOL_GPL(snd_soc_new_compress);
 740