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