blob: 706954b787c3acfe5e961d5756d46c2756458c79 [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
Jayasena Sangaraboinadde4ea92011-11-14 14:32:13 -0800485 if (dsp_params->state != SND_SOC_DSP_LINK_STATE_FREE)
486 continue;
487
Liam Girdwooda00663b2011-01-31 21:23:17 +0000488 /* is this op for this BE ? */
489 if (fe->dsp[stream].runtime_update &&
490 !dsp_params->be->dsp[stream].runtime_update)
491 continue;
492
493 if (--dsp_params->be->dsp[stream].users != 0)
494 continue;
495
Liam Girdwooda00663b2011-01-31 21:23:17 +0000496 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
Jayasena Sangaraboina709e5ea2011-11-15 10:59:25 -0800630 if ((cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) ||
631 (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH))
632 return ret;
633
Liam Girdwooda00663b2011-01-31 21:23:17 +0000634 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
635
636 struct snd_pcm_substream *be_substream =
637 snd_soc_dsp_get_substream(dsp_params->be, stream);
638
639 /* is this op for this BE ? */
640 if (fe->dsp[stream].runtime_update &&
641 !dsp_params->be->dsp[stream].runtime_update)
642 continue;
643
644 switch (cmd) {
645 case SNDRV_PCM_TRIGGER_START:
646 /* only start BEs that are not triggered */
647 if (dsp_params->state == SND_SOC_DSP_LINK_STATE_PREPARE) {
648 ret = dsp_do_trigger(dsp_params, be_substream, cmd);
649 if (ret == 0)
650 dsp_params->state = SND_SOC_DSP_LINK_STATE_START;
651 }
652 break;
653 case SNDRV_PCM_TRIGGER_STOP:
654 /* only stop BEs that are being shutdown */
655 if (dsp_params->state == SND_SOC_DSP_LINK_STATE_FREE &&
656 dsp_params->be->dsp[stream].users == 1)
657 ret = dsp_do_trigger(dsp_params, be_substream, cmd);
658 break;
659 case SNDRV_PCM_TRIGGER_SUSPEND:
660 case SNDRV_PCM_TRIGGER_RESUME:
661 /* suspend and resume all BEs */
662 ret = dsp_do_trigger(dsp_params, be_substream, cmd);
663 break;
664 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
665 /* only release Paused BEs */
666 if (dsp_params->state == SND_SOC_DSP_LINK_STATE_PAUSED) {
667 ret = dsp_do_trigger(dsp_params, be_substream, cmd);
668 if (ret == 0)
669 dsp_params->state = SND_SOC_DSP_LINK_STATE_START;
670 }
671 break;
672 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
673 /* only pause active BEs */
674 if (dsp_params->state == SND_SOC_DSP_LINK_STATE_START) {
675 ret = dsp_do_trigger(dsp_params, be_substream, cmd);
676 if (ret == 0)
677 dsp_params->state = SND_SOC_DSP_LINK_STATE_PAUSED;
678 }
679 break;
680 }
681 if (ret < 0)
682 return ret;
683 }
684
685 return ret;
686}
687EXPORT_SYMBOL_GPL(soc_dsp_be_dai_trigger);
688
689int soc_dsp_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
690{
691 struct snd_soc_pcm_runtime *fe = substream->private_data;
692 struct snd_soc_dsp_link *dsp_link = fe->dai_link->dsp_link;
693 int stream = substream->stream, ret;
694
695 switch (dsp_link->trigger[stream]) {
696 case SND_SOC_DSP_TRIGGER_PRE:
697 /* call trigger on the frontend before the backend. */
698
699 dev_dbg(&fe->dev, "dsp: pre trigger FE %s cmd %d\n",
700 fe->dai_link->name, cmd);
701
702 ret = soc_pcm_trigger(substream, cmd);
703 if (ret < 0) {
704 dev_err(&fe->dev,"dsp: trigger FE failed %d\n", ret);
705 return ret;
706 }
707
708 ret = soc_dsp_be_dai_trigger(fe, substream->stream, cmd);
709 break;
710 case SND_SOC_DSP_TRIGGER_POST:
711 /* call trigger on the frontend after the backend. */
712
713 ret = soc_dsp_be_dai_trigger(fe, substream->stream, cmd);
714 if (ret < 0) {
715 dev_err(&fe->dev,"dsp: trigger FE failed %d\n", ret);
716 return ret;
717 }
718
719 dev_dbg(&fe->dev, "dsp: post trigger FE %s cmd %d\n",
720 fe->dai_link->name, cmd);
721
722 ret = soc_pcm_trigger(substream, cmd);
723 break;
724 case SND_SOC_DSP_TRIGGER_BESPOKE:
725 /* bespoke trigger() - handles both FE and BEs */
726
727 dev_dbg(&fe->dev, "dsp: bespoke trigger FE %s cmd %d\n",
728 fe->dai_link->name, cmd);
729
730 ret = soc_pcm_bespoke_trigger(substream, cmd);
731 if (ret < 0) {
732 dev_err(&fe->dev,"dsp: trigger FE failed %d\n", ret);
733 return ret;
734 }
735 break;
736 default:
737 dev_err(&fe->dev, "dsp: invalid trigger cmd %d for %s\n", cmd,
738 fe->dai_link->name);
739 return -EINVAL;
740 }
741
742 return ret;
743}
744
745static int soc_dsp_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
746{
747 struct snd_soc_dsp_params *dsp_params;
748 int ret = 0;
749
750 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
751
752 struct snd_pcm_substream *be_substream =
753 snd_soc_dsp_get_substream(dsp_params->be, stream);
754
755 /* is this op for this BE ? */
756 if (fe->dsp[stream].runtime_update &&
757 !dsp_params->be->dsp[stream].runtime_update)
758 continue;
759
760 /* only prepare ACTIVE or READY BE's */
761 if (dsp_params->state == SND_SOC_DSP_LINK_STATE_NEW ||
762 dsp_params->state == SND_SOC_DSP_LINK_STATE_FREE)
763 continue;
764
765 dev_dbg(&dsp_params->be->dev, "dsp: prepare BE %s\n",
766 dsp_params->fe->dai_link->name);
767
768 ret = soc_pcm_prepare(be_substream);
769 if (ret < 0) {
770 dev_err(&dsp_params->be->dev,"dsp: backend prepare failed %d\n",
771 ret);
772 break;
773 }
774
775 /* mark the BE as active */
776 be_state_update(fe, stream, SND_SOC_DSP_LINK_STATE_HW_PARAMS,
777 SND_SOC_DSP_LINK_STATE_PREPARE);
778 }
779 return ret;
780}
781
782int soc_dsp_fe_dai_prepare(struct snd_pcm_substream *substream)
783{
784 struct snd_soc_pcm_runtime *fe = substream->private_data;
785 int stream = substream->stream, ret = 0;
786
Liam Girdwoodfb7926c2011-07-04 17:23:32 +0200787 mutex_lock_nested(&fe->card->dsp_mutex, 0);
Liam Girdwooda00663b2011-01-31 21:23:17 +0000788
789 dev_dbg(&fe->dev, "dsp: prepare FE %s\n", fe->dai_link->name);
790
791 /* there is no point preparing this FE if there are no BEs */
792 if (list_empty(&fe->dsp[stream].be_clients)) {
793 dev_err(&fe->dev, "dsp: no backend DAIs enabled for %s\n",
794 fe->dai_link->name);
795 ret = -EINVAL;
796 goto out;
797 }
798
799 ret = soc_dsp_be_dai_prepare(fe, substream->stream);
800 if (ret < 0)
801 goto out;
802
803 /* mark the BE as active */
804 fe_state_update(fe, stream, SND_SOC_DSP_LINK_STATE_PREPARE);
805
806 /* call prepare on the frontend */
807 ret = soc_pcm_prepare(substream);
808 if (ret < 0) {
809 dev_err(&fe->dev,"dsp: prepare FE %s failed\n", fe->dai_link->name);
810 goto out;
811 }
812
813 /* run the stream event for each BE */
814 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
815 soc_dsp_dapm_stream_event(fe, stream,
816 fe->cpu_dai->driver->playback.stream_name,
817 SNDRV_PCM_TRIGGER_START);
818 else
819 soc_dsp_dapm_stream_event(fe, stream,
820 fe->cpu_dai->driver->capture.stream_name,
821 SNDRV_PCM_TRIGGER_START);
822
823out:
824 mutex_unlock(&fe->card->dsp_mutex);
825 return ret;
826}
827
828static int soc_dsp_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
829{
830 struct snd_soc_dsp_params *dsp_params;
831
832 /* only hw_params backends that are either sinks or sources
833 * to this frontend DAI */
834 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
835
836 struct snd_pcm_substream *be_substream =
837 snd_soc_dsp_get_substream(dsp_params->be, stream);
838
839 /* is this op for this BE ? */
840 if (fe->dsp[stream].runtime_update &&
841 !dsp_params->be->dsp[stream].runtime_update)
842 continue;
843
844 if (dsp_params->state != SND_SOC_DSP_LINK_STATE_FREE)
845 continue;
846
847 /* only free hw when no longer used */
848 if (dsp_params->be->dsp[stream].users != 1)
849 continue;
850
851 dev_dbg(&dsp_params->be->dev, "dsp: hw_free BE %s\n",
852 dsp_params->fe->dai_link->name);
853
854 soc_pcm_hw_free(be_substream);
855 }
856
857 return 0;
858}
859
860int soc_dsp_fe_dai_hw_free(struct snd_pcm_substream *substream)
861{
862 struct snd_soc_pcm_runtime *fe = substream->private_data;
863 int ret, stream = substream->stream;
864
Liam Girdwoodfb7926c2011-07-04 17:23:32 +0200865 mutex_lock_nested(&fe->card->dsp_mutex, 0);
Liam Girdwooda00663b2011-01-31 21:23:17 +0000866
867 fe_state_update(fe, stream, SND_SOC_DSP_LINK_STATE_FREE);
868
869 dev_dbg(&fe->dev, "dsp: hw_free FE %s\n", fe->dai_link->name);
870
871 /* call hw_free on the frontend */
872 ret = soc_pcm_hw_free(substream);
873 if (ret < 0)
874 dev_err(&fe->dev,"dsp: hw_free FE %s failed\n", fe->dai_link->name);
875
876 /* only hw_params backends that are either sinks or sources
877 * to this frontend DAI */
878 ret = soc_dsp_be_dai_hw_free(fe, stream);
879
880 mutex_unlock(&fe->card->dsp_mutex);
881 return ret;
882}
883
884/*
885 * FE stream event, send event to all active BEs.
886 */
887int soc_dsp_dapm_stream_event(struct snd_soc_pcm_runtime *fe,
888 int dir, const char *stream, int event)
889{
890 struct snd_soc_dsp_params *dsp_params;
891
892 /* resume for playback */
893 list_for_each_entry(dsp_params, &fe->dsp[dir].be_clients, list_be) {
894
895 struct snd_soc_pcm_runtime *be = dsp_params->be;
896
897 dev_dbg(&be->dev, "pm: BE %s stream %s event %d dir %d\n",
898 be->dai_link->name, stream, event, dir);
899
900 snd_soc_dapm_stream_event(be, stream, event);
901 }
902
903 return 0;
904}
905
906static int dsp_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
907{
908 struct snd_soc_dsp_link *dsp_link = fe->dai_link->dsp_link;
909 struct snd_pcm_substream *substream = snd_soc_dsp_get_substream(fe, stream);
910 struct snd_soc_dsp_params *dsp_params;
911 int ret;
912
913 dev_dbg(&fe->dev, "runtime %s close on FE %s\n",
914 stream ? "capture" : "playback", fe->dai_link->name);
915
916 if (dsp_link->trigger[stream] == SND_SOC_DSP_TRIGGER_BESPOKE) {
917 /* call bespoke trigger - FE takes care of all BE triggers */
918 dev_dbg(&fe->dev, "dsp: bespoke trigger FE %s cmd stop\n",
919 fe->dai_link->name);
920
921 ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
922 if (ret < 0) {
923 dev_err(&fe->dev,"dsp: trigger FE failed %d\n", ret);
924 return ret;
925 }
926 } else {
927
928 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
929
930 dev_dbg(&fe->dev, "dsp: trigger FE %s cmd stop\n",
931 fe->dai_link->name);
932
933 ret = soc_dsp_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
934 if (ret < 0)
935 return ret;
936 }
937 }
938
939 ret = soc_dsp_be_dai_hw_free(fe, stream);
940 if (ret < 0)
941 return ret;
942
943 ret = soc_dsp_be_dai_shutdown(fe, stream);
944 if (ret < 0)
945 return ret;
946
947 /* run the stream event for each BE */
948 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
949 soc_dsp_dapm_stream_event(fe, stream,
950 fe->cpu_dai->driver->playback.stream_name,
951 SNDRV_PCM_TRIGGER_STOP);
952 else
953 soc_dsp_dapm_stream_event(fe, stream,
954 fe->cpu_dai->driver->capture.stream_name,
955 SNDRV_PCM_TRIGGER_STOP);
956
957 return 0;
958}
959
Liam Girdwooda00663b2011-01-31 21:23:17 +0000960/* check for running BEs */
961static int dsp_get_fe_trigger_cmd(struct snd_soc_pcm_runtime *fe, int stream)
962{
963 struct snd_soc_dsp_params *dsp_be_params;
964
965 /* get the FEs for each BE */
966 list_for_each_entry(dsp_be_params, &fe->dsp[stream].be_clients, list_be) {
967
968 if (dsp_be_params->state == SND_SOC_DSP_LINK_STATE_START)
969 return SND_SOC_DSP_LINK_STATE_START;
970 }
971 return SND_SOC_DSP_LINK_STATE_PAUSED;
972}
973
974static int dsp_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
975{
976 struct snd_soc_dsp_link *dsp_link = fe->dai_link->dsp_link;
977 struct snd_pcm_substream *substream = snd_soc_dsp_get_substream(fe, stream);
978 struct snd_soc_dsp_params *dsp_params;
979 int ret, cmd;
980
981 dev_dbg(&fe->dev, "runtime %s open on FE %s\n",
982 stream ? "capture" : "playback", fe->dai_link->name);
983
984 ret = soc_dsp_be_dai_startup(fe, stream);
985 if (ret < 0)
986 return ret;
987
988 ret = soc_dsp_be_dai_hw_params(fe, stream);
989 if (ret < 0)
990 return ret;
991
992 ret = soc_dsp_be_dai_prepare(fe, stream);
993 if (ret < 0)
994 return ret;
995
996 /* run the stream event for each BE */
997 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
998 soc_dsp_dapm_stream_event(fe, stream,
999 fe->cpu_dai->driver->playback.stream_name,
1000 SNDRV_PCM_TRIGGER_START);
1001 else
1002 soc_dsp_dapm_stream_event(fe, stream,
1003 fe->cpu_dai->driver->capture.stream_name,
1004 SNDRV_PCM_TRIGGER_START);
1005
1006 if (dsp_link->trigger[stream] == SND_SOC_DSP_TRIGGER_BESPOKE) {
1007
1008 /* there is no point in triggering START iff all BEs are PAUSED */
1009 cmd = dsp_get_fe_trigger_cmd(fe, stream);
1010
1011 /* call trigger on the frontend - FE takes care of all BE triggers */
1012 dev_dbg(&fe->dev, "dsp: bespoke trigger FE %s cmd start\n",
1013 fe->dai_link->name);
1014
1015 ret = soc_pcm_bespoke_trigger(substream, cmd);
1016 if (ret < 0) {
1017 dev_err(&fe->dev,"dsp: trigger FE failed %d\n", ret);
1018 return ret;
1019 }
1020
1021 /* successful trigger so update BE trigger status */
1022 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
1023
1024 /* is this op for this BE ? */
1025 if (fe->dsp[stream].runtime_update &&
1026 !dsp_params->be->dsp[stream].runtime_update)
1027 continue;
1028
1029 switch (cmd) {
1030 case SNDRV_PCM_TRIGGER_START:
1031 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1032 case SNDRV_PCM_TRIGGER_RESUME:
1033 dsp_params->state = SND_SOC_DSP_LINK_STATE_START;
1034 break;
1035 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
1036 case SNDRV_PCM_TRIGGER_STOP:
1037 case SNDRV_PCM_TRIGGER_SUSPEND:
1038 dsp_params->state = SND_SOC_DSP_LINK_STATE_PAUSED;
1039 break;
1040 }
1041 }
1042 } else {
1043
1044 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
Patrick Lai837ee292011-07-14 15:14:41 -07001045 ret = soc_dsp_be_dai_trigger(fe, stream,
1046 SNDRV_PCM_TRIGGER_START);
Liam Girdwooda00663b2011-01-31 21:23:17 +00001047 if (ret < 0)
1048 return ret;
Patrick Lai837ee292011-07-14 15:14:41 -07001049 }
Liam Girdwooda00663b2011-01-31 21:23:17 +00001050 }
1051
1052 return 0;
1053}
1054
1055static int dsp_run_update(struct snd_soc_pcm_runtime *fe, int stream,
1056 int start, int stop)
1057{
1058 int ret = 0;
1059
1060 fe->dsp[stream].runtime_update = 1;
1061
1062 /* startup any new BEs */
1063 if (start) {
1064 ret = dsp_run_update_startup(fe, stream);
1065 if (ret < 0)
1066 dev_err(&fe->dev, "failed to startup BEs\n");
1067 }
1068
1069 /* close down old BEs */
1070 if (stop) {
1071 ret = dsp_run_update_shutdown(fe, stream);
1072 if (ret < 0)
1073 dev_err(&fe->dev, "failed to shutdown BEs\n");
1074 }
1075
1076 fe->dsp[stream].runtime_update = 0;
1077
1078 return ret;
1079}
1080
1081/* called when any mixer updates change FE -> BE the stream */
1082int soc_dsp_runtime_update(struct snd_soc_dapm_widget *widget)
1083{
1084 struct snd_soc_card *card;
1085 int i, ret = 0, start, stop;
1086
1087 if (widget->codec)
1088 card = widget->codec->card;
1089 else if (widget->platform)
1090 card = widget->platform->card;
1091 else
1092 return -EINVAL;
1093
Liam Girdwoodfb7926c2011-07-04 17:23:32 +02001094 mutex_lock_nested(&widget->dapm->card->dsp_mutex, 1);
Liam Girdwooda00663b2011-01-31 21:23:17 +00001095
1096 for (i = 0; i < card->num_rtd; i++) {
1097 struct snd_soc_pcm_runtime *fe = &card->rtd[i];
1098
1099 /* make sure link is BE */
1100 if (!fe->dai_link->dsp_link)
1101 continue;
1102
Patrick Lai5c415972011-08-01 23:24:18 -07001103 /* only check active playback links */
1104 if (!fe->cpu_dai->playback_active)
1105 goto capture;
Liam Girdwooda00663b2011-01-31 21:23:17 +00001106
1107 /* DAPM sync will call this to update DSP paths */
1108 dev_dbg(card->dev, "DSP runtime update for FE %s\n", fe->dai_link->name);
1109
1110 /* update any playback paths */
1111 start = dsp_add_new_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, 1);
1112 stop = dsp_prune_old_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, 1);
1113 if (!(start || stop))
1114 goto capture;
1115
1116 /* run PCM ops on new/old playback paths */
1117 ret = dsp_run_update(fe, SNDRV_PCM_STREAM_PLAYBACK, start, stop);
1118 if (ret < 0) {
1119 dev_err(&fe->dev, "failed to update playback FE stream %s\n",
1120 fe->dai_link->stream_name);
1121 }
1122
1123 /* free old playback links */
1124 be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
1125 fe_clear_pending(fe, SNDRV_PCM_STREAM_PLAYBACK);
1126
1127capture:
1128 /* update any capture paths */
Patrick Lai5c415972011-08-01 23:24:18 -07001129 if (fe->cpu_dai->capture_active) {
1130 start = dsp_add_new_paths(fe, SNDRV_PCM_STREAM_CAPTURE,
1131 1);
1132 stop = dsp_prune_old_paths(fe, SNDRV_PCM_STREAM_CAPTURE,
1133 1);
1134 if (!(start || stop))
1135 continue;
Liam Girdwooda00663b2011-01-31 21:23:17 +00001136
Patrick Lai5c415972011-08-01 23:24:18 -07001137 /* run PCM ops on new/old capture paths */
1138 ret = dsp_run_update(fe, SNDRV_PCM_STREAM_CAPTURE,
1139 start, stop);
1140 if (ret < 0) {
1141 dev_err(&fe->dev, "failed to update capture FE stream %s\n",
Liam Girdwooda00663b2011-01-31 21:23:17 +00001142 fe->dai_link->stream_name);
Patrick Lai5c415972011-08-01 23:24:18 -07001143 }
Liam Girdwooda00663b2011-01-31 21:23:17 +00001144
Patrick Lai5c415972011-08-01 23:24:18 -07001145 /* free old capture links */
1146 be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
1147 fe_clear_pending(fe, SNDRV_PCM_STREAM_CAPTURE);
1148 }
Liam Girdwooda00663b2011-01-31 21:23:17 +00001149 }
1150
1151 mutex_unlock(&widget->dapm->card->dsp_mutex);
1152 return ret;
1153}
1154
1155int soc_dsp_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute)
1156{
1157 struct snd_soc_dsp_params *dsp_params;
1158
1159 list_for_each_entry(dsp_params,
1160 &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
1161
1162 struct snd_soc_pcm_runtime *be = dsp_params->be;
1163 struct snd_soc_dai *dai = be->codec_dai;
1164 struct snd_soc_dai_driver *drv = dai->driver;
1165
1166 dev_dbg(&be->dev, "BE digital mute %s\n", be->dai_link->name);
1167
1168 if (be->dai_link->ignore_suspend)
1169 continue;
1170
1171 if (drv->ops->digital_mute && dai->playback_active)
1172 drv->ops->digital_mute(dai, mute);
1173 }
1174
1175 return 0;
1176}
1177
1178int soc_dsp_be_cpu_dai_suspend(struct snd_soc_pcm_runtime *fe)
1179{
1180 struct snd_soc_dsp_params *dsp_params;
1181
1182 /* suspend for playback */
1183 list_for_each_entry(dsp_params,
1184 &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
1185
1186 struct snd_soc_pcm_runtime *be = dsp_params->be;
1187 struct snd_soc_dai *dai = be->cpu_dai;
1188 struct snd_soc_dai_driver *drv = dai->driver;
1189
1190 dev_dbg(&be->dev, "pm: BE CPU DAI playback suspend %s\n",
1191 be->dai_link->name);
1192
1193 if (be->dai_link->ignore_suspend)
1194 continue;
1195
1196 if (drv->suspend && !drv->ac97_control)
1197 drv->suspend(dai);
1198 }
1199
1200 /* suspend for capture */
1201 list_for_each_entry(dsp_params,
1202 &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].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 capture 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 return 0;
1219}
1220
1221int soc_dsp_be_ac97_cpu_dai_suspend(struct snd_soc_pcm_runtime *fe)
1222{
1223 struct snd_soc_dsp_params *dsp_params;
1224
1225 /* suspend for playback */
1226 list_for_each_entry(dsp_params,
1227 &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
1228
1229 struct snd_soc_pcm_runtime *be = dsp_params->be;
1230 struct snd_soc_dai *dai = be->cpu_dai;
1231 struct snd_soc_dai_driver *drv = dai->driver;
1232
1233 dev_dbg(&be->dev, "pm: BE CPU DAI playback suspend %s\n",
1234 be->dai_link->name);
1235
1236 if (be->dai_link->ignore_suspend)
1237 continue;
1238
1239 if (drv->suspend && drv->ac97_control)
1240 drv->suspend(dai);
1241 }
1242
1243 /* suspend for capture */
1244 list_for_each_entry(dsp_params,
1245 &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].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 capture 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 return 0;
1262}
1263
1264int soc_dsp_be_platform_suspend(struct snd_soc_pcm_runtime *fe)
1265{
1266 struct snd_soc_dsp_params *dsp_params;
1267
1268 /* suspend for playback */
1269 list_for_each_entry(dsp_params,
1270 &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
1271
1272 struct snd_soc_pcm_runtime *be = dsp_params->be;
1273 struct snd_soc_platform *platform = be->platform;
1274 struct snd_soc_platform_driver *drv = platform->driver;
1275 struct snd_soc_dai *dai = be->cpu_dai;
1276
1277 dev_dbg(&be->dev, "pm: BE platform playback suspend %s\n",
1278 be->dai_link->name);
1279
1280 if (be->dai_link->ignore_suspend)
1281 continue;
1282
1283 if (drv->suspend && !platform->suspended) {
1284 drv->suspend(dai);
1285 platform->suspended = 1;
1286 }
1287 }
1288
1289 /* suspend for capture */
1290 list_for_each_entry(dsp_params,
1291 &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) {
1292
1293 struct snd_soc_pcm_runtime *be = dsp_params->be;
1294 struct snd_soc_platform *platform = be->platform;
1295 struct snd_soc_platform_driver *drv = platform->driver;
1296 struct snd_soc_dai *dai = be->cpu_dai;
1297
1298 dev_dbg(&be->dev, "pm: BE platform capture suspend %s\n",
1299 be->dai_link->name);
1300
1301 if (be->dai_link->ignore_suspend)
1302 continue;
1303
1304 if (drv->suspend && !platform->suspended) {
1305 drv->suspend(dai);
1306 platform->suspended = 1;
1307 }
1308 }
1309
1310 return 0;
1311}
1312
1313int soc_dsp_be_cpu_dai_resume(struct snd_soc_pcm_runtime *fe)
1314{
1315 struct snd_soc_dsp_params *dsp_params;
1316
1317 /* resume for playback */
1318 list_for_each_entry(dsp_params,
1319 &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
1320
1321 struct snd_soc_pcm_runtime *be = dsp_params->be;
1322 struct snd_soc_dai *dai = be->cpu_dai;
1323 struct snd_soc_dai_driver *drv = dai->driver;
1324
1325 dev_dbg(&be->dev, "pm: BE CPU DAI playback resume %s\n",
1326 be->dai_link->name);
1327
1328 if (be->dai_link->ignore_suspend)
1329 continue;
1330
1331 if (drv->resume && !drv->ac97_control)
1332 drv->resume(dai);
1333 }
1334
1335 /* suspend for capture */
1336 list_for_each_entry(dsp_params,
1337 &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].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 capture 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 return 0;
1354}
1355
1356int soc_dsp_be_ac97_cpu_dai_resume(struct snd_soc_pcm_runtime *fe)
1357{
1358 struct snd_soc_dsp_params *dsp_params;
1359
1360 /* resume for playback */
1361 list_for_each_entry(dsp_params,
1362 &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
1363
1364 struct snd_soc_pcm_runtime *be = dsp_params->be;
1365 struct snd_soc_dai *dai = be->cpu_dai;
1366 struct snd_soc_dai_driver *drv = dai->driver;
1367
1368 dev_dbg(&be->dev, "pm: BE CPU DAI playback resume %s\n",
1369 be->dai_link->name);
1370
1371 if (be->dai_link->ignore_suspend)
1372 continue;
1373
1374 if (drv->resume && drv->ac97_control)
1375 drv->resume(dai);
1376 }
1377
1378 /* suspend for capture */
1379 list_for_each_entry(dsp_params,
1380 &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].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 capture 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 return 0;
1397}
1398
1399int soc_dsp_be_platform_resume(struct snd_soc_pcm_runtime *fe)
1400{
1401 struct snd_soc_dsp_params *dsp_params;
1402
1403 /* resume for playback */
1404 list_for_each_entry(dsp_params,
1405 &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
1406
1407 struct snd_soc_pcm_runtime *be = dsp_params->be;
1408 struct snd_soc_platform *platform = be->platform;
1409 struct snd_soc_platform_driver *drv = platform->driver;
1410 struct snd_soc_dai *dai = be->cpu_dai;
1411
1412 dev_dbg(&be->dev, "pm: BE platform playback resume %s\n",
1413 be->dai_link->name);
1414
1415 if (be->dai_link->ignore_suspend)
1416 continue;
1417
1418 if (drv->resume && platform->suspended) {
1419 drv->resume(dai);
1420 platform->suspended = 0;
1421 }
1422 }
1423
1424 /* resume for capture */
1425 list_for_each_entry(dsp_params,
1426 &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) {
1427
1428 struct snd_soc_pcm_runtime *be = dsp_params->be;
1429 struct snd_soc_platform *platform = be->platform;
1430 struct snd_soc_platform_driver *drv = platform->driver;
1431 struct snd_soc_dai *dai = be->cpu_dai;
1432
1433 dev_dbg(&be->dev, "pm: BE platform capture resume %s\n",
1434 be->dai_link->name);
1435
1436 if (be->dai_link->ignore_suspend)
1437 continue;
1438
1439 if (drv->resume && platform->suspended) {
1440 drv->resume(dai);
1441 platform->suspended = 0;
1442 }
1443 }
1444
1445 return 0;
1446}
1447
1448/* called when opening FE stream */
1449int soc_dsp_fe_dai_open(struct snd_pcm_substream *fe_substream)
1450{
1451 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
1452 int err;
1453
1454 fe->dsp[fe_substream->stream].runtime = fe_substream->runtime;
1455
1456 /* calculate valid and active FE <-> BE dsp_paramss */
1457 err = dsp_add_new_paths(fe, fe_substream->stream, 0);
1458 if (err <= 0) {
1459 dev_warn(&fe->dev, "asoc: %s no valid %s route from source to sink\n",
1460 fe->dai_link->name, fe_substream->stream ? "capture" : "playback");
1461 }
1462
1463 return soc_dsp_fe_dai_startup(fe_substream);
1464}
1465
1466/* called when closing FE stream */
1467int soc_dsp_fe_dai_close(struct snd_pcm_substream *fe_substream)
1468{
1469 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
1470 int ret;
1471
1472 ret = soc_dsp_fe_dai_shutdown(fe_substream);
1473
1474 be_disconnect(fe, fe_substream->stream);
1475
Misael Lopez Cruz898185f2011-07-26 22:52:28 -05001476 fe->dsp[fe_substream->stream].runtime = NULL;
1477
Liam Girdwooda00663b2011-01-31 21:23:17 +00001478 return ret;
1479}
1480
1481#ifdef CONFIG_DEBUG_FS
1482int soc_dsp_debugfs_add(struct snd_soc_pcm_runtime *rtd)
1483{
1484 rtd->debugfs_dsp_root = debugfs_create_dir(rtd->dai_link->name,
1485 rtd->card->debugfs_card_root);
1486 if (!rtd->debugfs_dsp_root) {
1487 dev_dbg(&rtd->dev,
1488 "ASoC: Failed to create dsp debugfs directory %s\n",
1489 rtd->dai_link->name);
1490 return -EINVAL;
1491 }
1492
1493 return 0;
1494}
1495#endif
1496
1497/* Module information */
1498MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
1499MODULE_DESCRIPTION("ALSA SoC DSP Core");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001500MODULE_LICENSE("GPL v2");