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