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