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