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