blob: 9323b57152e46d973456cd90abeda253065c53ea [file] [log] [blame]
Liam Girdwooda00663b2011-01-31 21:23:17 +00001/*
2 * soc-dsp.c -- ALSA SoC Audio DSP
3 *
4 * Copyright (C) 2010 Texas Instruments Inc.
5 *
6 * Author: Liam Girdwood <lrg@slimlogic.co.uk>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 */
14
15#define DEBUG
16
17#include <linux/module.h>
18#include <linux/moduleparam.h>
19#include <linux/init.h>
20#include <linux/delay.h>
21#include <linux/pm.h>
22#include <linux/bitops.h>
23#include <linux/debugfs.h>
24#include <linux/platform_device.h>
25#include <linux/slab.h>
26#include <sound/ac97_codec.h>
27#include <sound/core.h>
28#include <sound/pcm.h>
29#include <sound/pcm_params.h>
30#include <sound/soc.h>
31#include <sound/soc-dapm.h>
32#include <sound/soc-dsp.h>
33
34int soc_pcm_open(struct snd_pcm_substream *);
35void soc_pcm_close(struct snd_pcm_substream *);
36int soc_pcm_hw_params(struct snd_pcm_substream *, struct snd_pcm_hw_params *);
37int soc_pcm_hw_free(struct snd_pcm_substream *);
38int soc_pcm_prepare(struct snd_pcm_substream *);
39int soc_pcm_trigger(struct snd_pcm_substream *, int);
40int soc_pcm_bespoke_trigger(struct snd_pcm_substream *, int);
41
Liam Girdwooda00663b2011-01-31 21:23:17 +000042static inline int be_connect(struct snd_soc_pcm_runtime *fe,
43 struct snd_soc_pcm_runtime *be, int stream)
44{
45 struct snd_soc_dsp_params *dsp_params;
46
47 /* only add new dsp_paramss */
48 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
49 if (dsp_params->be == be && dsp_params->fe == fe)
50 return 0;
51 }
52
53 dsp_params = kzalloc(sizeof(struct snd_soc_dsp_params), GFP_KERNEL);
54 if (!dsp_params)
55 return -ENOMEM;
56
57 dsp_params->be = be;
58 dsp_params->fe = fe;
59 be->dsp[stream].runtime = fe->dsp[stream].runtime;
60 dsp_params->state = SND_SOC_DSP_LINK_STATE_NEW;
61 list_add(&dsp_params->list_be, &fe->dsp[stream].be_clients);
62 list_add(&dsp_params->list_fe, &be->dsp[stream].fe_clients);
63
64 dev_dbg(&fe->dev, " connected new DSP %s path %s %s %s\n",
65 stream ? "capture" : "playback", fe->dai_link->name,
66 stream ? "<-" : "->", be->dai_link->name);
67
68#ifdef CONFIG_DEBUG_FS
69 dsp_params->debugfs_state = debugfs_create_u32(be->dai_link->name, 0644,
70 fe->debugfs_dsp_root, &dsp_params->state);
71#endif
72
73 return 1;
74}
75
76static inline void be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
77{
78 struct snd_soc_dsp_params *dsp_params, *d;
79
80 list_for_each_entry_safe(dsp_params, d, &fe->dsp[stream].be_clients, list_be) {
81 if (dsp_params->state == SND_SOC_DSP_LINK_STATE_FREE) {
82 dev_dbg(&fe->dev, " freed DSP %s path %s %s %s\n",
83 stream ? "capture" : "playback", fe->dai_link->name,
84 stream ? "<-" : "->", dsp_params->be->dai_link->name);
85
86#ifdef CONFIG_DEBUG_FS
87 debugfs_remove(dsp_params->debugfs_state);
88#endif
89
90 list_del(&dsp_params->list_be);
91 list_del(&dsp_params->list_fe);
92 kfree(dsp_params);
93 }
94 }
95}
96
Liam Girdwoodb61a8c92011-06-01 20:03:01 +010097static struct snd_soc_pcm_runtime *be_get_rtd(struct snd_soc_card *card,
98 struct snd_soc_dapm_widget *widget)
99{
100 struct snd_soc_pcm_runtime *be;
101 int i;
102
103 if (!widget->sname)
104 return NULL;
105
106 for (i = 0; i < card->num_links; i++) {
107 be = &card->rtd[i];
108
109 if (!strcmp(widget->sname, be->dai_link->stream_name))
110 return be;
111 }
112
113 return NULL;
114}
115
116static struct snd_soc_dapm_widget *be_get_widget(struct snd_soc_card *card,
117 struct snd_soc_pcm_runtime *rtd)
118{
119 struct snd_soc_dapm_widget *widget;
120
121 list_for_each_entry(widget, &card->widgets, list) {
122
123 if (!widget->sname)
124 continue;
125
126 if (!strcmp(widget->sname, rtd->dai_link->stream_name))
127 return widget;
128 }
129
130 return NULL;
131}
132
133static int widget_in_list(struct snd_soc_dapm_widget_list *list,
134 struct snd_soc_dapm_widget *widget)
135{
136 int i;
137
138 for (i = 0; i < list->num_widgets; i++) {
139 if (widget == list->widgets[i])
140 return 1;
141 }
142
143 return 0;
144}
145
Liam Girdwooda00663b2011-01-31 21:23:17 +0000146/*
147 * Find the corresponding BE DAIs that source or sink audio to this
148 * FE substream.
149 */
Liam Girdwoodb61a8c92011-06-01 20:03:01 +0100150static int dsp_add_new_paths(struct snd_soc_pcm_runtime *fe,
151 int stream, int pending)
Liam Girdwooda00663b2011-01-31 21:23:17 +0000152{
153 struct snd_soc_dai *cpu_dai = fe->cpu_dai;
154 struct snd_soc_card *card = fe->card;
Liam Girdwoodb61a8c92011-06-01 20:03:01 +0100155 struct snd_soc_dapm_widget_list *list;
Liam Girdwooda00663b2011-01-31 21:23:17 +0000156 enum snd_soc_dapm_type fe_type, be_type;
Liam Girdwoodb61a8c92011-06-01 20:03:01 +0100157 int i, count = 0, err, paths;
Liam Girdwooda00663b2011-01-31 21:23:17 +0000158
159 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
160 fe_type = snd_soc_dapm_aif_in;
161 be_type = snd_soc_dapm_aif_out;
162 } else {
Misael Lopez Cruzd5292e22011-06-06 19:54:42 -0500163 fe_type = snd_soc_dapm_aif_out;
164 be_type = snd_soc_dapm_aif_in;
Liam Girdwooda00663b2011-01-31 21:23:17 +0000165 }
166
Liam Girdwoodb61a8c92011-06-01 20:03:01 +0100167 /* get number of valid playback paths and their widgets */
168 paths = snd_soc_dapm_get_connected_widgets_type(&card->dapm,
169 cpu_dai->driver->name, &list, stream, fe_type);
Liam Girdwooda00663b2011-01-31 21:23:17 +0000170
Liam Girdwoodb61a8c92011-06-01 20:03:01 +0100171 dev_dbg(&fe->dev, "found %d audio %s paths\n", paths,
172 stream ? "capture" : "playback");
173 if (!paths)
174 goto out;
Liam Girdwooda00663b2011-01-31 21:23:17 +0000175
Liam Girdwoodb61a8c92011-06-01 20:03:01 +0100176 /* find BE DAI widgets and and connect the to FE */
177 for (i = 0; i < list->num_widgets; i++) {
178
179 if (list->widgets[i]->id == be_type) {
180 struct snd_soc_pcm_runtime *be;
181
182 /* is there a valid BE rtd for this widget */
183 be = be_get_rtd(card, list->widgets[i]);
184 if (!be) {
185 dev_err(&fe->dev, "no BE found for %s\n",
186 list->widgets[i]->name);
187 continue;
188 }
189
Misael Lopez Cruz898185f2011-07-26 22:52:28 -0500190 /* don't connect if FE is not running */
191 if (!fe->dsp[stream].runtime)
192 continue;
193
Liam Girdwoodb61a8c92011-06-01 20:03:01 +0100194 /* newly connected FE and BE */
195 err = be_connect(fe, be, stream);
196 if (err < 0) {
197 dev_err(&fe->dev, "can't connect %s\n", list->widgets[i]->name);
198 break;
199 } else if (err == 0)
200 continue;
201
202 be->dsp[stream].runtime_update = pending;
203 count++;
204 }
Liam Girdwooda00663b2011-01-31 21:23:17 +0000205 }
206
Liam Girdwoodb61a8c92011-06-01 20:03:01 +0100207out:
208 kfree(list);
Liam Girdwooda00663b2011-01-31 21:23:17 +0000209 return count;
210}
211
212/*
213 * Find the corresponding BE DAIs that source or sink audio to this
214 * FE substream.
215 */
216static int dsp_prune_old_paths(struct snd_soc_pcm_runtime *fe, int stream,
217 int pending)
218{
219 struct snd_soc_dai *cpu_dai = fe->cpu_dai;
220 struct snd_soc_card *card = fe->card;
221 struct snd_soc_dsp_params *dsp_params;
Liam Girdwoodb61a8c92011-06-01 20:03:01 +0100222 struct snd_soc_dapm_widget_list *list;
223 int count = 0, paths;
Liam Girdwooda00663b2011-01-31 21:23:17 +0000224 enum snd_soc_dapm_type fe_type, be_type;
Liam Girdwoodb61a8c92011-06-01 20:03:01 +0100225 struct snd_soc_dapm_widget *widget;
Liam Girdwooda00663b2011-01-31 21:23:17 +0000226
227 dev_dbg(&fe->dev, "scan for old %s %s streams\n", fe->dai_link->name,
228 stream ? "capture" : "playback");
229
230 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
231 fe_type = snd_soc_dapm_aif_in;
232 be_type = snd_soc_dapm_aif_out;
233 } else {
234 fe_type = snd_soc_dapm_aif_out;
235 be_type = snd_soc_dapm_aif_in;
236 }
237
Liam Girdwoodb61a8c92011-06-01 20:03:01 +0100238 /* get number of valid playback paths and their widgets */
239 paths = snd_soc_dapm_get_connected_widgets_type(&card->dapm,
240 cpu_dai->driver->name, &list, stream, fe_type);
Liam Girdwooda00663b2011-01-31 21:23:17 +0000241
Liam Girdwoodb61a8c92011-06-01 20:03:01 +0100242 dev_dbg(&fe->dev, "found %d audio %s paths\n", paths,
243 stream ? "capture" : "playback");
244 if (!paths) {
245 /* prune all BEs */
246 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
Liam Girdwooda00663b2011-01-31 21:23:17 +0000247
Liam Girdwoodb61a8c92011-06-01 20:03:01 +0100248 dsp_params->state = SND_SOC_DSP_LINK_STATE_FREE;
249 dsp_params->be->dsp[stream].runtime_update = pending;
250 count++;
251 }
252
253 dev_dbg(&fe->dev, "pruned all %s BE for FE %s\n", fe->dai_link->name,
254 stream ? "capture" : "playback");
255 goto out;
Liam Girdwooda00663b2011-01-31 21:23:17 +0000256 }
257
Liam Girdwooda00663b2011-01-31 21:23:17 +0000258 /* search card for valid BE AIFs */
259 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
260
Liam Girdwoodb61a8c92011-06-01 20:03:01 +0100261 /* is there a valid widget for this BE */
262 widget = be_get_widget(card, dsp_params->be);
263 if (!widget) {
264 dev_err(&fe->dev, "no widget found for %s\n",
265 dsp_params->be->dai_link->name);
Liam Girdwooda00663b2011-01-31 21:23:17 +0000266 continue;
267 }
268
Liam Girdwoodb61a8c92011-06-01 20:03:01 +0100269 /* prune the BE if it's no longer in our active list */
270 if (widget_in_list(list, widget))
Liam Girdwooda00663b2011-01-31 21:23:17 +0000271 continue;
272
Liam Girdwoodb61a8c92011-06-01 20:03:01 +0100273 dev_dbg(&fe->dev, "pruning %s BE %s for %s\n",
274 stream ? "capture" : "playback", dsp_params->be->dai_link->name,
275 fe->dai_link->name);
Liam Girdwooda00663b2011-01-31 21:23:17 +0000276 dsp_params->state = SND_SOC_DSP_LINK_STATE_FREE;
277 dsp_params->be->dsp[stream].runtime_update = pending;
278 count++;
279 }
280
281 /* the number of old paths pruned */
Liam Girdwoodb61a8c92011-06-01 20:03:01 +0100282out:
283 kfree(list);
Liam Girdwooda00663b2011-01-31 21:23:17 +0000284 return count;
285}
286
287/*
288 * Update the state of all BE's with state old to state new.
289 */
290static void be_state_update(struct snd_soc_pcm_runtime *fe, int stream,
291 enum snd_soc_dsp_link_state old, enum snd_soc_dsp_link_state new)
292{
293 struct snd_soc_dsp_params *dsp_params;
294
295 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
296 if (dsp_params->state == old)
297 dsp_params->state = new;
298 }
299}
300
301/*
302 * Update the state of all BE's to new regardless of current state.
303 */
304static void fe_state_update(struct snd_soc_pcm_runtime *fe, int stream,
305 enum snd_soc_dsp_link_state new)
306{
307 struct snd_soc_dsp_params *dsp_params;
308
309 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be)
310 dsp_params->state = new;
311}
312
313/*
314 * Clear the runtime pending state of all BE's.
315 */
316static void fe_clear_pending(struct snd_soc_pcm_runtime *fe, int stream)
317{
318 struct snd_soc_dsp_params *dsp_params;
319
320 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be)
321 dsp_params->be->dsp[stream].runtime_update = 0;
322}
323
324/* Unwind the BE startup */
325static void soc_dsp_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe, int stream)
326{
327 struct snd_soc_dsp_params *dsp_params;
328
329 /* disable any enabled and non active backends */
330 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
331
332 struct snd_pcm_substream *be_substream =
333 snd_soc_dsp_get_substream(dsp_params->be, stream);
334
335 if (--dsp_params->be->dsp[stream].users != 0)
336 continue;
337
338 if (dsp_params->state != SND_SOC_DSP_LINK_STATE_NEW)
339 continue;
340
341 soc_pcm_close(be_substream);
342 be_substream->runtime = NULL;
343 }
344}
345
346/* Startup all new BE */
347static int soc_dsp_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
348{
349 struct snd_soc_dsp_params *dsp_params;
350 int err, count = 0;
351
352 /* only startup BE DAIs that are either sinks or sources to this FE DAI */
353 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
354
355 struct snd_pcm_substream *be_substream =
356 snd_soc_dsp_get_substream(dsp_params->be, stream);
357
358 /* is this op for this BE ? */
359 if (fe->dsp[stream].runtime_update &&
360 !dsp_params->be->dsp[stream].runtime_update)
361 continue;
362
363 /* first time the dsp_params is open ? */
364 if (dsp_params->be->dsp[stream].users++ != 0)
365 continue;
366
367 /* only open and ref count new links */
368 if (dsp_params->state != SND_SOC_DSP_LINK_STATE_NEW)
369 continue;
370
371 dev_dbg(&dsp_params->be->dev, "dsp: open BE %s\n",
372 dsp_params->be->dai_link->name);
373
374 be_substream->runtime = dsp_params->be->dsp[stream].runtime;
375 err = soc_pcm_open(be_substream);
376 if (err < 0)
377 goto unwind;
378 count++;
379 }
380
381 /* update BE state */
382 be_state_update(fe, stream,
383 SND_SOC_DSP_LINK_STATE_NEW, SND_SOC_DSP_LINK_STATE_HW_PARAMS);
384 return count;
385
386unwind:
387 /* disable any enabled and non active backends */
388 list_for_each_entry_continue_reverse(dsp_params, &fe->dsp[stream].be_clients, list_be) {
389
390 struct snd_pcm_substream *be_substream =
391 snd_soc_dsp_get_substream(dsp_params->be, stream);
392
393 if (fe->dsp[stream].runtime_update &&
394 !dsp_params->be->dsp[stream].runtime_update)
395 continue;
396
397 if (--dsp_params->be->dsp[stream].users != 0)
398 continue;
399
400 if (dsp_params->state != SND_SOC_DSP_LINK_STATE_NEW)
401 continue;
402
403 soc_pcm_close(be_substream);
404 be_substream->runtime = NULL;
405 }
406
407 /* update BE state for disconnect */
408 be_state_update(fe, stream,
409 SND_SOC_DSP_LINK_STATE_NEW, SND_SOC_DSP_LINK_STATE_FREE);
410 return err;
411}
412
413void soc_dsp_set_dynamic_runtime(struct snd_pcm_substream *substream)
414{
415 struct snd_pcm_runtime *runtime = substream->runtime;
416 struct snd_soc_pcm_runtime *rtd = substream->private_data;
417 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
418 struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
419
420 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
421 runtime->hw.rate_min = cpu_dai_drv->playback.rate_min;
422 runtime->hw.rate_max = cpu_dai_drv->playback.rate_max;
423 runtime->hw.channels_min = cpu_dai_drv->playback.channels_min;
424 runtime->hw.channels_max = cpu_dai_drv->playback.channels_max;
425 runtime->hw.formats &= cpu_dai_drv->playback.formats;
426 runtime->hw.rates = cpu_dai_drv->playback.rates;
427 } else {
428 runtime->hw.rate_min = cpu_dai_drv->capture.rate_min;
429 runtime->hw.rate_max = cpu_dai_drv->capture.rate_max;
430 runtime->hw.channels_min = cpu_dai_drv->capture.channels_min;
431 runtime->hw.channels_max = cpu_dai_drv->capture.channels_max;
432 runtime->hw.formats &= cpu_dai_drv->capture.formats;
433 runtime->hw.rates = cpu_dai_drv->capture.rates;
434 }
435}
436
437static int soc_dsp_fe_dai_startup(struct snd_pcm_substream *fe_substream)
438{
439 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
440 struct snd_pcm_runtime *runtime = fe_substream->runtime;
441 int ret = 0;
442
Liam Girdwoodfb7926c2011-07-04 17:23:32 +0200443 mutex_lock_nested(&fe->card->dsp_mutex, 0);
Liam Girdwooda00663b2011-01-31 21:23:17 +0000444
445 ret = soc_dsp_be_dai_startup(fe, fe_substream->stream);
446 if (ret < 0)
447 goto be_err;
448
449 dev_dbg(&fe->dev, "dsp: open FE %s\n", fe->dai_link->name);
450
451 /* start the DAI frontend */
452 ret = soc_pcm_open(fe_substream);
453 if (ret < 0) {
454 dev_err(&fe->dev,"dsp: failed to start FE %d\n", ret);
455 goto unwind;
456 }
457
458 soc_dsp_set_dynamic_runtime(fe_substream);
459 snd_pcm_limit_hw_rates(runtime);
460
461 mutex_unlock(&fe->card->dsp_mutex);
462 return 0;
463
464unwind:
465 soc_dsp_be_dai_startup_unwind(fe, fe_substream->stream);
466be_err:
467 mutex_unlock(&fe->card->dsp_mutex);
468 return ret;
469}
470
471/* BE shutdown - called on DAPM sync updates (i.e. FE is already running)*/
472static int soc_dsp_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
473{
474 struct snd_soc_dsp_params *dsp_params;
475
476 /* only shutdown backends that are either sinks or sources to this frontend DAI */
477 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
478
479 struct snd_pcm_substream *be_substream =
480 snd_soc_dsp_get_substream(dsp_params->be, stream);
481
482 /* is this op for this BE ? */
483 if (fe->dsp[stream].runtime_update &&
484 !dsp_params->be->dsp[stream].runtime_update)
485 continue;
486
487 if (--dsp_params->be->dsp[stream].users != 0)
488 continue;
489
490 if (dsp_params->state != SND_SOC_DSP_LINK_STATE_FREE)
491 continue;
492
493 dev_dbg(&dsp_params->be->dev, "dsp: close BE %s\n",
494 dsp_params->fe->dai_link->name);
495
496 soc_pcm_close(be_substream);
497 be_substream->runtime = NULL;
498 }
499 return 0;
500}
501
502/* FE +BE shutdown - called on FE PCM ops */
503static int soc_dsp_fe_dai_shutdown(struct snd_pcm_substream *substream)
504{
505 struct snd_soc_pcm_runtime *fe = substream->private_data;
506 int stream = substream->stream;
507
Liam Girdwoodfb7926c2011-07-04 17:23:32 +0200508 mutex_lock_nested(&fe->card->dsp_mutex, 0);
Liam Girdwooda00663b2011-01-31 21:23:17 +0000509
510 /* shutdown the BEs */
511 soc_dsp_be_dai_shutdown(fe, substream->stream);
512
513 dev_dbg(&fe->dev, "dsp: close FE %s\n", fe->dai_link->name);
514
515 /* now shutdown the frontend */
516 soc_pcm_close(substream);
517
518 /* run the stream event for each BE */
519 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
520 soc_dsp_dapm_stream_event(fe, stream,
521 fe->cpu_dai->driver->playback.stream_name,
522 SND_SOC_DAPM_STREAM_STOP);
523 else
524 soc_dsp_dapm_stream_event(fe, stream,
525 fe->cpu_dai->driver->capture.stream_name,
526 SND_SOC_DAPM_STREAM_STOP);
527
528 mutex_unlock(&fe->card->dsp_mutex);
529 return 0;
530}
531
532static int soc_dsp_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
533{
534 struct snd_soc_dsp_params *dsp_params;
535 int ret;
536
537 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
538
539 struct snd_pcm_substream *be_substream =
540 snd_soc_dsp_get_substream(dsp_params->be, stream);
541
542 /* is this op for this BE ? */
543 if (fe->dsp[stream].runtime_update &&
544 !dsp_params->be->dsp[stream].runtime_update)
545 continue;
546
547 if (dsp_params->state != SND_SOC_DSP_LINK_STATE_HW_PARAMS)
548 continue;
549
550 /* first time the dsp_params is open ? */
551 if (dsp_params->be->dsp[stream].users != 1)
552 continue;
553
554 dev_dbg(&dsp_params->be->dev, "dsp: hw_params BE %s\n",
555 dsp_params->fe->dai_link->name);
556
557 /* copy params for each dsp_params */
558 memcpy(&dsp_params->params, &fe->dsp[stream].params,
559 sizeof(struct snd_pcm_hw_params));
560
561 /* perform any hw_params fixups */
562 if (dsp_params->be->dai_link->be_hw_params_fixup) {
563 ret = dsp_params->be->dai_link->be_hw_params_fixup(dsp_params->be,
564 &dsp_params->params);
565 if (ret < 0) {
566 dev_err(&dsp_params->be->dev,
567 "dsp: hw_params BE fixup failed %d\n", ret);
568 return ret;
569 }
570 }
571
572 ret = soc_pcm_hw_params(be_substream, &dsp_params->params);
573 if (ret < 0) {
574 dev_err(&dsp_params->be->dev, "dsp: hw_params BE failed %d\n", ret);
575 return ret;
576 }
577 }
578 return 0;
579}
580
581int soc_dsp_fe_dai_hw_params(struct snd_pcm_substream *substream,
582 struct snd_pcm_hw_params *params)
583{
584 struct snd_soc_pcm_runtime *fe = substream->private_data;
585 int ret;
586
Liam Girdwoodfb7926c2011-07-04 17:23:32 +0200587 mutex_lock_nested(&fe->card->dsp_mutex, 0);
Liam Girdwooda00663b2011-01-31 21:23:17 +0000588
589 memcpy(&fe->dsp[substream->stream].params, params,
590 sizeof(struct snd_pcm_hw_params));
591 ret = soc_dsp_be_dai_hw_params(fe, substream->stream);
592 if (ret < 0)
593 goto out;
594
595 dev_dbg(&fe->dev, "dsp: hw_params FE %s\n", fe->dai_link->name);
596
597 /* call hw_params on the frontend */
598 ret = soc_pcm_hw_params(substream, params);
599 if (ret < 0)
600 dev_err(&fe->dev,"dsp: hw_params FE failed %d\n", ret);
601
602out:
603 mutex_unlock(&fe->card->dsp_mutex);
604 return ret;
605}
606
607static int dsp_do_trigger(struct snd_soc_dsp_params *dsp_params,
608 struct snd_pcm_substream *substream, int cmd)
609{
610 int ret;
611
612 dev_dbg(&dsp_params->be->dev, "dsp: trigger BE %s cmd %d\n",
613 dsp_params->fe->dai_link->name, cmd);
614
615 ret = soc_pcm_trigger(substream, cmd);
616 if (ret < 0)
617 dev_err(&dsp_params->be->dev,"dsp: trigger BE failed %d\n", ret);
618
619 return ret;
620}
621
622int soc_dsp_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, int cmd)
623{
624 struct snd_soc_dsp_params *dsp_params;
625 int ret = 0;
626
627 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
628
629 struct snd_pcm_substream *be_substream =
630 snd_soc_dsp_get_substream(dsp_params->be, stream);
631
632 /* is this op for this BE ? */
633 if (fe->dsp[stream].runtime_update &&
634 !dsp_params->be->dsp[stream].runtime_update)
635 continue;
636
637 switch (cmd) {
638 case SNDRV_PCM_TRIGGER_START:
639 /* only start BEs that are not triggered */
640 if (dsp_params->state == SND_SOC_DSP_LINK_STATE_PREPARE) {
641 ret = dsp_do_trigger(dsp_params, be_substream, cmd);
642 if (ret == 0)
643 dsp_params->state = SND_SOC_DSP_LINK_STATE_START;
644 }
645 break;
646 case SNDRV_PCM_TRIGGER_STOP:
647 /* only stop BEs that are being shutdown */
648 if (dsp_params->state == SND_SOC_DSP_LINK_STATE_FREE &&
649 dsp_params->be->dsp[stream].users == 1)
650 ret = dsp_do_trigger(dsp_params, be_substream, cmd);
651 break;
652 case SNDRV_PCM_TRIGGER_SUSPEND:
653 case SNDRV_PCM_TRIGGER_RESUME:
654 /* suspend and resume all BEs */
655 ret = dsp_do_trigger(dsp_params, be_substream, cmd);
656 break;
657 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
658 /* only release Paused BEs */
659 if (dsp_params->state == SND_SOC_DSP_LINK_STATE_PAUSED) {
660 ret = dsp_do_trigger(dsp_params, be_substream, cmd);
661 if (ret == 0)
662 dsp_params->state = SND_SOC_DSP_LINK_STATE_START;
663 }
664 break;
665 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
666 /* only pause active BEs */
667 if (dsp_params->state == SND_SOC_DSP_LINK_STATE_START) {
668 ret = dsp_do_trigger(dsp_params, be_substream, cmd);
669 if (ret == 0)
670 dsp_params->state = SND_SOC_DSP_LINK_STATE_PAUSED;
671 }
672 break;
673 }
674 if (ret < 0)
675 return ret;
676 }
677
678 return ret;
679}
680EXPORT_SYMBOL_GPL(soc_dsp_be_dai_trigger);
681
682int soc_dsp_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
683{
684 struct snd_soc_pcm_runtime *fe = substream->private_data;
685 struct snd_soc_dsp_link *dsp_link = fe->dai_link->dsp_link;
686 int stream = substream->stream, ret;
687
688 switch (dsp_link->trigger[stream]) {
689 case SND_SOC_DSP_TRIGGER_PRE:
690 /* call trigger on the frontend before the backend. */
691
692 dev_dbg(&fe->dev, "dsp: pre trigger FE %s cmd %d\n",
693 fe->dai_link->name, cmd);
694
695 ret = soc_pcm_trigger(substream, cmd);
696 if (ret < 0) {
697 dev_err(&fe->dev,"dsp: trigger FE failed %d\n", ret);
698 return ret;
699 }
700
701 ret = soc_dsp_be_dai_trigger(fe, substream->stream, cmd);
702 break;
703 case SND_SOC_DSP_TRIGGER_POST:
704 /* call trigger on the frontend after the backend. */
705
706 ret = soc_dsp_be_dai_trigger(fe, substream->stream, cmd);
707 if (ret < 0) {
708 dev_err(&fe->dev,"dsp: trigger FE failed %d\n", ret);
709 return ret;
710 }
711
712 dev_dbg(&fe->dev, "dsp: post trigger FE %s cmd %d\n",
713 fe->dai_link->name, cmd);
714
715 ret = soc_pcm_trigger(substream, cmd);
716 break;
717 case SND_SOC_DSP_TRIGGER_BESPOKE:
718 /* bespoke trigger() - handles both FE and BEs */
719
720 dev_dbg(&fe->dev, "dsp: bespoke trigger FE %s cmd %d\n",
721 fe->dai_link->name, cmd);
722
723 ret = soc_pcm_bespoke_trigger(substream, cmd);
724 if (ret < 0) {
725 dev_err(&fe->dev,"dsp: trigger FE failed %d\n", ret);
726 return ret;
727 }
728 break;
729 default:
730 dev_err(&fe->dev, "dsp: invalid trigger cmd %d for %s\n", cmd,
731 fe->dai_link->name);
732 return -EINVAL;
733 }
734
735 return ret;
736}
737
738static int soc_dsp_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
739{
740 struct snd_soc_dsp_params *dsp_params;
741 int ret = 0;
742
743 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
744
745 struct snd_pcm_substream *be_substream =
746 snd_soc_dsp_get_substream(dsp_params->be, stream);
747
748 /* is this op for this BE ? */
749 if (fe->dsp[stream].runtime_update &&
750 !dsp_params->be->dsp[stream].runtime_update)
751 continue;
752
753 /* only prepare ACTIVE or READY BE's */
754 if (dsp_params->state == SND_SOC_DSP_LINK_STATE_NEW ||
755 dsp_params->state == SND_SOC_DSP_LINK_STATE_FREE)
756 continue;
757
758 dev_dbg(&dsp_params->be->dev, "dsp: prepare BE %s\n",
759 dsp_params->fe->dai_link->name);
760
761 ret = soc_pcm_prepare(be_substream);
762 if (ret < 0) {
763 dev_err(&dsp_params->be->dev,"dsp: backend prepare failed %d\n",
764 ret);
765 break;
766 }
767
768 /* mark the BE as active */
769 be_state_update(fe, stream, SND_SOC_DSP_LINK_STATE_HW_PARAMS,
770 SND_SOC_DSP_LINK_STATE_PREPARE);
771 }
772 return ret;
773}
774
775int soc_dsp_fe_dai_prepare(struct snd_pcm_substream *substream)
776{
777 struct snd_soc_pcm_runtime *fe = substream->private_data;
778 int stream = substream->stream, ret = 0;
779
Liam Girdwoodfb7926c2011-07-04 17:23:32 +0200780 mutex_lock_nested(&fe->card->dsp_mutex, 0);
Liam Girdwooda00663b2011-01-31 21:23:17 +0000781
782 dev_dbg(&fe->dev, "dsp: prepare FE %s\n", fe->dai_link->name);
783
784 /* there is no point preparing this FE if there are no BEs */
785 if (list_empty(&fe->dsp[stream].be_clients)) {
786 dev_err(&fe->dev, "dsp: no backend DAIs enabled for %s\n",
787 fe->dai_link->name);
788 ret = -EINVAL;
789 goto out;
790 }
791
792 ret = soc_dsp_be_dai_prepare(fe, substream->stream);
793 if (ret < 0)
794 goto out;
795
796 /* mark the BE as active */
797 fe_state_update(fe, stream, SND_SOC_DSP_LINK_STATE_PREPARE);
798
799 /* call prepare on the frontend */
800 ret = soc_pcm_prepare(substream);
801 if (ret < 0) {
802 dev_err(&fe->dev,"dsp: prepare FE %s failed\n", fe->dai_link->name);
803 goto out;
804 }
805
806 /* run the stream event for each BE */
807 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
808 soc_dsp_dapm_stream_event(fe, stream,
809 fe->cpu_dai->driver->playback.stream_name,
810 SNDRV_PCM_TRIGGER_START);
811 else
812 soc_dsp_dapm_stream_event(fe, stream,
813 fe->cpu_dai->driver->capture.stream_name,
814 SNDRV_PCM_TRIGGER_START);
815
816out:
817 mutex_unlock(&fe->card->dsp_mutex);
818 return ret;
819}
820
821static int soc_dsp_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
822{
823 struct snd_soc_dsp_params *dsp_params;
824
825 /* only hw_params backends that are either sinks or sources
826 * to this frontend DAI */
827 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
828
829 struct snd_pcm_substream *be_substream =
830 snd_soc_dsp_get_substream(dsp_params->be, stream);
831
832 /* is this op for this BE ? */
833 if (fe->dsp[stream].runtime_update &&
834 !dsp_params->be->dsp[stream].runtime_update)
835 continue;
836
837 if (dsp_params->state != SND_SOC_DSP_LINK_STATE_FREE)
838 continue;
839
840 /* only free hw when no longer used */
841 if (dsp_params->be->dsp[stream].users != 1)
842 continue;
843
844 dev_dbg(&dsp_params->be->dev, "dsp: hw_free BE %s\n",
845 dsp_params->fe->dai_link->name);
846
847 soc_pcm_hw_free(be_substream);
848 }
849
850 return 0;
851}
852
853int soc_dsp_fe_dai_hw_free(struct snd_pcm_substream *substream)
854{
855 struct snd_soc_pcm_runtime *fe = substream->private_data;
856 int ret, stream = substream->stream;
857
Liam Girdwoodfb7926c2011-07-04 17:23:32 +0200858 mutex_lock_nested(&fe->card->dsp_mutex, 0);
Liam Girdwooda00663b2011-01-31 21:23:17 +0000859
860 fe_state_update(fe, stream, SND_SOC_DSP_LINK_STATE_FREE);
861
862 dev_dbg(&fe->dev, "dsp: hw_free FE %s\n", fe->dai_link->name);
863
864 /* call hw_free on the frontend */
865 ret = soc_pcm_hw_free(substream);
866 if (ret < 0)
867 dev_err(&fe->dev,"dsp: hw_free FE %s failed\n", fe->dai_link->name);
868
869 /* only hw_params backends that are either sinks or sources
870 * to this frontend DAI */
871 ret = soc_dsp_be_dai_hw_free(fe, stream);
872
873 mutex_unlock(&fe->card->dsp_mutex);
874 return ret;
875}
876
877/*
878 * FE stream event, send event to all active BEs.
879 */
880int soc_dsp_dapm_stream_event(struct snd_soc_pcm_runtime *fe,
881 int dir, const char *stream, int event)
882{
883 struct snd_soc_dsp_params *dsp_params;
884
885 /* resume for playback */
886 list_for_each_entry(dsp_params, &fe->dsp[dir].be_clients, list_be) {
887
888 struct snd_soc_pcm_runtime *be = dsp_params->be;
889
890 dev_dbg(&be->dev, "pm: BE %s stream %s event %d dir %d\n",
891 be->dai_link->name, stream, event, dir);
892
893 snd_soc_dapm_stream_event(be, stream, event);
894 }
895
896 return 0;
897}
898
899static int dsp_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
900{
901 struct snd_soc_dsp_link *dsp_link = fe->dai_link->dsp_link;
902 struct snd_pcm_substream *substream = snd_soc_dsp_get_substream(fe, stream);
903 struct snd_soc_dsp_params *dsp_params;
904 int ret;
905
906 dev_dbg(&fe->dev, "runtime %s close on FE %s\n",
907 stream ? "capture" : "playback", fe->dai_link->name);
908
909 if (dsp_link->trigger[stream] == SND_SOC_DSP_TRIGGER_BESPOKE) {
910 /* call bespoke trigger - FE takes care of all BE triggers */
911 dev_dbg(&fe->dev, "dsp: bespoke trigger FE %s cmd stop\n",
912 fe->dai_link->name);
913
914 ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
915 if (ret < 0) {
916 dev_err(&fe->dev,"dsp: trigger FE failed %d\n", ret);
917 return ret;
918 }
919 } else {
920
921 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
922
923 dev_dbg(&fe->dev, "dsp: trigger FE %s cmd stop\n",
924 fe->dai_link->name);
925
926 ret = soc_dsp_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
927 if (ret < 0)
928 return ret;
929 }
930 }
931
932 ret = soc_dsp_be_dai_hw_free(fe, stream);
933 if (ret < 0)
934 return ret;
935
936 ret = soc_dsp_be_dai_shutdown(fe, stream);
937 if (ret < 0)
938 return ret;
939
940 /* run the stream event for each BE */
941 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
942 soc_dsp_dapm_stream_event(fe, stream,
943 fe->cpu_dai->driver->playback.stream_name,
944 SNDRV_PCM_TRIGGER_STOP);
945 else
946 soc_dsp_dapm_stream_event(fe, stream,
947 fe->cpu_dai->driver->capture.stream_name,
948 SNDRV_PCM_TRIGGER_STOP);
949
950 return 0;
951}
952
953/* check for running FEs */
954static int dsp_get_be_trigger_cmd(struct snd_soc_pcm_runtime *fe, int stream)
955{
956 struct snd_soc_dsp_params *dsp_be_params, *dsp_fe_params;
957
958 /* get the FEs for each BE */
959 list_for_each_entry(dsp_be_params, &fe->dsp[stream].be_clients, list_be) {
960 struct snd_soc_pcm_runtime *be = dsp_be_params->be;
961
962 /* get the FEs for this BE */
963 list_for_each_entry(dsp_fe_params, &be->dsp[stream].fe_clients, list_fe) {
964
965 if (dsp_fe_params->state == SND_SOC_DSP_LINK_STATE_START)
966 return SND_SOC_DSP_LINK_STATE_START;
967 }
968 }
969 return SND_SOC_DSP_LINK_STATE_PAUSED;
970}
971
972/* check for running BEs */
973static int dsp_get_fe_trigger_cmd(struct snd_soc_pcm_runtime *fe, int stream)
974{
975 struct snd_soc_dsp_params *dsp_be_params;
976
977 /* get the FEs for each BE */
978 list_for_each_entry(dsp_be_params, &fe->dsp[stream].be_clients, list_be) {
979
980 if (dsp_be_params->state == SND_SOC_DSP_LINK_STATE_START)
981 return SND_SOC_DSP_LINK_STATE_START;
982 }
983 return SND_SOC_DSP_LINK_STATE_PAUSED;
984}
985
986static int dsp_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
987{
988 struct snd_soc_dsp_link *dsp_link = fe->dai_link->dsp_link;
989 struct snd_pcm_substream *substream = snd_soc_dsp_get_substream(fe, stream);
990 struct snd_soc_dsp_params *dsp_params;
991 int ret, cmd;
992
993 dev_dbg(&fe->dev, "runtime %s open on FE %s\n",
994 stream ? "capture" : "playback", fe->dai_link->name);
995
996 ret = soc_dsp_be_dai_startup(fe, stream);
997 if (ret < 0)
998 return ret;
999
1000 ret = soc_dsp_be_dai_hw_params(fe, stream);
1001 if (ret < 0)
1002 return ret;
1003
1004 ret = soc_dsp_be_dai_prepare(fe, stream);
1005 if (ret < 0)
1006 return ret;
1007
1008 /* run the stream event for each BE */
1009 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1010 soc_dsp_dapm_stream_event(fe, stream,
1011 fe->cpu_dai->driver->playback.stream_name,
1012 SNDRV_PCM_TRIGGER_START);
1013 else
1014 soc_dsp_dapm_stream_event(fe, stream,
1015 fe->cpu_dai->driver->capture.stream_name,
1016 SNDRV_PCM_TRIGGER_START);
1017
1018 if (dsp_link->trigger[stream] == SND_SOC_DSP_TRIGGER_BESPOKE) {
1019
1020 /* there is no point in triggering START iff all BEs are PAUSED */
1021 cmd = dsp_get_fe_trigger_cmd(fe, stream);
1022
1023 /* call trigger on the frontend - FE takes care of all BE triggers */
1024 dev_dbg(&fe->dev, "dsp: bespoke trigger FE %s cmd start\n",
1025 fe->dai_link->name);
1026
1027 ret = soc_pcm_bespoke_trigger(substream, cmd);
1028 if (ret < 0) {
1029 dev_err(&fe->dev,"dsp: trigger FE failed %d\n", ret);
1030 return ret;
1031 }
1032
1033 /* successful trigger so update BE trigger status */
1034 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
1035
1036 /* is this op for this BE ? */
1037 if (fe->dsp[stream].runtime_update &&
1038 !dsp_params->be->dsp[stream].runtime_update)
1039 continue;
1040
1041 switch (cmd) {
1042 case SNDRV_PCM_TRIGGER_START:
1043 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1044 case SNDRV_PCM_TRIGGER_RESUME:
1045 dsp_params->state = SND_SOC_DSP_LINK_STATE_START;
1046 break;
1047 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
1048 case SNDRV_PCM_TRIGGER_STOP:
1049 case SNDRV_PCM_TRIGGER_SUSPEND:
1050 dsp_params->state = SND_SOC_DSP_LINK_STATE_PAUSED;
1051 break;
1052 }
1053 }
1054 } else {
1055
1056 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
1057
1058 /* there is no point in triggering start iff all FEs are PAUSED */
1059 cmd = dsp_get_be_trigger_cmd(fe, stream);
1060
1061 dev_dbg(&fe->dev, "dsp: trigger FE %s cmd start\n",
1062 fe->dai_link->name);
1063
1064 ret = soc_dsp_be_dai_trigger(fe, stream, cmd);
1065 if (ret < 0)
1066 return ret;
1067 }
1068 }
1069
1070 return 0;
1071}
1072
1073static int dsp_run_update(struct snd_soc_pcm_runtime *fe, int stream,
1074 int start, int stop)
1075{
1076 int ret = 0;
1077
1078 fe->dsp[stream].runtime_update = 1;
1079
1080 /* startup any new BEs */
1081 if (start) {
1082 ret = dsp_run_update_startup(fe, stream);
1083 if (ret < 0)
1084 dev_err(&fe->dev, "failed to startup BEs\n");
1085 }
1086
1087 /* close down old BEs */
1088 if (stop) {
1089 ret = dsp_run_update_shutdown(fe, stream);
1090 if (ret < 0)
1091 dev_err(&fe->dev, "failed to shutdown BEs\n");
1092 }
1093
1094 fe->dsp[stream].runtime_update = 0;
1095
1096 return ret;
1097}
1098
1099/* called when any mixer updates change FE -> BE the stream */
1100int soc_dsp_runtime_update(struct snd_soc_dapm_widget *widget)
1101{
1102 struct snd_soc_card *card;
1103 int i, ret = 0, start, stop;
1104
1105 if (widget->codec)
1106 card = widget->codec->card;
1107 else if (widget->platform)
1108 card = widget->platform->card;
1109 else
1110 return -EINVAL;
1111
Liam Girdwoodfb7926c2011-07-04 17:23:32 +02001112 mutex_lock_nested(&widget->dapm->card->dsp_mutex, 1);
Liam Girdwooda00663b2011-01-31 21:23:17 +00001113
1114 for (i = 0; i < card->num_rtd; i++) {
1115 struct snd_soc_pcm_runtime *fe = &card->rtd[i];
1116
1117 /* make sure link is BE */
1118 if (!fe->dai_link->dsp_link)
1119 continue;
1120
1121 /* only check active links */
1122 if (!fe->cpu_dai->active) {
1123 continue;
1124 }
1125
1126 /* DAPM sync will call this to update DSP paths */
1127 dev_dbg(card->dev, "DSP runtime update for FE %s\n", fe->dai_link->name);
1128
1129 /* update any playback paths */
1130 start = dsp_add_new_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, 1);
1131 stop = dsp_prune_old_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, 1);
1132 if (!(start || stop))
1133 goto capture;
1134
1135 /* run PCM ops on new/old playback paths */
1136 ret = dsp_run_update(fe, SNDRV_PCM_STREAM_PLAYBACK, start, stop);
1137 if (ret < 0) {
1138 dev_err(&fe->dev, "failed to update playback FE stream %s\n",
1139 fe->dai_link->stream_name);
1140 }
1141
1142 /* free old playback links */
1143 be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
1144 fe_clear_pending(fe, SNDRV_PCM_STREAM_PLAYBACK);
1145
1146capture:
1147 /* update any capture paths */
1148 start = dsp_add_new_paths(fe, SNDRV_PCM_STREAM_CAPTURE, 1);
1149 stop = dsp_prune_old_paths(fe, SNDRV_PCM_STREAM_CAPTURE, 1);
1150 if (!(start || stop))
1151 continue;
1152
1153 /* run PCM ops on new/old capture paths */
1154 ret = dsp_run_update(fe, SNDRV_PCM_STREAM_CAPTURE, start, stop);
1155 if (ret < 0) {
1156 dev_err(&fe->dev, "failed to update capture FE stream %s\n",
1157 fe->dai_link->stream_name);
1158 }
1159
1160 /* free old capture links */
1161 be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
1162 fe_clear_pending(fe, SNDRV_PCM_STREAM_CAPTURE);
1163 }
1164
1165 mutex_unlock(&widget->dapm->card->dsp_mutex);
1166 return ret;
1167}
1168
1169int soc_dsp_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute)
1170{
1171 struct snd_soc_dsp_params *dsp_params;
1172
1173 list_for_each_entry(dsp_params,
1174 &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
1175
1176 struct snd_soc_pcm_runtime *be = dsp_params->be;
1177 struct snd_soc_dai *dai = be->codec_dai;
1178 struct snd_soc_dai_driver *drv = dai->driver;
1179
1180 dev_dbg(&be->dev, "BE digital mute %s\n", be->dai_link->name);
1181
1182 if (be->dai_link->ignore_suspend)
1183 continue;
1184
1185 if (drv->ops->digital_mute && dai->playback_active)
1186 drv->ops->digital_mute(dai, mute);
1187 }
1188
1189 return 0;
1190}
1191
1192int soc_dsp_be_cpu_dai_suspend(struct snd_soc_pcm_runtime *fe)
1193{
1194 struct snd_soc_dsp_params *dsp_params;
1195
1196 /* suspend for playback */
1197 list_for_each_entry(dsp_params,
1198 &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
1199
1200 struct snd_soc_pcm_runtime *be = dsp_params->be;
1201 struct snd_soc_dai *dai = be->cpu_dai;
1202 struct snd_soc_dai_driver *drv = dai->driver;
1203
1204 dev_dbg(&be->dev, "pm: BE CPU DAI playback suspend %s\n",
1205 be->dai_link->name);
1206
1207 if (be->dai_link->ignore_suspend)
1208 continue;
1209
1210 if (drv->suspend && !drv->ac97_control)
1211 drv->suspend(dai);
1212 }
1213
1214 /* suspend for capture */
1215 list_for_each_entry(dsp_params,
1216 &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) {
1217
1218 struct snd_soc_pcm_runtime *be = dsp_params->be;
1219 struct snd_soc_dai *dai = be->cpu_dai;
1220 struct snd_soc_dai_driver *drv = dai->driver;
1221
1222 dev_dbg(&be->dev, "pm: BE CPU DAI capture suspend %s\n",
1223 be->dai_link->name);
1224
1225 if (be->dai_link->ignore_suspend)
1226 continue;
1227
1228 if (drv->suspend && !drv->ac97_control)
1229 drv->suspend(dai);
1230 }
1231
1232 return 0;
1233}
1234
1235int soc_dsp_be_ac97_cpu_dai_suspend(struct snd_soc_pcm_runtime *fe)
1236{
1237 struct snd_soc_dsp_params *dsp_params;
1238
1239 /* suspend for playback */
1240 list_for_each_entry(dsp_params,
1241 &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
1242
1243 struct snd_soc_pcm_runtime *be = dsp_params->be;
1244 struct snd_soc_dai *dai = be->cpu_dai;
1245 struct snd_soc_dai_driver *drv = dai->driver;
1246
1247 dev_dbg(&be->dev, "pm: BE CPU DAI playback suspend %s\n",
1248 be->dai_link->name);
1249
1250 if (be->dai_link->ignore_suspend)
1251 continue;
1252
1253 if (drv->suspend && drv->ac97_control)
1254 drv->suspend(dai);
1255 }
1256
1257 /* suspend for capture */
1258 list_for_each_entry(dsp_params,
1259 &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) {
1260
1261 struct snd_soc_pcm_runtime *be = dsp_params->be;
1262 struct snd_soc_dai *dai = be->cpu_dai;
1263 struct snd_soc_dai_driver *drv = dai->driver;
1264
1265 dev_dbg(&be->dev, "pm: BE CPU DAI capture suspend %s\n",
1266 be->dai_link->name);
1267
1268 if (be->dai_link->ignore_suspend)
1269 continue;
1270
1271 if (drv->suspend && drv->ac97_control)
1272 drv->suspend(dai);
1273 }
1274
1275 return 0;
1276}
1277
1278int soc_dsp_be_platform_suspend(struct snd_soc_pcm_runtime *fe)
1279{
1280 struct snd_soc_dsp_params *dsp_params;
1281
1282 /* suspend for playback */
1283 list_for_each_entry(dsp_params,
1284 &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
1285
1286 struct snd_soc_pcm_runtime *be = dsp_params->be;
1287 struct snd_soc_platform *platform = be->platform;
1288 struct snd_soc_platform_driver *drv = platform->driver;
1289 struct snd_soc_dai *dai = be->cpu_dai;
1290
1291 dev_dbg(&be->dev, "pm: BE platform playback suspend %s\n",
1292 be->dai_link->name);
1293
1294 if (be->dai_link->ignore_suspend)
1295 continue;
1296
1297 if (drv->suspend && !platform->suspended) {
1298 drv->suspend(dai);
1299 platform->suspended = 1;
1300 }
1301 }
1302
1303 /* suspend for capture */
1304 list_for_each_entry(dsp_params,
1305 &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) {
1306
1307 struct snd_soc_pcm_runtime *be = dsp_params->be;
1308 struct snd_soc_platform *platform = be->platform;
1309 struct snd_soc_platform_driver *drv = platform->driver;
1310 struct snd_soc_dai *dai = be->cpu_dai;
1311
1312 dev_dbg(&be->dev, "pm: BE platform capture suspend %s\n",
1313 be->dai_link->name);
1314
1315 if (be->dai_link->ignore_suspend)
1316 continue;
1317
1318 if (drv->suspend && !platform->suspended) {
1319 drv->suspend(dai);
1320 platform->suspended = 1;
1321 }
1322 }
1323
1324 return 0;
1325}
1326
1327int soc_dsp_be_cpu_dai_resume(struct snd_soc_pcm_runtime *fe)
1328{
1329 struct snd_soc_dsp_params *dsp_params;
1330
1331 /* resume for playback */
1332 list_for_each_entry(dsp_params,
1333 &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
1334
1335 struct snd_soc_pcm_runtime *be = dsp_params->be;
1336 struct snd_soc_dai *dai = be->cpu_dai;
1337 struct snd_soc_dai_driver *drv = dai->driver;
1338
1339 dev_dbg(&be->dev, "pm: BE CPU DAI playback resume %s\n",
1340 be->dai_link->name);
1341
1342 if (be->dai_link->ignore_suspend)
1343 continue;
1344
1345 if (drv->resume && !drv->ac97_control)
1346 drv->resume(dai);
1347 }
1348
1349 /* suspend for capture */
1350 list_for_each_entry(dsp_params,
1351 &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) {
1352
1353 struct snd_soc_pcm_runtime *be = dsp_params->be;
1354 struct snd_soc_dai *dai = be->cpu_dai;
1355 struct snd_soc_dai_driver *drv = dai->driver;
1356
1357 dev_dbg(&be->dev, "pm: BE CPU DAI capture resume %s\n",
1358 be->dai_link->name);
1359
1360 if (be->dai_link->ignore_suspend)
1361 continue;
1362
1363 if (drv->resume && !drv->ac97_control)
1364 drv->resume(dai);
1365 }
1366
1367 return 0;
1368}
1369
1370int soc_dsp_be_ac97_cpu_dai_resume(struct snd_soc_pcm_runtime *fe)
1371{
1372 struct snd_soc_dsp_params *dsp_params;
1373
1374 /* resume for playback */
1375 list_for_each_entry(dsp_params,
1376 &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
1377
1378 struct snd_soc_pcm_runtime *be = dsp_params->be;
1379 struct snd_soc_dai *dai = be->cpu_dai;
1380 struct snd_soc_dai_driver *drv = dai->driver;
1381
1382 dev_dbg(&be->dev, "pm: BE CPU DAI playback resume %s\n",
1383 be->dai_link->name);
1384
1385 if (be->dai_link->ignore_suspend)
1386 continue;
1387
1388 if (drv->resume && drv->ac97_control)
1389 drv->resume(dai);
1390 }
1391
1392 /* suspend for capture */
1393 list_for_each_entry(dsp_params,
1394 &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) {
1395
1396 struct snd_soc_pcm_runtime *be = dsp_params->be;
1397 struct snd_soc_dai *dai = be->cpu_dai;
1398 struct snd_soc_dai_driver *drv = dai->driver;
1399
1400 dev_dbg(&be->dev, "pm: BE CPU DAI capture resume %s\n",
1401 be->dai_link->name);
1402
1403 if (be->dai_link->ignore_suspend)
1404 continue;
1405
1406 if (drv->resume && drv->ac97_control)
1407 drv->resume(dai);
1408 }
1409
1410 return 0;
1411}
1412
1413int soc_dsp_be_platform_resume(struct snd_soc_pcm_runtime *fe)
1414{
1415 struct snd_soc_dsp_params *dsp_params;
1416
1417 /* resume for playback */
1418 list_for_each_entry(dsp_params,
1419 &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
1420
1421 struct snd_soc_pcm_runtime *be = dsp_params->be;
1422 struct snd_soc_platform *platform = be->platform;
1423 struct snd_soc_platform_driver *drv = platform->driver;
1424 struct snd_soc_dai *dai = be->cpu_dai;
1425
1426 dev_dbg(&be->dev, "pm: BE platform playback resume %s\n",
1427 be->dai_link->name);
1428
1429 if (be->dai_link->ignore_suspend)
1430 continue;
1431
1432 if (drv->resume && platform->suspended) {
1433 drv->resume(dai);
1434 platform->suspended = 0;
1435 }
1436 }
1437
1438 /* resume for capture */
1439 list_for_each_entry(dsp_params,
1440 &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) {
1441
1442 struct snd_soc_pcm_runtime *be = dsp_params->be;
1443 struct snd_soc_platform *platform = be->platform;
1444 struct snd_soc_platform_driver *drv = platform->driver;
1445 struct snd_soc_dai *dai = be->cpu_dai;
1446
1447 dev_dbg(&be->dev, "pm: BE platform capture resume %s\n",
1448 be->dai_link->name);
1449
1450 if (be->dai_link->ignore_suspend)
1451 continue;
1452
1453 if (drv->resume && platform->suspended) {
1454 drv->resume(dai);
1455 platform->suspended = 0;
1456 }
1457 }
1458
1459 return 0;
1460}
1461
1462/* called when opening FE stream */
1463int soc_dsp_fe_dai_open(struct snd_pcm_substream *fe_substream)
1464{
1465 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
1466 int err;
1467
1468 fe->dsp[fe_substream->stream].runtime = fe_substream->runtime;
1469
1470 /* calculate valid and active FE <-> BE dsp_paramss */
1471 err = dsp_add_new_paths(fe, fe_substream->stream, 0);
1472 if (err <= 0) {
1473 dev_warn(&fe->dev, "asoc: %s no valid %s route from source to sink\n",
1474 fe->dai_link->name, fe_substream->stream ? "capture" : "playback");
1475 }
1476
1477 return soc_dsp_fe_dai_startup(fe_substream);
1478}
1479
1480/* called when closing FE stream */
1481int soc_dsp_fe_dai_close(struct snd_pcm_substream *fe_substream)
1482{
1483 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
1484 int ret;
1485
1486 ret = soc_dsp_fe_dai_shutdown(fe_substream);
1487
1488 be_disconnect(fe, fe_substream->stream);
1489
Misael Lopez Cruz898185f2011-07-26 22:52:28 -05001490 fe->dsp[fe_substream->stream].runtime = NULL;
1491
Liam Girdwooda00663b2011-01-31 21:23:17 +00001492 return ret;
1493}
1494
1495#ifdef CONFIG_DEBUG_FS
1496int soc_dsp_debugfs_add(struct snd_soc_pcm_runtime *rtd)
1497{
1498 rtd->debugfs_dsp_root = debugfs_create_dir(rtd->dai_link->name,
1499 rtd->card->debugfs_card_root);
1500 if (!rtd->debugfs_dsp_root) {
1501 dev_dbg(&rtd->dev,
1502 "ASoC: Failed to create dsp debugfs directory %s\n",
1503 rtd->dai_link->name);
1504 return -EINVAL;
1505 }
1506
1507 return 0;
1508}
1509#endif
1510
1511/* Module information */
1512MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
1513MODULE_DESCRIPTION("ALSA SoC DSP Core");
1514MODULE_LICENSE("GPL");