]> git.karo-electronics.de Git - mv-sheeva.git/blob
1347584
[mv-sheeva.git] /
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 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  */
71 static 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
82         mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
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++;
212         mutex_unlock(&rtd->pcm_mutex);
213         return 0;
214
215 config_err:
216         if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
217                 rtd->dai_link->ops->shutdown(substream);
218
219 machine_err:
220         if (codec_dai->driver->ops->shutdown)
221                 codec_dai->driver->ops->shutdown(substream, codec_dai);
222
223 codec_dai_err:
224         if (platform->driver->ops && platform->driver->ops->close)
225                 platform->driver->ops->close(substream);
226
227 platform_err:
228         if (cpu_dai->driver->ops->shutdown)
229                 cpu_dai->driver->ops->shutdown(substream, cpu_dai);
230 out:
231         mutex_unlock(&rtd->pcm_mutex);
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  */
240 static 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
246         mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
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
261         mutex_unlock(&rtd->pcm_mutex);
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  */
269 static int soc_pcm_close(struct snd_pcm_substream *substream)
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
277         mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
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
322         mutex_unlock(&rtd->pcm_mutex);
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  */
331 static 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
339         mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
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
391 out:
392         mutex_unlock(&rtd->pcm_mutex);
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  */
401 static 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
410         mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
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
449 out:
450         mutex_unlock(&rtd->pcm_mutex);
451         return ret;
452
453 platform_err:
454         if (cpu_dai->driver->ops->hw_free)
455                 cpu_dai->driver->ops->hw_free(substream, cpu_dai);
456
457 interface_err:
458         if (codec_dai->driver->ops->hw_free)
459                 codec_dai->driver->ops->hw_free(substream, codec_dai);
460
461 codec_err:
462         if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
463                 rtd->dai_link->ops->hw_free(substream);
464
465         mutex_unlock(&rtd->pcm_mutex);
466         return ret;
467 }
468
469 /*
470  * Frees resources allocated by hw_params, can be called multiple times
471  */
472 static 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
480         mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
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
501         mutex_unlock(&rtd->pcm_mutex);
502         return 0;
503 }
504
505 static 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  */
538 static 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 */
566 static struct snd_pcm_ops soc_pcm_ops = {
567         .open           = soc_pcm_open,
568         .close          = soc_pcm_close,
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 */
577 int 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 }