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