blob: 7f7821356baac5183e40e2869103a3e9179f876f [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
514 /* shutdown the BEs */
515 soc_dsp_be_dai_shutdown(fe, substream->stream);
516
517 dev_dbg(&fe->dev, "dsp: close FE %s\n", fe->dai_link->name);
518
519 /* now shutdown the frontend */
520 soc_pcm_close(substream);
521
522 /* 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
957/* check for running FEs */
958static int dsp_get_be_trigger_cmd(struct snd_soc_pcm_runtime *fe, int stream)
959{
960 struct snd_soc_dsp_params *dsp_be_params, *dsp_fe_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 struct snd_soc_pcm_runtime *be = dsp_be_params->be;
965
966 /* get the FEs for this BE */
967 list_for_each_entry(dsp_fe_params, &be->dsp[stream].fe_clients, list_fe) {
968
969 if (dsp_fe_params->state == SND_SOC_DSP_LINK_STATE_START)
970 return SND_SOC_DSP_LINK_STATE_START;
971 }
972 }
973 return SND_SOC_DSP_LINK_STATE_PAUSED;
974}
975
976/* check for running BEs */
977static int dsp_get_fe_trigger_cmd(struct snd_soc_pcm_runtime *fe, int stream)
978{
979 struct snd_soc_dsp_params *dsp_be_params;
980
981 /* get the FEs for each BE */
982 list_for_each_entry(dsp_be_params, &fe->dsp[stream].be_clients, list_be) {
983
984 if (dsp_be_params->state == SND_SOC_DSP_LINK_STATE_START)
985 return SND_SOC_DSP_LINK_STATE_START;
986 }
987 return SND_SOC_DSP_LINK_STATE_PAUSED;
988}
989
990static int dsp_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
991{
992 struct snd_soc_dsp_link *dsp_link = fe->dai_link->dsp_link;
993 struct snd_pcm_substream *substream = snd_soc_dsp_get_substream(fe, stream);
994 struct snd_soc_dsp_params *dsp_params;
995 int ret, cmd;
996
997 dev_dbg(&fe->dev, "runtime %s open on FE %s\n",
998 stream ? "capture" : "playback", fe->dai_link->name);
999
1000 ret = soc_dsp_be_dai_startup(fe, stream);
1001 if (ret < 0)
1002 return ret;
1003
1004 ret = soc_dsp_be_dai_hw_params(fe, stream);
1005 if (ret < 0)
1006 return ret;
1007
1008 ret = soc_dsp_be_dai_prepare(fe, stream);
1009 if (ret < 0)
1010 return ret;
1011
1012 /* run the stream event for each BE */
1013 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1014 soc_dsp_dapm_stream_event(fe, stream,
1015 fe->cpu_dai->driver->playback.stream_name,
1016 SNDRV_PCM_TRIGGER_START);
1017 else
1018 soc_dsp_dapm_stream_event(fe, stream,
1019 fe->cpu_dai->driver->capture.stream_name,
1020 SNDRV_PCM_TRIGGER_START);
1021
1022 if (dsp_link->trigger[stream] == SND_SOC_DSP_TRIGGER_BESPOKE) {
1023
1024 /* there is no point in triggering START iff all BEs are PAUSED */
1025 cmd = dsp_get_fe_trigger_cmd(fe, stream);
1026
1027 /* call trigger on the frontend - FE takes care of all BE triggers */
1028 dev_dbg(&fe->dev, "dsp: bespoke trigger FE %s cmd start\n",
1029 fe->dai_link->name);
1030
1031 ret = soc_pcm_bespoke_trigger(substream, cmd);
1032 if (ret < 0) {
1033 dev_err(&fe->dev,"dsp: trigger FE failed %d\n", ret);
1034 return ret;
1035 }
1036
1037 /* successful trigger so update BE trigger status */
1038 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
1039
1040 /* is this op for this BE ? */
1041 if (fe->dsp[stream].runtime_update &&
1042 !dsp_params->be->dsp[stream].runtime_update)
1043 continue;
1044
1045 switch (cmd) {
1046 case SNDRV_PCM_TRIGGER_START:
1047 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1048 case SNDRV_PCM_TRIGGER_RESUME:
1049 dsp_params->state = SND_SOC_DSP_LINK_STATE_START;
1050 break;
1051 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
1052 case SNDRV_PCM_TRIGGER_STOP:
1053 case SNDRV_PCM_TRIGGER_SUSPEND:
1054 dsp_params->state = SND_SOC_DSP_LINK_STATE_PAUSED;
1055 break;
1056 }
1057 }
1058 } else {
1059
1060 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
1061
1062 /* there is no point in triggering start iff all FEs are PAUSED */
1063 cmd = dsp_get_be_trigger_cmd(fe, stream);
1064
1065 dev_dbg(&fe->dev, "dsp: trigger FE %s cmd start\n",
1066 fe->dai_link->name);
1067
1068 ret = soc_dsp_be_dai_trigger(fe, stream, cmd);
1069 if (ret < 0)
1070 return ret;
1071 }
1072 }
1073
1074 return 0;
1075}
1076
1077static int dsp_run_update(struct snd_soc_pcm_runtime *fe, int stream,
1078 int start, int stop)
1079{
1080 int ret = 0;
1081
1082 fe->dsp[stream].runtime_update = 1;
1083
1084 /* startup any new BEs */
1085 if (start) {
1086 ret = dsp_run_update_startup(fe, stream);
1087 if (ret < 0)
1088 dev_err(&fe->dev, "failed to startup BEs\n");
1089 }
1090
1091 /* close down old BEs */
1092 if (stop) {
1093 ret = dsp_run_update_shutdown(fe, stream);
1094 if (ret < 0)
1095 dev_err(&fe->dev, "failed to shutdown BEs\n");
1096 }
1097
1098 fe->dsp[stream].runtime_update = 0;
1099
1100 return ret;
1101}
1102
1103/* called when any mixer updates change FE -> BE the stream */
1104int soc_dsp_runtime_update(struct snd_soc_dapm_widget *widget)
1105{
1106 struct snd_soc_card *card;
1107 int i, ret = 0, start, stop;
1108
1109 if (widget->codec)
1110 card = widget->codec->card;
1111 else if (widget->platform)
1112 card = widget->platform->card;
1113 else
1114 return -EINVAL;
1115
Liam Girdwoodfb7926c2011-07-04 17:23:32 +02001116 mutex_lock_nested(&widget->dapm->card->dsp_mutex, 1);
Liam Girdwooda00663b2011-01-31 21:23:17 +00001117
1118 for (i = 0; i < card->num_rtd; i++) {
1119 struct snd_soc_pcm_runtime *fe = &card->rtd[i];
1120
1121 /* make sure link is BE */
1122 if (!fe->dai_link->dsp_link)
1123 continue;
1124
1125 /* only check active links */
1126 if (!fe->cpu_dai->active) {
1127 continue;
1128 }
1129
1130 /* DAPM sync will call this to update DSP paths */
1131 dev_dbg(card->dev, "DSP runtime update for FE %s\n", fe->dai_link->name);
1132
1133 /* update any playback paths */
1134 start = dsp_add_new_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, 1);
1135 stop = dsp_prune_old_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, 1);
1136 if (!(start || stop))
1137 goto capture;
1138
1139 /* run PCM ops on new/old playback paths */
1140 ret = dsp_run_update(fe, SNDRV_PCM_STREAM_PLAYBACK, start, stop);
1141 if (ret < 0) {
1142 dev_err(&fe->dev, "failed to update playback FE stream %s\n",
1143 fe->dai_link->stream_name);
1144 }
1145
1146 /* free old playback links */
1147 be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
1148 fe_clear_pending(fe, SNDRV_PCM_STREAM_PLAYBACK);
1149
1150capture:
1151 /* update any capture paths */
1152 start = dsp_add_new_paths(fe, SNDRV_PCM_STREAM_CAPTURE, 1);
1153 stop = dsp_prune_old_paths(fe, SNDRV_PCM_STREAM_CAPTURE, 1);
1154 if (!(start || stop))
1155 continue;
1156
1157 /* run PCM ops on new/old capture paths */
1158 ret = dsp_run_update(fe, SNDRV_PCM_STREAM_CAPTURE, start, stop);
1159 if (ret < 0) {
1160 dev_err(&fe->dev, "failed to update capture FE stream %s\n",
1161 fe->dai_link->stream_name);
1162 }
1163
1164 /* free old capture links */
1165 be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
1166 fe_clear_pending(fe, SNDRV_PCM_STREAM_CAPTURE);
1167 }
1168
1169 mutex_unlock(&widget->dapm->card->dsp_mutex);
1170 return ret;
1171}
1172
1173int soc_dsp_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute)
1174{
1175 struct snd_soc_dsp_params *dsp_params;
1176
1177 list_for_each_entry(dsp_params,
1178 &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
1179
1180 struct snd_soc_pcm_runtime *be = dsp_params->be;
1181 struct snd_soc_dai *dai = be->codec_dai;
1182 struct snd_soc_dai_driver *drv = dai->driver;
1183
1184 dev_dbg(&be->dev, "BE digital mute %s\n", be->dai_link->name);
1185
1186 if (be->dai_link->ignore_suspend)
1187 continue;
1188
1189 if (drv->ops->digital_mute && dai->playback_active)
1190 drv->ops->digital_mute(dai, mute);
1191 }
1192
1193 return 0;
1194}
1195
1196int soc_dsp_be_cpu_dai_suspend(struct snd_soc_pcm_runtime *fe)
1197{
1198 struct snd_soc_dsp_params *dsp_params;
1199
1200 /* suspend for playback */
1201 list_for_each_entry(dsp_params,
1202 &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
1203
1204 struct snd_soc_pcm_runtime *be = dsp_params->be;
1205 struct snd_soc_dai *dai = be->cpu_dai;
1206 struct snd_soc_dai_driver *drv = dai->driver;
1207
1208 dev_dbg(&be->dev, "pm: BE CPU DAI playback suspend %s\n",
1209 be->dai_link->name);
1210
1211 if (be->dai_link->ignore_suspend)
1212 continue;
1213
1214 if (drv->suspend && !drv->ac97_control)
1215 drv->suspend(dai);
1216 }
1217
1218 /* suspend for capture */
1219 list_for_each_entry(dsp_params,
1220 &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].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 capture 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 return 0;
1237}
1238
1239int soc_dsp_be_ac97_cpu_dai_suspend(struct snd_soc_pcm_runtime *fe)
1240{
1241 struct snd_soc_dsp_params *dsp_params;
1242
1243 /* suspend for playback */
1244 list_for_each_entry(dsp_params,
1245 &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
1246
1247 struct snd_soc_pcm_runtime *be = dsp_params->be;
1248 struct snd_soc_dai *dai = be->cpu_dai;
1249 struct snd_soc_dai_driver *drv = dai->driver;
1250
1251 dev_dbg(&be->dev, "pm: BE CPU DAI playback suspend %s\n",
1252 be->dai_link->name);
1253
1254 if (be->dai_link->ignore_suspend)
1255 continue;
1256
1257 if (drv->suspend && drv->ac97_control)
1258 drv->suspend(dai);
1259 }
1260
1261 /* suspend for capture */
1262 list_for_each_entry(dsp_params,
1263 &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) {
1264
1265 struct snd_soc_pcm_runtime *be = dsp_params->be;
1266 struct snd_soc_dai *dai = be->cpu_dai;
1267 struct snd_soc_dai_driver *drv = dai->driver;
1268
1269 dev_dbg(&be->dev, "pm: BE CPU DAI capture suspend %s\n",
1270 be->dai_link->name);
1271
1272 if (be->dai_link->ignore_suspend)
1273 continue;
1274
1275 if (drv->suspend && drv->ac97_control)
1276 drv->suspend(dai);
1277 }
1278
1279 return 0;
1280}
1281
1282int soc_dsp_be_platform_suspend(struct snd_soc_pcm_runtime *fe)
1283{
1284 struct snd_soc_dsp_params *dsp_params;
1285
1286 /* suspend for playback */
1287 list_for_each_entry(dsp_params,
1288 &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
1289
1290 struct snd_soc_pcm_runtime *be = dsp_params->be;
1291 struct snd_soc_platform *platform = be->platform;
1292 struct snd_soc_platform_driver *drv = platform->driver;
1293 struct snd_soc_dai *dai = be->cpu_dai;
1294
1295 dev_dbg(&be->dev, "pm: BE platform playback suspend %s\n",
1296 be->dai_link->name);
1297
1298 if (be->dai_link->ignore_suspend)
1299 continue;
1300
1301 if (drv->suspend && !platform->suspended) {
1302 drv->suspend(dai);
1303 platform->suspended = 1;
1304 }
1305 }
1306
1307 /* suspend for capture */
1308 list_for_each_entry(dsp_params,
1309 &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) {
1310
1311 struct snd_soc_pcm_runtime *be = dsp_params->be;
1312 struct snd_soc_platform *platform = be->platform;
1313 struct snd_soc_platform_driver *drv = platform->driver;
1314 struct snd_soc_dai *dai = be->cpu_dai;
1315
1316 dev_dbg(&be->dev, "pm: BE platform capture suspend %s\n",
1317 be->dai_link->name);
1318
1319 if (be->dai_link->ignore_suspend)
1320 continue;
1321
1322 if (drv->suspend && !platform->suspended) {
1323 drv->suspend(dai);
1324 platform->suspended = 1;
1325 }
1326 }
1327
1328 return 0;
1329}
1330
1331int soc_dsp_be_cpu_dai_resume(struct snd_soc_pcm_runtime *fe)
1332{
1333 struct snd_soc_dsp_params *dsp_params;
1334
1335 /* resume for playback */
1336 list_for_each_entry(dsp_params,
1337 &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
1338
1339 struct snd_soc_pcm_runtime *be = dsp_params->be;
1340 struct snd_soc_dai *dai = be->cpu_dai;
1341 struct snd_soc_dai_driver *drv = dai->driver;
1342
1343 dev_dbg(&be->dev, "pm: BE CPU DAI playback resume %s\n",
1344 be->dai_link->name);
1345
1346 if (be->dai_link->ignore_suspend)
1347 continue;
1348
1349 if (drv->resume && !drv->ac97_control)
1350 drv->resume(dai);
1351 }
1352
1353 /* suspend for capture */
1354 list_for_each_entry(dsp_params,
1355 &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].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 capture 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 return 0;
1372}
1373
1374int soc_dsp_be_ac97_cpu_dai_resume(struct snd_soc_pcm_runtime *fe)
1375{
1376 struct snd_soc_dsp_params *dsp_params;
1377
1378 /* resume for playback */
1379 list_for_each_entry(dsp_params,
1380 &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
1381
1382 struct snd_soc_pcm_runtime *be = dsp_params->be;
1383 struct snd_soc_dai *dai = be->cpu_dai;
1384 struct snd_soc_dai_driver *drv = dai->driver;
1385
1386 dev_dbg(&be->dev, "pm: BE CPU DAI playback resume %s\n",
1387 be->dai_link->name);
1388
1389 if (be->dai_link->ignore_suspend)
1390 continue;
1391
1392 if (drv->resume && drv->ac97_control)
1393 drv->resume(dai);
1394 }
1395
1396 /* suspend for capture */
1397 list_for_each_entry(dsp_params,
1398 &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) {
1399
1400 struct snd_soc_pcm_runtime *be = dsp_params->be;
1401 struct snd_soc_dai *dai = be->cpu_dai;
1402 struct snd_soc_dai_driver *drv = dai->driver;
1403
1404 dev_dbg(&be->dev, "pm: BE CPU DAI capture resume %s\n",
1405 be->dai_link->name);
1406
1407 if (be->dai_link->ignore_suspend)
1408 continue;
1409
1410 if (drv->resume && drv->ac97_control)
1411 drv->resume(dai);
1412 }
1413
1414 return 0;
1415}
1416
1417int soc_dsp_be_platform_resume(struct snd_soc_pcm_runtime *fe)
1418{
1419 struct snd_soc_dsp_params *dsp_params;
1420
1421 /* resume for playback */
1422 list_for_each_entry(dsp_params,
1423 &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
1424
1425 struct snd_soc_pcm_runtime *be = dsp_params->be;
1426 struct snd_soc_platform *platform = be->platform;
1427 struct snd_soc_platform_driver *drv = platform->driver;
1428 struct snd_soc_dai *dai = be->cpu_dai;
1429
1430 dev_dbg(&be->dev, "pm: BE platform playback resume %s\n",
1431 be->dai_link->name);
1432
1433 if (be->dai_link->ignore_suspend)
1434 continue;
1435
1436 if (drv->resume && platform->suspended) {
1437 drv->resume(dai);
1438 platform->suspended = 0;
1439 }
1440 }
1441
1442 /* resume for capture */
1443 list_for_each_entry(dsp_params,
1444 &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) {
1445
1446 struct snd_soc_pcm_runtime *be = dsp_params->be;
1447 struct snd_soc_platform *platform = be->platform;
1448 struct snd_soc_platform_driver *drv = platform->driver;
1449 struct snd_soc_dai *dai = be->cpu_dai;
1450
1451 dev_dbg(&be->dev, "pm: BE platform capture resume %s\n",
1452 be->dai_link->name);
1453
1454 if (be->dai_link->ignore_suspend)
1455 continue;
1456
1457 if (drv->resume && platform->suspended) {
1458 drv->resume(dai);
1459 platform->suspended = 0;
1460 }
1461 }
1462
1463 return 0;
1464}
1465
1466/* called when opening FE stream */
1467int soc_dsp_fe_dai_open(struct snd_pcm_substream *fe_substream)
1468{
1469 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
1470 int err;
1471
1472 fe->dsp[fe_substream->stream].runtime = fe_substream->runtime;
1473
1474 /* calculate valid and active FE <-> BE dsp_paramss */
1475 err = dsp_add_new_paths(fe, fe_substream->stream, 0);
1476 if (err <= 0) {
1477 dev_warn(&fe->dev, "asoc: %s no valid %s route from source to sink\n",
1478 fe->dai_link->name, fe_substream->stream ? "capture" : "playback");
1479 }
1480
1481 return soc_dsp_fe_dai_startup(fe_substream);
1482}
1483
1484/* called when closing FE stream */
1485int soc_dsp_fe_dai_close(struct snd_pcm_substream *fe_substream)
1486{
1487 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
1488 int ret;
1489
1490 ret = soc_dsp_fe_dai_shutdown(fe_substream);
1491
1492 be_disconnect(fe, fe_substream->stream);
1493
Misael Lopez Cruz898185f2011-07-26 22:52:28 -05001494 fe->dsp[fe_substream->stream].runtime = NULL;
1495
Liam Girdwooda00663b2011-01-31 21:23:17 +00001496 return ret;
1497}
1498
1499#ifdef CONFIG_DEBUG_FS
1500int soc_dsp_debugfs_add(struct snd_soc_pcm_runtime *rtd)
1501{
1502 rtd->debugfs_dsp_root = debugfs_create_dir(rtd->dai_link->name,
1503 rtd->card->debugfs_card_root);
1504 if (!rtd->debugfs_dsp_root) {
1505 dev_dbg(&rtd->dev,
1506 "ASoC: Failed to create dsp debugfs directory %s\n",
1507 rtd->dai_link->name);
1508 return -EINVAL;
1509 }
1510
1511 return 0;
1512}
1513#endif
1514
1515/* Module information */
1516MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
1517MODULE_DESCRIPTION("ALSA SoC DSP Core");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001518MODULE_LICENSE("GPL v2");