linux/sound/soc/soc-pcm.c
<<
>>
Prefs
   1/*
   2 * soc-pcm.c  --  ALSA SoC PCM
   3 *
   4 * Copyright 2005 Wolfson Microelectronics PLC.
   5 * Copyright 2005 Openedhand Ltd.
   6 * Copyright (C) 2010 Slimlogic Ltd.
   7 * Copyright (C) 2010 Texas Instruments Inc.
   8 *
   9 * Authors: Liam Girdwood <lrg@ti.com>
  10 *          Mark Brown <broonie@opensource.wolfsonmicro.com>       
  11 *
  12 *  This program is free software; you can redistribute  it and/or modify it
  13 *  under  the terms of  the GNU General  Public License as published by the
  14 *  Free Software Foundation;  either version 2 of the  License, or (at your
  15 *  option) any later version.
  16 *
  17 */
  18
  19#include <linux/kernel.h>
  20#include <linux/init.h>
  21#include <linux/delay.h>
  22#include <linux/slab.h>
  23#include <linux/workqueue.h>
  24#include <sound/core.h>
  25#include <sound/pcm.h>
  26#include <sound/pcm_params.h>
  27#include <sound/soc.h>
  28#include <sound/initval.h>
  29
  30static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
  31                                        struct snd_soc_dai *soc_dai)
  32{
  33        struct snd_soc_pcm_runtime *rtd = substream->private_data;
  34        int ret;
  35
  36        if (!soc_dai->driver->symmetric_rates &&
  37            !rtd->dai_link->symmetric_rates)
  38                return 0;
  39
  40        /* This can happen if multiple streams are starting simultaneously -
  41         * the second can need to get its constraints before the first has
  42         * picked a rate.  Complain and allow the application to carry on.
  43         */
  44        if (!soc_dai->rate) {
  45                dev_warn(soc_dai->dev,
  46                         "Not enforcing symmetric_rates due to race\n");
  47                return 0;
  48        }
  49
  50        dev_dbg(soc_dai->dev, "Symmetry forces %dHz rate\n", soc_dai->rate);
  51
  52        ret = snd_pcm_hw_constraint_minmax(substream->runtime,
  53                                           SNDRV_PCM_HW_PARAM_RATE,
  54                                           soc_dai->rate, soc_dai->rate);
  55        if (ret < 0) {
  56                dev_err(soc_dai->dev,
  57                        "Unable to apply rate symmetry constraint: %d\n", ret);
  58                return ret;
  59        }
  60
  61        return 0;
  62}
  63
  64/*
  65 * Called by ALSA when a PCM substream is opened, the runtime->hw record is
  66 * then initialized and any private data can be allocated. This also calls
  67 * startup for the cpu DAI, platform, machine and codec DAI.
  68 */
  69static int soc_pcm_open(struct snd_pcm_substream *substream)
  70{
  71        struct snd_soc_pcm_runtime *rtd = substream->private_data;
  72        struct snd_pcm_runtime *runtime = substream->runtime;
  73        struct snd_soc_platform *platform = rtd->platform;
  74        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  75        struct snd_soc_dai *codec_dai = rtd->codec_dai;
  76        struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
  77        struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver;
  78        int ret = 0;
  79
  80        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
  81
  82        /* startup the audio subsystem */
  83        if (cpu_dai->driver->ops->startup) {
  84                ret = cpu_dai->driver->ops->startup(substream, cpu_dai);
  85                if (ret < 0) {
  86                        printk(KERN_ERR "asoc: can't open interface %s\n",
  87                                cpu_dai->name);
  88                        goto out;
  89                }
  90        }
  91
  92        if (platform->driver->ops && platform->driver->ops->open) {
  93                ret = platform->driver->ops->open(substream);
  94                if (ret < 0) {
  95                        printk(KERN_ERR "asoc: can't open platform %s\n", platform->name);
  96                        goto platform_err;
  97                }
  98        }
  99
 100        if (codec_dai->driver->ops->startup) {
 101                ret = codec_dai->driver->ops->startup(substream, codec_dai);
 102                if (ret < 0) {
 103                        printk(KERN_ERR "asoc: can't open codec %s\n",
 104                                codec_dai->name);
 105                        goto codec_dai_err;
 106                }
 107        }
 108
 109        if (rtd->dai_link->ops && rtd->dai_link->ops->startup) {
 110                ret = rtd->dai_link->ops->startup(substream);
 111                if (ret < 0) {
 112                        printk(KERN_ERR "asoc: %s startup failed\n", rtd->dai_link->name);
 113                        goto machine_err;
 114                }
 115        }
 116
 117        /* Check that the codec and cpu DAIs are compatible */
 118        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 119                runtime->hw.rate_min =
 120                        max(codec_dai_drv->playback.rate_min,
 121                            cpu_dai_drv->playback.rate_min);
 122                runtime->hw.rate_max =
 123                        min(codec_dai_drv->playback.rate_max,
 124                            cpu_dai_drv->playback.rate_max);
 125                runtime->hw.channels_min =
 126                        max(codec_dai_drv->playback.channels_min,
 127                                cpu_dai_drv->playback.channels_min);
 128                runtime->hw.channels_max =
 129                        min(codec_dai_drv->playback.channels_max,
 130                                cpu_dai_drv->playback.channels_max);
 131                runtime->hw.formats =
 132                        codec_dai_drv->playback.formats & cpu_dai_drv->playback.formats;
 133                runtime->hw.rates =
 134                        codec_dai_drv->playback.rates & cpu_dai_drv->playback.rates;
 135                if (codec_dai_drv->playback.rates
 136                           & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
 137                        runtime->hw.rates |= cpu_dai_drv->playback.rates;
 138                if (cpu_dai_drv->playback.rates
 139                           & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
 140                        runtime->hw.rates |= codec_dai_drv->playback.rates;
 141        } else {
 142                runtime->hw.rate_min =
 143                        max(codec_dai_drv->capture.rate_min,
 144                            cpu_dai_drv->capture.rate_min);
 145                runtime->hw.rate_max =
 146                        min(codec_dai_drv->capture.rate_max,
 147                            cpu_dai_drv->capture.rate_max);
 148                runtime->hw.channels_min =
 149                        max(codec_dai_drv->capture.channels_min,
 150                                cpu_dai_drv->capture.channels_min);
 151                runtime->hw.channels_max =
 152                        min(codec_dai_drv->capture.channels_max,
 153                                cpu_dai_drv->capture.channels_max);
 154                runtime->hw.formats =
 155                        codec_dai_drv->capture.formats & cpu_dai_drv->capture.formats;
 156                runtime->hw.rates =
 157                        codec_dai_drv->capture.rates & cpu_dai_drv->capture.rates;
 158                if (codec_dai_drv->capture.rates
 159                           & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
 160                        runtime->hw.rates |= cpu_dai_drv->capture.rates;
 161                if (cpu_dai_drv->capture.rates
 162                           & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
 163                        runtime->hw.rates |= codec_dai_drv->capture.rates;
 164        }
 165
 166        ret = -EINVAL;
 167        snd_pcm_limit_hw_rates(runtime);
 168        if (!runtime->hw.rates) {
 169                printk(KERN_ERR "asoc: %s <-> %s No matching rates\n",
 170                        codec_dai->name, cpu_dai->name);
 171                goto config_err;
 172        }
 173        if (!runtime->hw.formats) {
 174                printk(KERN_ERR "asoc: %s <-> %s No matching formats\n",
 175                        codec_dai->name, cpu_dai->name);
 176                goto config_err;
 177        }
 178        if (!runtime->hw.channels_min || !runtime->hw.channels_max ||
 179            runtime->hw.channels_min > runtime->hw.channels_max) {
 180                printk(KERN_ERR "asoc: %s <-> %s No matching channels\n",
 181                                codec_dai->name, cpu_dai->name);
 182                goto config_err;
 183        }
 184
 185        /* Symmetry only applies if we've already got an active stream. */
 186        if (cpu_dai->active) {
 187                ret = soc_pcm_apply_symmetry(substream, cpu_dai);
 188                if (ret != 0)
 189                        goto config_err;
 190        }
 191
 192        if (codec_dai->active) {
 193                ret = soc_pcm_apply_symmetry(substream, codec_dai);
 194                if (ret != 0)
 195                        goto config_err;
 196        }
 197
 198        pr_debug("asoc: %s <-> %s info:\n",
 199                        codec_dai->name, cpu_dai->name);
 200        pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates);
 201        pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min,
 202                 runtime->hw.channels_max);
 203        pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min,
 204                 runtime->hw.rate_max);
 205
 206        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 207                cpu_dai->playback_active++;
 208                codec_dai->playback_active++;
 209        } else {
 210                cpu_dai->capture_active++;
 211                codec_dai->capture_active++;
 212        }
 213        cpu_dai->active++;
 214        codec_dai->active++;
 215        rtd->codec->active++;
 216        mutex_unlock(&rtd->pcm_mutex);
 217        return 0;
 218
 219config_err:
 220        if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
 221                rtd->dai_link->ops->shutdown(substream);
 222
 223machine_err:
 224        if (codec_dai->driver->ops->shutdown)
 225                codec_dai->driver->ops->shutdown(substream, codec_dai);
 226
 227codec_dai_err:
 228        if (platform->driver->ops && platform->driver->ops->close)
 229                platform->driver->ops->close(substream);
 230
 231platform_err:
 232        if (cpu_dai->driver->ops->shutdown)
 233                cpu_dai->driver->ops->shutdown(substream, cpu_dai);
 234out:
 235        mutex_unlock(&rtd->pcm_mutex);
 236        return ret;
 237}
 238
 239/*
 240 * Power down the audio subsystem pmdown_time msecs after close is called.
 241 * This is to ensure there are no pops or clicks in between any music tracks
 242 * due to DAPM power cycling.
 243 */
 244static void close_delayed_work(struct work_struct *work)
 245{
 246        struct snd_soc_pcm_runtime *rtd =
 247                        container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
 248        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 249
 250        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 251
 252        pr_debug("pop wq checking: %s status: %s waiting: %s\n",
 253                 codec_dai->driver->playback.stream_name,
 254                 codec_dai->playback_active ? "active" : "inactive",
 255                 codec_dai->pop_wait ? "yes" : "no");
 256
 257        /* are we waiting on this codec DAI stream */
 258        if (codec_dai->pop_wait == 1) {
 259                codec_dai->pop_wait = 0;
 260                snd_soc_dapm_stream_event(rtd,
 261                        codec_dai->driver->playback.stream_name,
 262                        SND_SOC_DAPM_STREAM_STOP);
 263        }
 264
 265        mutex_unlock(&rtd->pcm_mutex);
 266}
 267
 268/*
 269 * Called by ALSA when a PCM substream is closed. Private data can be
 270 * freed here. The cpu DAI, codec DAI, machine and platform are also
 271 * shutdown.
 272 */
 273static int soc_pcm_close(struct snd_pcm_substream *substream)
 274{
 275        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 276        struct snd_soc_platform *platform = rtd->platform;
 277        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 278        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 279        struct snd_soc_codec *codec = rtd->codec;
 280
 281        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 282
 283        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 284                cpu_dai->playback_active--;
 285                codec_dai->playback_active--;
 286        } else {
 287                cpu_dai->capture_active--;
 288                codec_dai->capture_active--;
 289        }
 290
 291        cpu_dai->active--;
 292        codec_dai->active--;
 293        codec->active--;
 294
 295        /* clear the corresponding DAIs rate when inactive */
 296        if (!cpu_dai->active)
 297                cpu_dai->rate = 0;
 298
 299        if (!codec_dai->active)
 300                codec_dai->rate = 0;
 301
 302        /* Muting the DAC suppresses artifacts caused during digital
 303         * shutdown, for example from stopping clocks.
 304         */
 305        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 306                snd_soc_dai_digital_mute(codec_dai, 1);
 307
 308        if (cpu_dai->driver->ops->shutdown)
 309                cpu_dai->driver->ops->shutdown(substream, cpu_dai);
 310
 311        if (codec_dai->driver->ops->shutdown)
 312                codec_dai->driver->ops->shutdown(substream, codec_dai);
 313
 314        if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
 315                rtd->dai_link->ops->shutdown(substream);
 316
 317        if (platform->driver->ops && platform->driver->ops->close)
 318                platform->driver->ops->close(substream);
 319        cpu_dai->runtime = NULL;
 320
 321        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 322                if (unlikely(codec->ignore_pmdown_time)) {
 323                        /* powered down playback stream now */
 324                        snd_soc_dapm_stream_event(rtd,
 325                                codec_dai->driver->playback.stream_name,
 326                                SND_SOC_DAPM_STREAM_STOP);
 327                } else {
 328                        /* start delayed pop wq here for playback streams */
 329                        codec_dai->pop_wait = 1;
 330                        schedule_delayed_work(&rtd->delayed_work,
 331                                msecs_to_jiffies(rtd->pmdown_time));
 332                }
 333        } else {
 334                /* capture streams can be powered down now */
 335                snd_soc_dapm_stream_event(rtd,
 336                        codec_dai->driver->capture.stream_name,
 337                        SND_SOC_DAPM_STREAM_STOP);
 338        }
 339
 340        mutex_unlock(&rtd->pcm_mutex);
 341        return 0;
 342}
 343
 344/*
 345 * Called by ALSA when the PCM substream is prepared, can set format, sample
 346 * rate, etc.  This function is non atomic and can be called multiple times,
 347 * it can refer to the runtime info.
 348 */
 349static int soc_pcm_prepare(struct snd_pcm_substream *substream)
 350{
 351        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 352        struct snd_soc_platform *platform = rtd->platform;
 353        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 354        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 355        int ret = 0;
 356
 357        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 358
 359        if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) {
 360                ret = rtd->dai_link->ops->prepare(substream);
 361                if (ret < 0) {
 362                        printk(KERN_ERR "asoc: machine prepare error\n");
 363                        goto out;
 364                }
 365        }
 366
 367        if (platform->driver->ops && platform->driver->ops->prepare) {
 368                ret = platform->driver->ops->prepare(substream);
 369                if (ret < 0) {
 370                        printk(KERN_ERR "asoc: platform prepare error\n");
 371                        goto out;
 372                }
 373        }
 374
 375        if (codec_dai->driver->ops->prepare) {
 376                ret = codec_dai->driver->ops->prepare(substream, codec_dai);
 377                if (ret < 0) {
 378                        printk(KERN_ERR "asoc: codec DAI prepare error\n");
 379                        goto out;
 380                }
 381        }
 382
 383        if (cpu_dai->driver->ops->prepare) {
 384                ret = cpu_dai->driver->ops->prepare(substream, cpu_dai);
 385                if (ret < 0) {
 386                        printk(KERN_ERR "asoc: cpu DAI prepare error\n");
 387                        goto out;
 388                }
 389        }
 390
 391        /* cancel any delayed stream shutdown that is pending */
 392        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
 393            codec_dai->pop_wait) {
 394                codec_dai->pop_wait = 0;
 395                cancel_delayed_work(&rtd->delayed_work);
 396        }
 397
 398        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 399                snd_soc_dapm_stream_event(rtd,
 400                                          codec_dai->driver->playback.stream_name,
 401                                          SND_SOC_DAPM_STREAM_START);
 402        else
 403                snd_soc_dapm_stream_event(rtd,
 404                                          codec_dai->driver->capture.stream_name,
 405                                          SND_SOC_DAPM_STREAM_START);
 406
 407        snd_soc_dai_digital_mute(codec_dai, 0);
 408
 409out:
 410        mutex_unlock(&rtd->pcm_mutex);
 411        return ret;
 412}
 413
 414/*
 415 * Called by ALSA when the hardware params are set by application. This
 416 * function can also be called multiple times and can allocate buffers
 417 * (using snd_pcm_lib_* ). It's non-atomic.
 418 */
 419static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
 420                                struct snd_pcm_hw_params *params)
 421{
 422        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 423        struct snd_soc_platform *platform = rtd->platform;
 424        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 425        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 426        int ret = 0;
 427
 428        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 429
 430        if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) {
 431                ret = rtd->dai_link->ops->hw_params(substream, params);
 432                if (ret < 0) {
 433                        printk(KERN_ERR "asoc: machine hw_params failed\n");
 434                        goto out;
 435                }
 436        }
 437
 438        if (codec_dai->driver->ops->hw_params) {
 439                ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai);
 440                if (ret < 0) {
 441                        printk(KERN_ERR "asoc: can't set codec %s hw params\n",
 442                                codec_dai->name);
 443                        goto codec_err;
 444                }
 445        }
 446
 447        if (cpu_dai->driver->ops->hw_params) {
 448                ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai);
 449                if (ret < 0) {
 450                        printk(KERN_ERR "asoc: interface %s hw params failed\n",
 451                                cpu_dai->name);
 452                        goto interface_err;
 453                }
 454        }
 455
 456        if (platform->driver->ops && platform->driver->ops->hw_params) {
 457                ret = platform->driver->ops->hw_params(substream, params);
 458                if (ret < 0) {
 459                        printk(KERN_ERR "asoc: platform %s hw params failed\n",
 460                                platform->name);
 461                        goto platform_err;
 462                }
 463        }
 464
 465        /* store the rate for each DAIs */
 466        cpu_dai->rate = params_rate(params);
 467        codec_dai->rate = params_rate(params);
 468
 469out:
 470        mutex_unlock(&rtd->pcm_mutex);
 471        return ret;
 472
 473platform_err:
 474        if (cpu_dai->driver->ops->hw_free)
 475                cpu_dai->driver->ops->hw_free(substream, cpu_dai);
 476
 477interface_err:
 478        if (codec_dai->driver->ops->hw_free)
 479                codec_dai->driver->ops->hw_free(substream, codec_dai);
 480
 481codec_err:
 482        if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
 483                rtd->dai_link->ops->hw_free(substream);
 484
 485        mutex_unlock(&rtd->pcm_mutex);
 486        return ret;
 487}
 488
 489/*
 490 * Frees resources allocated by hw_params, can be called multiple times
 491 */
 492static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
 493{
 494        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 495        struct snd_soc_platform *platform = rtd->platform;
 496        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 497        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 498        struct snd_soc_codec *codec = rtd->codec;
 499
 500        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 501
 502        /* apply codec digital mute */
 503        if (!codec->active)
 504                snd_soc_dai_digital_mute(codec_dai, 1);
 505
 506        /* free any machine hw params */
 507        if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
 508                rtd->dai_link->ops->hw_free(substream);
 509
 510        /* free any DMA resources */
 511        if (platform->driver->ops && platform->driver->ops->hw_free)
 512                platform->driver->ops->hw_free(substream);
 513
 514        /* now free hw params for the DAIs  */
 515        if (codec_dai->driver->ops->hw_free)
 516                codec_dai->driver->ops->hw_free(substream, codec_dai);
 517
 518        if (cpu_dai->driver->ops->hw_free)
 519                cpu_dai->driver->ops->hw_free(substream, cpu_dai);
 520
 521        mutex_unlock(&rtd->pcm_mutex);
 522        return 0;
 523}
 524
 525static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 526{
 527        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 528        struct snd_soc_platform *platform = rtd->platform;
 529        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 530        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 531        int ret;
 532
 533        if (codec_dai->driver->ops->trigger) {
 534                ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai);
 535                if (ret < 0)
 536                        return ret;
 537        }
 538
 539        if (platform->driver->ops && platform->driver->ops->trigger) {
 540                ret = platform->driver->ops->trigger(substream, cmd);
 541                if (ret < 0)
 542                        return ret;
 543        }
 544
 545        if (cpu_dai->driver->ops->trigger) {
 546                ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai);
 547                if (ret < 0)
 548                        return ret;
 549        }
 550        return 0;
 551}
 552
 553/*
 554 * soc level wrapper for pointer callback
 555 * If cpu_dai, codec_dai, platform driver has the delay callback, than
 556 * the runtime->delay will be updated accordingly.
 557 */
 558static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
 559{
 560        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 561        struct snd_soc_platform *platform = rtd->platform;
 562        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 563        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 564        struct snd_pcm_runtime *runtime = substream->runtime;
 565        snd_pcm_uframes_t offset = 0;
 566        snd_pcm_sframes_t delay = 0;
 567
 568        if (platform->driver->ops && platform->driver->ops->pointer)
 569                offset = platform->driver->ops->pointer(substream);
 570
 571        if (cpu_dai->driver->ops->delay)
 572                delay += cpu_dai->driver->ops->delay(substream, cpu_dai);
 573
 574        if (codec_dai->driver->ops->delay)
 575                delay += codec_dai->driver->ops->delay(substream, codec_dai);
 576
 577        if (platform->driver->delay)
 578                delay += platform->driver->delay(substream, codec_dai);
 579
 580        runtime->delay = delay;
 581
 582        return offset;
 583}
 584
 585/* ASoC PCM operations */
 586static struct snd_pcm_ops soc_pcm_ops = {
 587        .open           = soc_pcm_open,
 588        .close          = soc_pcm_close,
 589        .hw_params      = soc_pcm_hw_params,
 590        .hw_free        = soc_pcm_hw_free,
 591        .prepare        = soc_pcm_prepare,
 592        .trigger        = soc_pcm_trigger,
 593        .pointer        = soc_pcm_pointer,
 594};
 595
 596/* create a new pcm */
 597int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 598{
 599        struct snd_soc_codec *codec = rtd->codec;
 600        struct snd_soc_platform *platform = rtd->platform;
 601        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 602        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 603        struct snd_pcm *pcm;
 604        char new_name[64];
 605        int ret = 0, playback = 0, capture = 0;
 606
 607        /* check client and interface hw capabilities */
 608        snprintf(new_name, sizeof(new_name), "%s %s-%d",
 609                        rtd->dai_link->stream_name, codec_dai->name, num);
 610
 611        if (codec_dai->driver->playback.channels_min)
 612                playback = 1;
 613        if (codec_dai->driver->capture.channels_min)
 614                capture = 1;
 615
 616        dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num,new_name);
 617        ret = snd_pcm_new(rtd->card->snd_card, new_name,
 618                        num, playback, capture, &pcm);
 619        if (ret < 0) {
 620                printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name);
 621                return ret;
 622        }
 623
 624        /* DAPM dai link stream work */
 625        INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
 626
 627        rtd->pcm = pcm;
 628        pcm->private_data = rtd;
 629        if (platform->driver->ops) {
 630                soc_pcm_ops.mmap = platform->driver->ops->mmap;
 631                soc_pcm_ops.pointer = platform->driver->ops->pointer;
 632                soc_pcm_ops.ioctl = platform->driver->ops->ioctl;
 633                soc_pcm_ops.copy = platform->driver->ops->copy;
 634                soc_pcm_ops.silence = platform->driver->ops->silence;
 635                soc_pcm_ops.ack = platform->driver->ops->ack;
 636                soc_pcm_ops.page = platform->driver->ops->page;
 637        }
 638
 639        if (playback)
 640                snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops);
 641
 642        if (capture)
 643                snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops);
 644
 645        if (platform->driver->pcm_new) {
 646                ret = platform->driver->pcm_new(rtd);
 647                if (ret < 0) {
 648                        pr_err("asoc: platform pcm constructor failed\n");
 649                        return ret;
 650                }
 651        }
 652
 653        pcm->private_free = platform->driver->pcm_free;
 654        printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name,
 655                cpu_dai->name);
 656        return ret;
 657}
 658