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