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