blob: 7c6f0eab20abca9c6037368406c6cc8876c2a161 [file] [log] [blame]
Liam Girdwoodddee6272011-06-09 14:45:53 +01001/*
2 * soc-pcm.c -- ALSA SoC PCM
3 *
4 * Copyright 2005 Wolfson Microelectronics PLC.
5 * Copyright 2005 Openedhand Ltd.
6 * Copyright (C) 2010 Slimlogic Ltd.
7 * Copyright (C) 2010 Texas Instruments Inc.
8 *
9 * Authors: Liam Girdwood <lrg@ti.com>
10 * Mark Brown <broonie@opensource.wolfsonmicro.com>
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 *
17 */
18
19#include <linux/kernel.h>
20#include <linux/init.h>
21#include <linux/delay.h>
Mark Brownd6652ef2011-12-03 20:14:31 +000022#include <linux/pm_runtime.h>
Liam Girdwoodddee6272011-06-09 14:45:53 +010023#include <linux/slab.h>
24#include <linux/workqueue.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070025#include <linux/debugfs.h>
26#include <linux/dma-mapping.h>
27#include <linux/export.h>
Liam Girdwoodddee6272011-06-09 14:45:53 +010028#include <sound/core.h>
29#include <sound/pcm.h>
30#include <sound/pcm_params.h>
31#include <sound/soc.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070032#include <sound/soc-dpcm.h>
Liam Girdwoodddee6272011-06-09 14:45:53 +010033#include <sound/initval.h>
34
Steve Mucklef132c6c2012-06-06 18:30:57 -070035#define MAX_BE_USERS 8 /* adjust if too low for everday use */
36
Steve Mucklef132c6c2012-06-06 18:30:57 -070037/* ASoC no host IO hardware.
38 * TODO: fine tune these values for all host less transfers.
39 */
40static const struct snd_pcm_hardware no_host_hardware = {
41 .info = SNDRV_PCM_INFO_MMAP |
42 SNDRV_PCM_INFO_MMAP_VALID |
43 SNDRV_PCM_INFO_INTERLEAVED |
44 SNDRV_PCM_INFO_PAUSE |
45 SNDRV_PCM_INFO_RESUME,
46 .formats = SNDRV_PCM_FMTBIT_S16_LE |
47 SNDRV_PCM_FMTBIT_S32_LE,
48 .period_bytes_min = PAGE_SIZE >> 2,
49 .period_bytes_max = PAGE_SIZE >> 1,
50 .periods_min = 2,
51 .periods_max = 4,
52 .buffer_bytes_max = PAGE_SIZE,
53};
54
55/*
56 * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE
57 * are not running, paused or suspended for the specified stream direction.
58 */
59int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
60 struct snd_soc_pcm_runtime *be, int stream)
61{
62 struct snd_soc_dpcm_params *dpcm_params;
63
64 list_for_each_entry(dpcm_params, &be->dpcm[stream].fe_clients, list_fe) {
65
66 if (dpcm_params->fe == fe)
67 continue;
68
69 if (dpcm_params->fe->dpcm[stream].state == SND_SOC_DPCM_STATE_START ||
70 dpcm_params->fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PAUSED ||
71 dpcm_params->fe->dpcm[stream].state == SND_SOC_DPCM_STATE_SUSPEND)
72 return 0;
73 }
74 return 1;
75}
76EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop);
77
78/*
79 * We can only change hw params a BE DAI if any of it's FE are not prepared,
80 * running, paused or suspended for the specified stream direction.
81 */
82static int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
83 struct snd_soc_pcm_runtime *be, int stream)
84{
85 struct snd_soc_dpcm_params *dpcm_params;
86
87 list_for_each_entry(dpcm_params, &be->dpcm[stream].fe_clients, list_fe) {
88
89 if (dpcm_params->fe == fe)
90 continue;
91
92 if (dpcm_params->fe->dpcm[stream].state == SND_SOC_DPCM_STATE_START ||
93 dpcm_params->fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PAUSED ||
94 dpcm_params->fe->dpcm[stream].state == SND_SOC_DPCM_STATE_SUSPEND ||
95 dpcm_params->fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE)
96 return 0;
97 }
98 return 1;
99}
100
Dong Aisheng17841022011-08-29 17:15:14 +0800101static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
102 struct snd_soc_dai *soc_dai)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100103{
104 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100105 int ret;
106
Dong Aisheng17841022011-08-29 17:15:14 +0800107 if (!soc_dai->driver->symmetric_rates &&
Liam Girdwoodddee6272011-06-09 14:45:53 +0100108 !rtd->dai_link->symmetric_rates)
109 return 0;
110
111 /* This can happen if multiple streams are starting simultaneously -
112 * the second can need to get its constraints before the first has
113 * picked a rate. Complain and allow the application to carry on.
114 */
Dong Aisheng17841022011-08-29 17:15:14 +0800115 if (!soc_dai->rate) {
116 dev_warn(soc_dai->dev,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100117 "Not enforcing symmetric_rates due to race\n");
118 return 0;
119 }
120
Dong Aisheng17841022011-08-29 17:15:14 +0800121 dev_dbg(soc_dai->dev, "Symmetry forces %dHz rate\n", soc_dai->rate);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100122
123 ret = snd_pcm_hw_constraint_minmax(substream->runtime,
124 SNDRV_PCM_HW_PARAM_RATE,
Dong Aisheng17841022011-08-29 17:15:14 +0800125 soc_dai->rate, soc_dai->rate);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100126 if (ret < 0) {
Dong Aisheng17841022011-08-29 17:15:14 +0800127 dev_err(soc_dai->dev,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100128 "Unable to apply rate symmetry constraint: %d\n", ret);
129 return ret;
130 }
131
132 return 0;
133}
134
135/*
Mark Brown58ba9b22012-01-16 18:38:51 +0000136 * List of sample sizes that might go over the bus for parameter
137 * application. There ought to be a wildcard sample size for things
138 * like the DAC/ADC resolution to use but there isn't right now.
139 */
140static int sample_sizes[] = {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700141 8, 16, 24, 32,
Mark Brown58ba9b22012-01-16 18:38:51 +0000142};
143
144static void soc_pcm_apply_msb(struct snd_pcm_substream *substream,
145 struct snd_soc_dai *dai)
146{
147 int ret, i, bits;
148
149 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
150 bits = dai->driver->playback.sig_bits;
151 else
152 bits = dai->driver->capture.sig_bits;
153
154 if (!bits)
155 return;
156
157 for (i = 0; i < ARRAY_SIZE(sample_sizes); i++) {
Mark Brown278047f2012-01-19 18:04:18 +0000158 if (bits >= sample_sizes[i])
159 continue;
160
161 ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0,
162 sample_sizes[i], bits);
Mark Brown58ba9b22012-01-16 18:38:51 +0000163 if (ret != 0)
164 dev_warn(dai->dev,
165 "Failed to set MSB %d/%d: %d\n",
166 bits, sample_sizes[i], ret);
167 }
168}
169
170/*
Steve Mucklef132c6c2012-06-06 18:30:57 -0700171 * stream event, send event to FE and all active BEs.
172 */
Eric Laurentdb88f282013-07-15 10:00:45 -0700173int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe,
Steve Mucklef132c6c2012-06-06 18:30:57 -0700174 int dir, const char *stream, int event)
175{
176 struct snd_soc_dpcm_params *dpcm_params;
177
178 snd_soc_dapm_rtd_stream_event(fe, dir, event);
179
180 list_for_each_entry(dpcm_params, &fe->dpcm[dir].be_clients, list_be) {
181
182 struct snd_soc_pcm_runtime *be = dpcm_params->be;
183
184 dev_dbg(be->dev, "pm: BE %s stream %s event %d dir %d\n",
185 be->dai_link->name, stream, event, dir);
186
187 snd_soc_dapm_rtd_stream_event(be, dir, event);
188 }
189
190 return 0;
191}
192
193/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100194 * Called by ALSA when a PCM substream is opened, the runtime->hw record is
195 * then initialized and any private data can be allocated. This also calls
196 * startup for the cpu DAI, platform, machine and codec DAI.
197 */
198static int soc_pcm_open(struct snd_pcm_substream *substream)
199{
200 struct snd_soc_pcm_runtime *rtd = substream->private_data;
201 struct snd_pcm_runtime *runtime = substream->runtime;
202 struct snd_soc_platform *platform = rtd->platform;
203 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
204 struct snd_soc_dai *codec_dai = rtd->codec_dai;
205 struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
206 struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver;
207 int ret = 0;
208
Mark Brownd6652ef2011-12-03 20:14:31 +0000209 pm_runtime_get_sync(cpu_dai->dev);
210 pm_runtime_get_sync(codec_dai->dev);
211 pm_runtime_get_sync(platform->dev);
212
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100213 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100214
Steve Mucklef132c6c2012-06-06 18:30:57 -0700215 if (rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST)
216 snd_soc_set_runtime_hwparams(substream, &no_host_hardware);
217
Liam Girdwoodddee6272011-06-09 14:45:53 +0100218 /* startup the audio subsystem */
219 if (cpu_dai->driver->ops->startup) {
220 ret = cpu_dai->driver->ops->startup(substream, cpu_dai);
221 if (ret < 0) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700222 printk(KERN_ERR "asoc: can't open interface %s\n",
223 cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100224 goto out;
225 }
226 }
227
228 if (platform->driver->ops && platform->driver->ops->open) {
229 ret = platform->driver->ops->open(substream);
230 if (ret < 0) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700231 printk(KERN_ERR "asoc: can't open platform %s\n", platform->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100232 goto platform_err;
233 }
234 }
235
236 if (codec_dai->driver->ops->startup) {
Helen Zeng5749b092012-06-10 11:50:29 -0700237 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
238 ret = codec_dai->driver->ops->startup(substream,
239 codec_dai);
240 if (ret < 0) {
241 printk(KERN_ERR "asoc: can't open codec %s\n",
242 codec_dai->name);
243 goto codec_dai_err;
244 }
245 } else {
246 if (!codec_dai->capture_active) {
247 ret = codec_dai->driver->ops->startup(substream,
248 codec_dai);
249 if (ret < 0) {
250 printk(KERN_ERR "can't open codec %s\n",
251 codec_dai->name);
252 goto codec_dai_err;
253 }
254 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100255 }
256 }
257
258 if (rtd->dai_link->ops && rtd->dai_link->ops->startup) {
259 ret = rtd->dai_link->ops->startup(substream);
260 if (ret < 0) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700261 printk(KERN_ERR "asoc: %s startup failed\n", rtd->dai_link->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100262 goto machine_err;
263 }
264 }
265
Steve Mucklef132c6c2012-06-06 18:30:57 -0700266 /* DSP DAI links compat checks are different */
267 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm)
268 goto dynamic;
269
Liam Girdwoodddee6272011-06-09 14:45:53 +0100270 /* Check that the codec and cpu DAIs are compatible */
271 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
272 runtime->hw.rate_min =
273 max(codec_dai_drv->playback.rate_min,
274 cpu_dai_drv->playback.rate_min);
275 runtime->hw.rate_max =
276 min(codec_dai_drv->playback.rate_max,
277 cpu_dai_drv->playback.rate_max);
278 runtime->hw.channels_min =
279 max(codec_dai_drv->playback.channels_min,
280 cpu_dai_drv->playback.channels_min);
281 runtime->hw.channels_max =
282 min(codec_dai_drv->playback.channels_max,
283 cpu_dai_drv->playback.channels_max);
284 runtime->hw.formats =
285 codec_dai_drv->playback.formats & cpu_dai_drv->playback.formats;
286 runtime->hw.rates =
287 codec_dai_drv->playback.rates & cpu_dai_drv->playback.rates;
288 if (codec_dai_drv->playback.rates
289 & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
290 runtime->hw.rates |= cpu_dai_drv->playback.rates;
291 if (cpu_dai_drv->playback.rates
292 & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
293 runtime->hw.rates |= codec_dai_drv->playback.rates;
294 } else {
295 runtime->hw.rate_min =
296 max(codec_dai_drv->capture.rate_min,
297 cpu_dai_drv->capture.rate_min);
298 runtime->hw.rate_max =
299 min(codec_dai_drv->capture.rate_max,
300 cpu_dai_drv->capture.rate_max);
301 runtime->hw.channels_min =
302 max(codec_dai_drv->capture.channels_min,
303 cpu_dai_drv->capture.channels_min);
304 runtime->hw.channels_max =
305 min(codec_dai_drv->capture.channels_max,
306 cpu_dai_drv->capture.channels_max);
307 runtime->hw.formats =
308 codec_dai_drv->capture.formats & cpu_dai_drv->capture.formats;
309 runtime->hw.rates =
310 codec_dai_drv->capture.rates & cpu_dai_drv->capture.rates;
311 if (codec_dai_drv->capture.rates
312 & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
313 runtime->hw.rates |= cpu_dai_drv->capture.rates;
314 if (cpu_dai_drv->capture.rates
315 & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
316 runtime->hw.rates |= codec_dai_drv->capture.rates;
317 }
318
319 ret = -EINVAL;
320 snd_pcm_limit_hw_rates(runtime);
321 if (!runtime->hw.rates) {
322 printk(KERN_ERR "asoc: %s <-> %s No matching rates\n",
323 codec_dai->name, cpu_dai->name);
324 goto config_err;
325 }
326 if (!runtime->hw.formats) {
327 printk(KERN_ERR "asoc: %s <-> %s No matching formats\n",
328 codec_dai->name, cpu_dai->name);
329 goto config_err;
330 }
331 if (!runtime->hw.channels_min || !runtime->hw.channels_max ||
332 runtime->hw.channels_min > runtime->hw.channels_max) {
333 printk(KERN_ERR "asoc: %s <-> %s No matching channels\n",
334 codec_dai->name, cpu_dai->name);
335 goto config_err;
336 }
337
Mark Brown58ba9b22012-01-16 18:38:51 +0000338 soc_pcm_apply_msb(substream, codec_dai);
339 soc_pcm_apply_msb(substream, cpu_dai);
340
Liam Girdwoodddee6272011-06-09 14:45:53 +0100341 /* Symmetry only applies if we've already got an active stream. */
Dong Aisheng17841022011-08-29 17:15:14 +0800342 if (cpu_dai->active) {
343 ret = soc_pcm_apply_symmetry(substream, cpu_dai);
344 if (ret != 0)
345 goto config_err;
346 }
347
348 if (codec_dai->active) {
349 ret = soc_pcm_apply_symmetry(substream, codec_dai);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100350 if (ret != 0)
351 goto config_err;
352 }
353
354 pr_debug("asoc: %s <-> %s info:\n",
355 codec_dai->name, cpu_dai->name);
356 pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates);
357 pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min,
358 runtime->hw.channels_max);
359 pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min,
360 runtime->hw.rate_max);
361
Steve Mucklef132c6c2012-06-06 18:30:57 -0700362dynamic:
Liam Girdwoodddee6272011-06-09 14:45:53 +0100363 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
364 cpu_dai->playback_active++;
365 codec_dai->playback_active++;
366 } else {
367 cpu_dai->capture_active++;
368 codec_dai->capture_active++;
369 }
370 cpu_dai->active++;
371 codec_dai->active++;
372 rtd->codec->active++;
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100373 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100374 return 0;
375
376config_err:
377 if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
378 rtd->dai_link->ops->shutdown(substream);
379
380machine_err:
381 if (codec_dai->driver->ops->shutdown)
382 codec_dai->driver->ops->shutdown(substream, codec_dai);
383
384codec_dai_err:
385 if (platform->driver->ops && platform->driver->ops->close)
386 platform->driver->ops->close(substream);
387
388platform_err:
389 if (cpu_dai->driver->ops->shutdown)
390 cpu_dai->driver->ops->shutdown(substream, cpu_dai);
391out:
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100392 mutex_unlock(&rtd->pcm_mutex);
Mark Brownd6652ef2011-12-03 20:14:31 +0000393
394 pm_runtime_put(platform->dev);
395 pm_runtime_put(codec_dai->dev);
396 pm_runtime_put(cpu_dai->dev);
397
Liam Girdwoodddee6272011-06-09 14:45:53 +0100398 return ret;
399}
400
401/*
402 * Power down the audio subsystem pmdown_time msecs after close is called.
403 * This is to ensure there are no pops or clicks in between any music tracks
404 * due to DAPM power cycling.
405 */
406static void close_delayed_work(struct work_struct *work)
407{
408 struct snd_soc_pcm_runtime *rtd =
409 container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
410 struct snd_soc_dai *codec_dai = rtd->codec_dai;
411
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100412 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100413
414 pr_debug("pop wq checking: %s status: %s waiting: %s\n",
415 codec_dai->driver->playback.stream_name,
416 codec_dai->playback_active ? "active" : "inactive",
417 codec_dai->pop_wait ? "yes" : "no");
418
419 /* are we waiting on this codec DAI stream */
420 if (codec_dai->pop_wait == 1) {
421 codec_dai->pop_wait = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -0700422 snd_soc_dapm_stream_event(rtd,
423 codec_dai->driver->playback.stream_name,
424 SND_SOC_DAPM_STREAM_STOP);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100425 }
426
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100427 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100428}
429
430/*
431 * Called by ALSA when a PCM substream is closed. Private data can be
432 * freed here. The cpu DAI, codec DAI, machine and platform are also
433 * shutdown.
434 */
Liam Girdwood91d5e6b2011-06-09 17:04:59 +0100435static int soc_pcm_close(struct snd_pcm_substream *substream)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100436{
437 struct snd_soc_pcm_runtime *rtd = substream->private_data;
438 struct snd_soc_platform *platform = rtd->platform;
439 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
440 struct snd_soc_dai *codec_dai = rtd->codec_dai;
441 struct snd_soc_codec *codec = rtd->codec;
442
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100443 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100444
445 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
446 cpu_dai->playback_active--;
447 codec_dai->playback_active--;
448 } else {
449 cpu_dai->capture_active--;
450 codec_dai->capture_active--;
451 }
452
453 cpu_dai->active--;
454 codec_dai->active--;
455 codec->active--;
456
Dong Aisheng17841022011-08-29 17:15:14 +0800457 /* clear the corresponding DAIs rate when inactive */
458 if (!cpu_dai->active)
459 cpu_dai->rate = 0;
460
461 if (!codec_dai->active)
462 codec_dai->rate = 0;
Sascha Hauer25b76792011-08-17 09:20:01 +0200463
Liam Girdwoodddee6272011-06-09 14:45:53 +0100464 /* Muting the DAC suppresses artifacts caused during digital
465 * shutdown, for example from stopping clocks.
466 */
467 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
468 snd_soc_dai_digital_mute(codec_dai, 1);
469
Helen Zengd5131792012-06-28 11:24:11 -0700470 if (cpu_dai->driver->ops->shutdown)
471 cpu_dai->driver->ops->shutdown(substream, cpu_dai);
472
473 if (codec_dai->driver->ops->shutdown) {
Helen Zeng5749b092012-06-10 11:50:29 -0700474 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
475 codec_dai->driver->ops->shutdown(substream, codec_dai);
476 } else {
477 if (!codec_dai->capture_active)
478 codec_dai->driver->ops->shutdown(substream,
479 codec_dai);
480 }
481 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100482
Liam Girdwoodddee6272011-06-09 14:45:53 +0100483 if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
484 rtd->dai_link->ops->shutdown(substream);
485
486 if (platform->driver->ops && platform->driver->ops->close)
487 platform->driver->ops->close(substream);
488 cpu_dai->runtime = NULL;
489
490 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700491 if (codec->ignore_pmdown_time ||
492 rtd->dai_link->ignore_pmdown_time ||
493 !rtd->pmdown_time) {
Peter Ujfalusi1d69c5c2011-10-14 14:43:33 +0300494 /* powered down playback stream now */
495 snd_soc_dapm_stream_event(rtd,
Steve Mucklef132c6c2012-06-06 18:30:57 -0700496 codec_dai->driver->playback.stream_name,
497 SND_SOC_DAPM_STREAM_STOP);
Peter Ujfalusi1d69c5c2011-10-14 14:43:33 +0300498 } else {
499 /* start delayed pop wq here for playback streams */
500 codec_dai->pop_wait = 1;
501 schedule_delayed_work(&rtd->delayed_work,
502 msecs_to_jiffies(rtd->pmdown_time));
503 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100504 } else {
505 /* capture streams can be powered down now */
Helen Zeng5749b092012-06-10 11:50:29 -0700506 if (!codec_dai->capture_active)
507 snd_soc_dapm_stream_event(rtd,
Steve Mucklef132c6c2012-06-06 18:30:57 -0700508 codec_dai->driver->capture.stream_name,
509 SND_SOC_DAPM_STREAM_STOP);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100510 }
511
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100512 mutex_unlock(&rtd->pcm_mutex);
Mark Brownd6652ef2011-12-03 20:14:31 +0000513
514 pm_runtime_put(platform->dev);
515 pm_runtime_put(codec_dai->dev);
516 pm_runtime_put(cpu_dai->dev);
517
Liam Girdwoodddee6272011-06-09 14:45:53 +0100518 return 0;
519}
520
521/*
522 * Called by ALSA when the PCM substream is prepared, can set format, sample
523 * rate, etc. This function is non atomic and can be called multiple times,
524 * it can refer to the runtime info.
525 */
526static int soc_pcm_prepare(struct snd_pcm_substream *substream)
527{
528 struct snd_soc_pcm_runtime *rtd = substream->private_data;
529 struct snd_soc_platform *platform = rtd->platform;
530 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
531 struct snd_soc_dai *codec_dai = rtd->codec_dai;
532 int ret = 0;
533
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100534 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100535
536 if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) {
537 ret = rtd->dai_link->ops->prepare(substream);
538 if (ret < 0) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700539 printk(KERN_ERR "asoc: machine prepare error\n");
Liam Girdwoodddee6272011-06-09 14:45:53 +0100540 goto out;
541 }
542 }
543
544 if (platform->driver->ops && platform->driver->ops->prepare) {
545 ret = platform->driver->ops->prepare(substream);
546 if (ret < 0) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700547 printk(KERN_ERR "asoc: platform prepare error\n");
Liam Girdwoodddee6272011-06-09 14:45:53 +0100548 goto out;
549 }
550 }
551
552 if (codec_dai->driver->ops->prepare) {
553 ret = codec_dai->driver->ops->prepare(substream, codec_dai);
554 if (ret < 0) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700555 printk(KERN_ERR "asoc: codec DAI prepare error\n");
Liam Girdwoodddee6272011-06-09 14:45:53 +0100556 goto out;
557 }
558 }
559
560 if (cpu_dai->driver->ops->prepare) {
561 ret = cpu_dai->driver->ops->prepare(substream, cpu_dai);
562 if (ret < 0) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700563 printk(KERN_ERR "asoc: cpu DAI prepare error\n");
Liam Girdwoodddee6272011-06-09 14:45:53 +0100564 goto out;
565 }
566 }
567
568 /* cancel any delayed stream shutdown that is pending */
569 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
570 codec_dai->pop_wait) {
571 codec_dai->pop_wait = 0;
572 cancel_delayed_work(&rtd->delayed_work);
573 }
574
Steve Mucklef132c6c2012-06-06 18:30:57 -0700575 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
576 snd_soc_dapm_stream_event(rtd,
577 codec_dai->driver->playback.stream_name,
578 SND_SOC_DAPM_STREAM_START);
Helen Zeng5749b092012-06-10 11:50:29 -0700579 else {
580 if (codec_dai->capture_active == 1)
581 snd_soc_dapm_stream_event(rtd,
Steve Mucklef132c6c2012-06-06 18:30:57 -0700582 codec_dai->driver->capture.stream_name,
583 SND_SOC_DAPM_STREAM_START);
Helen Zeng5749b092012-06-10 11:50:29 -0700584 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100585 snd_soc_dai_digital_mute(codec_dai, 0);
586
587out:
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100588 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100589 return ret;
590}
591
592/*
593 * Called by ALSA when the hardware params are set by application. This
594 * function can also be called multiple times and can allocate buffers
595 * (using snd_pcm_lib_* ). It's non-atomic.
596 */
597static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
598 struct snd_pcm_hw_params *params)
599{
600 struct snd_soc_pcm_runtime *rtd = substream->private_data;
601 struct snd_soc_platform *platform = rtd->platform;
602 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
603 struct snd_soc_dai *codec_dai = rtd->codec_dai;
604 int ret = 0;
605
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100606 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100607
608 if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) {
609 ret = rtd->dai_link->ops->hw_params(substream, params);
610 if (ret < 0) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700611 printk(KERN_ERR "asoc: machine hw_params failed\n");
Liam Girdwoodddee6272011-06-09 14:45:53 +0100612 goto out;
613 }
614 }
615
616 if (codec_dai->driver->ops->hw_params) {
Helen Zeng5749b092012-06-10 11:50:29 -0700617 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
618 ret = codec_dai->driver->ops->hw_params(substream,
619 params, codec_dai);
620 if (ret < 0) {
621 printk(KERN_ERR "not set codec %s hw params\n",
622 codec_dai->name);
623 goto codec_err;
624 }
625 } else {
626 if (codec_dai->capture_active == 1) {
627 ret = codec_dai->driver->ops->hw_params(
628 substream, params, codec_dai);
629 if (ret < 0) {
630 printk(KERN_ERR "fail: %s hw params\n",
631 codec_dai->name);
632 goto codec_err;
633 }
634 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100635 }
636 }
637
638 if (cpu_dai->driver->ops->hw_params) {
639 ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai);
640 if (ret < 0) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700641 printk(KERN_ERR "asoc: interface %s hw params failed\n",
642 cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100643 goto interface_err;
644 }
645 }
646
647 if (platform->driver->ops && platform->driver->ops->hw_params) {
648 ret = platform->driver->ops->hw_params(substream, params);
649 if (ret < 0) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700650 printk(KERN_ERR "asoc: platform %s hw params failed\n",
651 platform->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100652 goto platform_err;
653 }
654 }
655
Dong Aisheng17841022011-08-29 17:15:14 +0800656 /* store the rate for each DAIs */
657 cpu_dai->rate = params_rate(params);
658 codec_dai->rate = params_rate(params);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100659
Steve Mucklef132c6c2012-06-06 18:30:57 -0700660 /* malloc a page for hostless IO.
661 * FIXME: rework with alsa-lib changes so that this malloc is not required.
662 */
663 if (rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST) {
664 substream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV;
665 substream->dma_buffer.dev.dev = rtd->dev;
666 substream->dma_buffer.dev.dev->coherent_dma_mask = DMA_BIT_MASK(32);
667 substream->dma_buffer.private_data = NULL;
668
669 ret = snd_pcm_lib_malloc_pages(substream, PAGE_SIZE);
670 if (ret < 0)
671 goto platform_err;
672 }
673
Liam Girdwoodddee6272011-06-09 14:45:53 +0100674out:
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100675 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100676 return ret;
677
678platform_err:
679 if (cpu_dai->driver->ops->hw_free)
680 cpu_dai->driver->ops->hw_free(substream, cpu_dai);
681
682interface_err:
683 if (codec_dai->driver->ops->hw_free)
684 codec_dai->driver->ops->hw_free(substream, codec_dai);
685
686codec_err:
687 if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
688 rtd->dai_link->ops->hw_free(substream);
689
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100690 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100691 return ret;
692}
693
694/*
695 * Frees resources allocated by hw_params, can be called multiple times
696 */
697static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
698{
699 struct snd_soc_pcm_runtime *rtd = substream->private_data;
700 struct snd_soc_platform *platform = rtd->platform;
701 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
702 struct snd_soc_dai *codec_dai = rtd->codec_dai;
703 struct snd_soc_codec *codec = rtd->codec;
704
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100705 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100706
707 /* apply codec digital mute */
708 if (!codec->active)
709 snd_soc_dai_digital_mute(codec_dai, 1);
710
711 /* free any machine hw params */
712 if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
713 rtd->dai_link->ops->hw_free(substream);
714
715 /* free any DMA resources */
716 if (platform->driver->ops && platform->driver->ops->hw_free)
717 platform->driver->ops->hw_free(substream);
718
719 /* now free hw params for the DAIs */
720 if (codec_dai->driver->ops->hw_free)
721 codec_dai->driver->ops->hw_free(substream, codec_dai);
722
723 if (cpu_dai->driver->ops->hw_free)
724 cpu_dai->driver->ops->hw_free(substream, cpu_dai);
725
Steve Mucklef132c6c2012-06-06 18:30:57 -0700726 if (rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST)
727 snd_pcm_lib_free_pages(substream);
728
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100729 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100730 return 0;
731}
732
733static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
734{
735 struct snd_soc_pcm_runtime *rtd = substream->private_data;
736 struct snd_soc_platform *platform = rtd->platform;
737 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
738 struct snd_soc_dai *codec_dai = rtd->codec_dai;
739 int ret;
740
741 if (codec_dai->driver->ops->trigger) {
Helen Zeng5749b092012-06-10 11:50:29 -0700742 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
743 ret = codec_dai->driver->ops->trigger(substream,
744 cmd, codec_dai);
745 if (ret < 0)
746 return ret;
747 } else {
748 if (codec_dai->capture_active == 1) {
749 ret = codec_dai->driver->ops->trigger(
750 substream, cmd, codec_dai);
751 if (ret < 0)
752 return ret;
753 }
754 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100755 }
756
757 if (platform->driver->ops && platform->driver->ops->trigger) {
758 ret = platform->driver->ops->trigger(substream, cmd);
759 if (ret < 0)
760 return ret;
761 }
762
763 if (cpu_dai->driver->ops->trigger) {
764 ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai);
765 if (ret < 0)
766 return ret;
767 }
768 return 0;
769}
770
Steve Mucklef132c6c2012-06-06 18:30:57 -0700771int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, int cmd)
772{
773 struct snd_soc_pcm_runtime *rtd = substream->private_data;
774 struct snd_soc_platform *platform = rtd->platform;
775 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
776 struct snd_soc_dai *codec_dai = rtd->codec_dai;
777 int ret;
778
779 if (codec_dai->driver->ops->bespoke_trigger) {
780 ret = codec_dai->driver->ops->bespoke_trigger(substream, cmd, codec_dai);
781 if (ret < 0)
782 return ret;
783 }
784
785 if (platform->driver->bespoke_trigger) {
786 ret = platform->driver->bespoke_trigger(substream, cmd);
787 if (ret < 0)
788 return ret;
789 }
790
791 if (cpu_dai->driver->ops->bespoke_trigger) {
792 ret = cpu_dai->driver->ops->bespoke_trigger(substream, cmd, cpu_dai);
793 if (ret < 0)
794 return ret;
795 }
796 return 0;
797}
798
Liam Girdwoodddee6272011-06-09 14:45:53 +0100799/*
800 * soc level wrapper for pointer callback
801 * If cpu_dai, codec_dai, platform driver has the delay callback, than
802 * the runtime->delay will be updated accordingly.
803 */
804static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
805{
806 struct snd_soc_pcm_runtime *rtd = substream->private_data;
807 struct snd_soc_platform *platform = rtd->platform;
808 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
809 struct snd_soc_dai *codec_dai = rtd->codec_dai;
810 struct snd_pcm_runtime *runtime = substream->runtime;
811 snd_pcm_uframes_t offset = 0;
812 snd_pcm_sframes_t delay = 0;
813
814 if (platform->driver->ops && platform->driver->ops->pointer)
815 offset = platform->driver->ops->pointer(substream);
816
817 if (cpu_dai->driver->ops->delay)
818 delay += cpu_dai->driver->ops->delay(substream, cpu_dai);
819
820 if (codec_dai->driver->ops->delay)
821 delay += codec_dai->driver->ops->delay(substream, codec_dai);
822
823 if (platform->driver->delay)
824 delay += platform->driver->delay(substream, codec_dai);
825
826 runtime->delay = delay;
827
828 return offset;
829}
830
Steve Mucklef132c6c2012-06-06 18:30:57 -0700831static inline int be_connect(struct snd_soc_pcm_runtime *fe,
832 struct snd_soc_pcm_runtime *be, int stream)
833{
834 struct snd_soc_dpcm_params *dpcm_params;
835
Eric Laurentdb88f282013-07-15 10:00:45 -0700836 if (!fe->dpcm[stream].runtime && !fe->fe_compr) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700837 dev_err(fe->dev, "%s no runtime\n", fe->dai_link->name);
838 return -ENODEV;
839 }
840
841 /* only add new dpcm_paramss */
842 list_for_each_entry(dpcm_params, &fe->dpcm[stream].be_clients, list_be) {
843 if (dpcm_params->be == be && dpcm_params->fe == fe)
844 return 0;
845 }
846
847 dpcm_params = kzalloc(sizeof(struct snd_soc_dpcm_params), GFP_KERNEL);
848 if (!dpcm_params)
849 return -ENOMEM;
850
851 dpcm_params->be = be;
852 dpcm_params->fe = fe;
853 be->dpcm[stream].runtime = fe->dpcm[stream].runtime;
854 dpcm_params->state = SND_SOC_DPCM_LINK_STATE_NEW;
855 list_add(&dpcm_params->list_be, &fe->dpcm[stream].be_clients);
856 list_add(&dpcm_params->list_fe, &be->dpcm[stream].fe_clients);
857
858 dev_dbg(fe->dev, " connected new DSP %s path %s %s %s\n",
859 stream ? "capture" : "playback", fe->dai_link->name,
860 stream ? "<-" : "->", be->dai_link->name);
861
862#ifdef CONFIG_DEBUG_FS
863 dpcm_params->debugfs_state = debugfs_create_u32(be->dai_link->name, 0644,
864 fe->debugfs_dpcm_root, &dpcm_params->state);
865#endif
866
867 return 1;
868}
869
870static inline void be_reparent(struct snd_soc_pcm_runtime *fe,
871 struct snd_soc_pcm_runtime *be, int stream)
872{
873 struct snd_soc_dpcm_params *dpcm_params;
874 struct snd_pcm_substream *fe_substream, *be_substream;
875
876 /* reparent if BE is connected to other FEs */
877 if (!be->dpcm[stream].users)
878 return;
879
880 be_substream = snd_soc_dpcm_get_substream(be, stream);
881
882 list_for_each_entry(dpcm_params, &be->dpcm[stream].fe_clients, list_fe) {
883 if (dpcm_params->fe != fe) {
884
885 dev_dbg(fe->dev, " reparent %s path %s %s %s\n",
886 stream ? "capture" : "playback",
887 dpcm_params->fe->dai_link->name,
888 stream ? "<-" : "->", dpcm_params->be->dai_link->name);
889
890 fe_substream = snd_soc_dpcm_get_substream(dpcm_params->fe,
891 stream);
892 be_substream->runtime = fe_substream->runtime;
893 break;
894 }
895 }
896}
897
Liam Girdwood748da442013-05-21 10:26:42 +0100898void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
Steve Mucklef132c6c2012-06-06 18:30:57 -0700899{
900 struct snd_soc_dpcm_params *dpcm_params, *d;
901
902 list_for_each_entry_safe(dpcm_params, d, &fe->dpcm[stream].be_clients, list_be) {
903 dev_dbg(fe->dev, "BE %s disconnect check for %s\n",
904 stream ? "capture" : "playback",
905 dpcm_params->be->dai_link->name);
906
907 if (dpcm_params->state == SND_SOC_DPCM_LINK_STATE_FREE) {
908 dev_dbg(fe->dev, " freed DSP %s path %s %s %s\n",
909 stream ? "capture" : "playback", fe->dai_link->name,
910 stream ? "<-" : "->", dpcm_params->be->dai_link->name);
911
912 /* BEs still alive need new FE */
913 be_reparent(fe, dpcm_params->be, stream);
914
915#ifdef CONFIG_DEBUG_FS
916 debugfs_remove(dpcm_params->debugfs_state);
917#endif
918
919 list_del(&dpcm_params->list_be);
920 list_del(&dpcm_params->list_fe);
921 kfree(dpcm_params);
922 }
923 }
924}
925
926static struct snd_soc_pcm_runtime *be_get_rtd(struct snd_soc_card *card,
927 struct snd_soc_dapm_widget *widget)
928{
929 struct snd_soc_pcm_runtime *be;
930 int i;
931
932 if (!widget->sname) {
933 dev_err(card->dev, "widget %s has no stream\n", widget->name);
934 return NULL;
935 }
936
937 for (i = 0; i < card->num_links; i++) {
938 be = &card->rtd[i];
939
940 if (!strcmp(widget->sname, be->dai_link->stream_name))
941 return be;
942 }
943
944 dev_err(card->dev, "can't get BE for %s\n", widget->name);
945 return NULL;
946}
947
948static struct snd_soc_dapm_widget *be_get_widget(struct snd_soc_card *card,
949 struct snd_soc_pcm_runtime *rtd)
950{
951 struct snd_soc_dapm_widget *widget;
952
953 list_for_each_entry(widget, &card->widgets, list) {
954
955 if (!widget->sname)
956 continue;
957
958 if (!strcmp(widget->sname, rtd->dai_link->stream_name))
959 return widget;
960 }
961
962 dev_err(card->dev, "can't get widget for %s\n",
963 rtd->dai_link->stream_name);
964 return NULL;
965}
966
967static int widget_in_list(struct snd_soc_dapm_widget_list *list,
968 struct snd_soc_dapm_widget *widget)
969{
970 int i;
971
972 for (i = 0; i < list->num_widgets; i++) {
973 if (widget == list->widgets[i])
974 return 1;
975 }
976
977 return 0;
978}
979
Liam Girdwood748da442013-05-21 10:26:42 +0100980int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
Steve Mucklef132c6c2012-06-06 18:30:57 -0700981 int stream, struct snd_soc_dapm_widget_list **list_)
982{
983 struct snd_soc_dai *cpu_dai = fe->cpu_dai;
984 struct snd_soc_dapm_widget_list *list;
985 int paths;
986
987 list = kzalloc(sizeof(struct snd_soc_dapm_widget_list) +
988 sizeof(struct snd_soc_dapm_widget *), GFP_KERNEL);
989 if (list == NULL)
990 return -ENOMEM;
991
992 /* get number of valid DAI paths and their widgets */
993 paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, &list);
994
995 dev_dbg(fe->dev, "found %d audio %s paths\n", paths,
996 stream ? "capture" : "playback");
997
998 *list_ = list;
999 return paths;
1000}
1001
Steve Mucklef132c6c2012-06-06 18:30:57 -07001002static int be_prune_old(struct snd_soc_pcm_runtime *fe, int stream,
1003 struct snd_soc_dapm_widget_list **list_)
1004{
1005 struct snd_soc_card *card = fe->card;
1006 struct snd_soc_dpcm_params *dpcm_params;
1007 struct snd_soc_dapm_widget_list *list = *list_;
1008 struct snd_soc_dapm_widget *widget;
1009 int old = 0;
1010
1011 /* Destroy any old FE <--> BE connections */
1012 list_for_each_entry(dpcm_params, &fe->dpcm[stream].be_clients, list_be) {
1013
1014 /* is there a valid widget for this BE */
1015 widget = be_get_widget(card, dpcm_params->be);
1016 if (!widget) {
1017 dev_err(fe->dev, "no widget found for %s\n",
1018 dpcm_params->be->dai_link->name);
1019 continue;
1020 }
1021
1022 /* prune the BE if it's no longer in our active list */
1023 if (widget_in_list(list, widget))
1024 continue;
1025
1026 dev_dbg(fe->dev, "pruning %s BE %s for %s\n",
1027 stream ? "capture" : "playback", dpcm_params->be->dai_link->name,
1028 fe->dai_link->name);
1029 dpcm_params->state = SND_SOC_DPCM_LINK_STATE_FREE;
1030 dpcm_params->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1031 old++;
1032 }
1033
1034 dev_dbg(fe->dev, "found %d old BEs\n", old);
1035 return old;
1036}
1037
1038static int be_add_new(struct snd_soc_pcm_runtime *fe, int stream,
1039 struct snd_soc_dapm_widget_list **list_)
1040{
1041 struct snd_soc_card *card = fe->card;
1042 struct snd_soc_dapm_widget_list *list = *list_;
1043 enum snd_soc_dapm_type be_type;
1044 int i, new = 0, err;
1045
1046 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1047 be_type = snd_soc_dapm_aif_out;
1048 else
1049 be_type = snd_soc_dapm_aif_in;
1050
1051 /* Create any new FE <--> BE connections */
1052 for (i = 0; i < list->num_widgets; i++) {
1053
1054 if (list->widgets[i]->id == be_type) {
1055 struct snd_soc_pcm_runtime *be;
1056
1057 /* is there a valid BE rtd for this widget */
1058 be = be_get_rtd(card, list->widgets[i]);
1059 if (!be) {
1060 dev_err(fe->dev, "no BE found for %s\n",
1061 list->widgets[i]->name);
1062 continue;
1063 }
1064
1065 /* don't connect if FE is not running */
Eric Laurentdb88f282013-07-15 10:00:45 -07001066 if (!fe->dpcm[stream].runtime && !fe->fe_compr)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001067 continue;
1068
1069 /* newly connected FE and BE */
1070 err = be_connect(fe, be, stream);
1071 if (err < 0) {
1072 dev_err(fe->dev, "can't connect %s\n", list->widgets[i]->name);
1073 break;
1074 } else if (err == 0) /* already connected */
1075 continue;
1076
1077 /* new */
1078 be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1079 new++;
1080 }
1081 }
1082
1083 dev_dbg(fe->dev, "found %d new BEs\n", new);
1084 return new;
1085}
1086
1087/*
1088 * Find the corresponding BE DAIs that source or sink audio to this
1089 * FE substream.
1090 */
Liam Girdwood748da442013-05-21 10:26:42 +01001091int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
Steve Mucklef132c6c2012-06-06 18:30:57 -07001092 int stream, struct snd_soc_dapm_widget_list **list, int new)
1093{
1094 if (new)
1095 return be_add_new(fe, stream, list);
1096 else
1097 return be_prune_old(fe, stream, list);
1098 return 0;
1099}
1100
1101/*
1102 * Clear the runtime pending state of all BE's.
1103 */
Liam Girdwood748da442013-05-21 10:26:42 +01001104void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001105{
1106 struct snd_soc_dpcm_params *dpcm_params;
1107
1108 list_for_each_entry(dpcm_params, &fe->dpcm[stream].be_clients, list_be)
1109 dpcm_params->be->dpcm[stream].runtime_update =
1110 SND_SOC_DPCM_UPDATE_NO;
1111}
1112
1113/* Unwind the BE startup */
1114static void soc_dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe, int stream)
1115{
1116 struct snd_soc_dpcm_params *dpcm_params;
1117
1118 /* disable any enabled and non active backends */
1119 list_for_each_entry(dpcm_params, &fe->dpcm[stream].be_clients, list_be) {
1120
1121 struct snd_soc_pcm_runtime *be = dpcm_params->be;
1122 struct snd_pcm_substream *be_substream =
1123 snd_soc_dpcm_get_substream(be, stream);
1124
1125 if (be->dpcm[stream].users == 0)
1126 dev_err(be->dev, "no users %s at close - state %d\n",
1127 stream ? "capture" : "playback", be->dpcm[stream].state);
1128
1129 if (--be->dpcm[stream].users != 0)
1130 continue;
1131
1132 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1133 continue;
1134
1135 soc_pcm_close(be_substream);
1136 be_substream->runtime = NULL;
1137
1138 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1139 }
1140}
1141
1142/* Startup all new BE */
Liam Girdwood748da442013-05-21 10:26:42 +01001143int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001144{
1145 struct snd_soc_dpcm_params *dpcm_params;
1146 int err, count = 0;
1147
1148 /* only startup BE DAIs that are either sinks or sources to this FE DAI */
1149 list_for_each_entry(dpcm_params, &fe->dpcm[stream].be_clients, list_be) {
1150
1151 struct snd_soc_pcm_runtime *be = dpcm_params->be;
1152 struct snd_pcm_substream *be_substream =
1153 snd_soc_dpcm_get_substream(be, stream);
1154
1155 /* is this op for this BE ? */
1156 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1157 continue;
1158
1159 /* first time the dpcm_params is open ? */
1160 if (be->dpcm[stream].users == MAX_BE_USERS)
1161 dev_err(be->dev, "too many users %s at open - state %d\n",
1162 stream ? "capture" : "playback", be->dpcm[stream].state);
1163
1164 if (be->dpcm[stream].users++ != 0)
1165 continue;
1166
1167 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
1168 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
1169 continue;
1170
1171 dev_dbg(be->dev, "dpcm: open BE %s\n", be->dai_link->name);
1172
1173 be_substream->runtime = be->dpcm[stream].runtime;
1174 err = soc_pcm_open(be_substream);
1175 if (err < 0) {
1176 dev_err(be->dev, "BE open failed %d\n", err);
1177 be->dpcm[stream].users--;
1178 if (be->dpcm[stream].users < 0)
1179 dev_err(be->dev, "no users %s at unwind - state %d\n",
1180 stream ? "capture" : "playback",
1181 be->dpcm[stream].state);
1182
1183 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1184 goto unwind;
1185 }
1186
1187 be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1188 count++;
1189 }
1190
1191 return count;
1192
1193unwind:
1194 /* disable any enabled and non active backends */
1195 list_for_each_entry_continue_reverse(dpcm_params, &fe->dpcm[stream].be_clients, list_be) {
1196 struct snd_soc_pcm_runtime *be = dpcm_params->be;
1197 struct snd_pcm_substream *be_substream =
1198 snd_soc_dpcm_get_substream(be, stream);
1199
1200 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1201 continue;
1202
1203 if (be->dpcm[stream].users == 0)
1204 dev_err(be->dev, "no users %s at close - state %d\n",
1205 stream ? "capture" : "playback", be->dpcm[stream].state);
1206
1207 if (--be->dpcm[stream].users != 0)
1208 continue;
1209
1210 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1211 continue;
1212
1213 soc_pcm_close(be_substream);
1214 be_substream->runtime = NULL;
1215
1216 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1217 }
1218
1219 return err;
1220}
1221
1222void soc_dpcm_set_dynamic_runtime(struct snd_pcm_substream *substream)
1223{
1224 struct snd_pcm_runtime *runtime = substream->runtime;
1225 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1226 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
1227 struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
1228
1229 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1230 runtime->hw.rate_min = cpu_dai_drv->playback.rate_min;
1231 runtime->hw.rate_max = cpu_dai_drv->playback.rate_max;
1232 runtime->hw.channels_min = cpu_dai_drv->playback.channels_min;
1233 runtime->hw.channels_max = cpu_dai_drv->playback.channels_max;
1234 runtime->hw.formats &= cpu_dai_drv->playback.formats;
1235 runtime->hw.rates = cpu_dai_drv->playback.rates;
1236 } else {
1237 runtime->hw.rate_min = cpu_dai_drv->capture.rate_min;
1238 runtime->hw.rate_max = cpu_dai_drv->capture.rate_max;
1239 runtime->hw.channels_min = cpu_dai_drv->capture.channels_min;
1240 runtime->hw.channels_max = cpu_dai_drv->capture.channels_max;
1241 runtime->hw.formats &= cpu_dai_drv->capture.formats;
1242 runtime->hw.rates = cpu_dai_drv->capture.rates;
1243 }
1244}
1245
1246static int soc_dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
1247{
1248 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
1249 struct snd_pcm_runtime *runtime = fe_substream->runtime;
1250 int stream = fe_substream->stream, ret = 0;
1251
Steve Mucklef132c6c2012-06-06 18:30:57 -07001252 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
1253
Liam Girdwood748da442013-05-21 10:26:42 +01001254 ret = dpcm_be_dai_startup(fe, fe_substream->stream);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001255 if (ret < 0) {
1256 dev_err(fe->dev,"dpcm: failed to start some BEs %d\n", ret);
1257 goto be_err;
1258 }
1259
1260 dev_dbg(fe->dev, "dpcm: open FE %s\n", fe->dai_link->name);
1261
1262 /* start the DAI frontend */
1263 ret = soc_pcm_open(fe_substream);
1264 if (ret < 0) {
1265 dev_err(fe->dev,"dpcm: failed to start FE %d\n", ret);
1266 goto unwind;
1267 }
1268
1269 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1270
1271 soc_dpcm_set_dynamic_runtime(fe_substream);
1272 snd_pcm_limit_hw_rates(runtime);
1273
1274 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
Steve Mucklef132c6c2012-06-06 18:30:57 -07001275 return 0;
1276
1277unwind:
1278 soc_dpcm_be_dai_startup_unwind(fe, fe_substream->stream);
1279be_err:
1280 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
Steve Mucklef132c6c2012-06-06 18:30:57 -07001281 return ret;
1282}
1283
1284/* BE shutdown - called on DAPM sync updates (i.e. FE is already running)*/
Liam Girdwood748da442013-05-21 10:26:42 +01001285int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001286{
1287 struct snd_soc_dpcm_params *dpcm_params;
1288
1289 /* only shutdown backends that are either sinks or sources to this frontend DAI */
1290 list_for_each_entry(dpcm_params, &fe->dpcm[stream].be_clients, list_be) {
1291
1292 struct snd_soc_pcm_runtime *be = dpcm_params->be;
1293 struct snd_pcm_substream *be_substream =
1294 snd_soc_dpcm_get_substream(be, stream);
1295
1296 /* is this op for this BE ? */
1297 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1298 continue;
1299
1300 if (be->dpcm[stream].users == 0)
1301 dev_err(be->dev, "no users %s at close - state %d\n",
1302 stream ? "capture" : "playback", be->dpcm[stream].state);
1303
1304 if (--be->dpcm[stream].users != 0)
1305 continue;
1306
1307 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
1308 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN))
1309 continue;
1310
1311 dev_dbg(be->dev, "dpcm: close BE %s\n",
1312 dpcm_params->fe->dai_link->name);
1313
1314 soc_pcm_close(be_substream);
1315 be_substream->runtime = NULL;
1316
1317 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1318 }
1319 return 0;
1320}
1321
1322/* FE +BE shutdown - called on FE PCM ops */
1323static int soc_dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
1324{
1325 struct snd_soc_pcm_runtime *fe = substream->private_data;
1326 int stream = substream->stream;
1327
Steve Mucklef132c6c2012-06-06 18:30:57 -07001328 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
1329
1330 dev_dbg(fe->dev, "dpcm: close FE %s\n", fe->dai_link->name);
1331
1332 /* now shutdown the frontend */
1333 soc_pcm_close(substream);
1334
1335 /* shutdown the BEs */
Liam Girdwood748da442013-05-21 10:26:42 +01001336 dpcm_be_dai_shutdown(fe, substream->stream);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001337 /* run the stream event for each BE */
1338 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
Eric Laurentdb88f282013-07-15 10:00:45 -07001339 dpcm_dapm_stream_event(fe, stream,
Steve Mucklef132c6c2012-06-06 18:30:57 -07001340 fe->cpu_dai->driver->playback.stream_name,
1341 SND_SOC_DAPM_STREAM_STOP);
1342 else
Eric Laurentdb88f282013-07-15 10:00:45 -07001343 dpcm_dapm_stream_event(fe, stream,
Steve Mucklef132c6c2012-06-06 18:30:57 -07001344 fe->cpu_dai->driver->capture.stream_name,
1345 SND_SOC_DAPM_STREAM_STOP);
1346
1347 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1348 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
1349
Steve Mucklef132c6c2012-06-06 18:30:57 -07001350 return 0;
1351}
1352
Liam Girdwood748da442013-05-21 10:26:42 +01001353int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001354{
1355 struct snd_soc_dpcm_params *dpcm_params;
1356 int ret;
1357
1358 list_for_each_entry(dpcm_params, &fe->dpcm[stream].be_clients, list_be) {
1359
1360 struct snd_soc_pcm_runtime *be = dpcm_params->be;
1361 struct snd_pcm_substream *be_substream =
1362 snd_soc_dpcm_get_substream(be, stream);
1363
1364 /* is this op for this BE ? */
1365 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1366 continue;
1367
1368 /* only allow hw_params() if no connected FEs are running */
1369 if (!snd_soc_dpcm_can_be_params(fe, be, stream))
1370 continue;
1371
1372 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
1373 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1374 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE))
1375 continue;
1376
1377 dev_dbg(be->dev, "dpcm: hw_params BE %s\n",
1378 dpcm_params->fe->dai_link->name);
1379
1380 /* copy params for each dpcm_params */
1381 memcpy(&dpcm_params->hw_params, &fe->dpcm[stream].hw_params,
1382 sizeof(struct snd_pcm_hw_params));
1383
1384 /* perform any hw_params fixups */
1385 if (be->dai_link->be_hw_params_fixup) {
1386 ret = be->dai_link->be_hw_params_fixup(be,
1387 &dpcm_params->hw_params);
1388 if (ret < 0) {
1389 dev_err(be->dev,
1390 "dpcm: hw_params BE fixup failed %d\n",
1391 ret);
1392 goto unwind;
1393 }
1394 }
1395
1396 ret = soc_pcm_hw_params(be_substream, &dpcm_params->hw_params);
1397 if (ret < 0) {
1398 dev_err(dpcm_params->be->dev, "dpcm: hw_params BE failed %d\n", ret);
1399 goto unwind;
1400 }
1401
1402 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
1403 }
1404 return 0;
1405
1406unwind:
1407 /* disable any enabled and non active backends */
1408 list_for_each_entry_continue_reverse(dpcm_params, &fe->dpcm[stream].be_clients, list_be) {
1409 struct snd_soc_pcm_runtime *be = dpcm_params->be;
1410 struct snd_pcm_substream *be_substream =
1411 snd_soc_dpcm_get_substream(be, stream);
1412
1413 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1414 continue;
1415
1416 /* only allow hw_free() if no connected FEs are running */
1417 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1418 continue;
1419
1420 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
1421 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1422 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
1423 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
1424 continue;
1425
1426 soc_pcm_hw_free(be_substream);
1427 }
1428
1429 return ret;
1430}
1431
1432int soc_dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
1433 struct snd_pcm_hw_params *params)
1434{
1435 struct snd_soc_pcm_runtime *fe = substream->private_data;
1436 int ret, stream = substream->stream;
1437
1438 mutex_lock(&fe->card->dpcm_mutex);
1439 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
1440
1441 memcpy(&fe->dpcm[substream->stream].hw_params, params,
1442 sizeof(struct snd_pcm_hw_params));
Liam Girdwood748da442013-05-21 10:26:42 +01001443 ret = dpcm_be_dai_hw_params(fe, substream->stream);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001444 if (ret < 0) {
1445 dev_err(fe->dev,"dpcm: hw_params failed for some BEs %d\n", ret);
1446 goto out;
1447 }
1448
1449 dev_dbg(fe->dev, "dpcm: hw_params FE %s rate %d chan %x fmt %d\n",
1450 fe->dai_link->name, params_rate(params), params_channels(params),
1451 params_format(params));
1452
1453 /* call hw_params on the frontend */
1454 ret = soc_pcm_hw_params(substream, params);
1455 if (ret < 0) {
1456 dev_err(fe->dev,"dpcm: hw_params FE failed %d\n", ret);
Liam Girdwood748da442013-05-21 10:26:42 +01001457 dpcm_be_dai_hw_free(fe, stream);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001458 } else
1459 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
1460
1461out:
1462 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
1463 mutex_unlock(&fe->card->dpcm_mutex);
1464 return ret;
1465}
1466
1467static int dpcm_do_trigger(struct snd_soc_dpcm_params *dpcm_params,
1468 struct snd_pcm_substream *substream, int cmd)
1469{
1470 int ret;
1471
1472 dev_dbg(dpcm_params->be->dev, "dpcm: trigger BE %s cmd %d\n",
1473 dpcm_params->fe->dai_link->name, cmd);
1474
1475 ret = soc_pcm_trigger(substream, cmd);
1476 if (ret < 0)
1477 dev_err(dpcm_params->be->dev,"dpcm: trigger BE failed %d\n", ret);
1478
1479 return ret;
1480}
1481
Liam Girdwood748da442013-05-21 10:26:42 +01001482int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, int cmd)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001483{
1484 struct snd_soc_dpcm_params *dpcm_params;
1485 int ret = 0;
1486
Steve Mucklef132c6c2012-06-06 18:30:57 -07001487
1488 list_for_each_entry(dpcm_params, &fe->dpcm[stream].be_clients, list_be) {
1489
1490 struct snd_soc_pcm_runtime *be = dpcm_params->be;
1491 struct snd_pcm_substream *be_substream =
1492 snd_soc_dpcm_get_substream(be, stream);
1493
1494 /* is this op for this BE ? */
1495 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1496 continue;
1497
1498 switch (cmd) {
1499 case SNDRV_PCM_TRIGGER_START:
1500 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
1501 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
1502 continue;
1503
1504 ret = dpcm_do_trigger(dpcm_params, be_substream, cmd);
1505 if (ret)
1506 return ret;
1507
1508 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
1509 break;
1510 case SNDRV_PCM_TRIGGER_RESUME:
1511 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
1512 continue;
1513
1514 ret = dpcm_do_trigger(dpcm_params, be_substream, cmd);
1515 if (ret)
1516 return ret;
1517
1518 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
1519 break;
1520 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1521 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
1522 continue;
1523
1524 ret = dpcm_do_trigger(dpcm_params, be_substream, cmd);
1525 if (ret)
1526 return ret;
1527
1528 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
1529 break;
1530 case SNDRV_PCM_TRIGGER_STOP:
1531 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
1532 continue;
1533
1534 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1535 continue;
1536
1537 ret = dpcm_do_trigger(dpcm_params, be_substream, cmd);
1538 if (ret)
1539 return ret;
1540
1541 be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
1542 break;
1543 case SNDRV_PCM_TRIGGER_SUSPEND:
1544 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)
1545 continue;
1546
1547 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1548 continue;
1549
1550 ret = dpcm_do_trigger(dpcm_params, be_substream, cmd);
1551 if (ret)
1552 return ret;
1553
1554 be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND;
1555 break;
1556 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
1557 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
1558 continue;
1559
1560 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1561 continue;
1562
1563 ret = dpcm_do_trigger(dpcm_params, be_substream, cmd);
1564 if (ret)
1565 return ret;
1566
1567 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
1568 break;
1569 }
1570 }
1571
1572 return ret;
1573}
Liam Girdwood748da442013-05-21 10:26:42 +01001574EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001575
1576int soc_dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
1577{
1578 struct snd_soc_pcm_runtime *fe = substream->private_data;
1579 int stream = substream->stream, ret;
1580 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
1581
1582 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
1583
1584 switch (trigger) {
1585 case SND_SOC_DPCM_TRIGGER_PRE:
1586 /* call trigger on the frontend before the backend. */
1587
1588 dev_dbg(fe->dev, "dpcm: pre trigger FE %s cmd %d\n",
1589 fe->dai_link->name, cmd);
1590
1591 ret = soc_pcm_trigger(substream, cmd);
1592 if (ret < 0) {
1593 dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret);
1594 goto out;
1595 }
1596
Liam Girdwood748da442013-05-21 10:26:42 +01001597 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001598 break;
1599 case SND_SOC_DPCM_TRIGGER_POST:
1600 /* call trigger on the frontend after the backend. */
1601
Liam Girdwood748da442013-05-21 10:26:42 +01001602 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001603 if (ret < 0) {
1604 dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret);
1605 goto out;
1606 }
1607
1608 dev_dbg(fe->dev, "dpcm: post trigger FE %s cmd %d\n",
1609 fe->dai_link->name, cmd);
1610
1611 ret = soc_pcm_trigger(substream, cmd);
1612 break;
1613 case SND_SOC_DPCM_TRIGGER_BESPOKE:
1614 /* bespoke trigger() - handles both FE and BEs */
1615
1616 dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd %d\n",
1617 fe->dai_link->name, cmd);
1618
1619 ret = soc_pcm_bespoke_trigger(substream, cmd);
1620 if (ret < 0) {
1621 dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret);
1622 goto out;
1623 }
1624 break;
1625 default:
1626 dev_err(fe->dev, "dpcm: invalid trigger cmd %d for %s\n", cmd,
1627 fe->dai_link->name);
1628 ret = -EINVAL;
1629 goto out;
1630 }
1631
1632 switch (cmd) {
1633 case SNDRV_PCM_TRIGGER_START:
1634 case SNDRV_PCM_TRIGGER_RESUME:
1635 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1636 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
1637 break;
1638 case SNDRV_PCM_TRIGGER_STOP:
1639 case SNDRV_PCM_TRIGGER_SUSPEND:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001640 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
1641 break;
Banajit Goswami17857112013-02-14 18:24:08 -08001642 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
1643 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
1644 break;
Steve Mucklef132c6c2012-06-06 18:30:57 -07001645 }
1646
1647out:
1648 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
1649 return ret;
1650}
1651
Liam Girdwood748da442013-05-21 10:26:42 +01001652int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001653{
1654 struct snd_soc_dpcm_params *dpcm_params;
1655 int ret = 0;
1656
1657 list_for_each_entry(dpcm_params, &fe->dpcm[stream].be_clients, list_be) {
1658
1659 struct snd_soc_pcm_runtime *be = dpcm_params->be;
1660 struct snd_pcm_substream *be_substream =
1661 snd_soc_dpcm_get_substream(be, stream);
1662
1663 /* is this op for this BE ? */
1664 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1665 continue;
1666
1667 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1668 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
1669 continue;
1670
1671 dev_dbg(be->dev, "dpcm: prepare BE %s\n",
1672 dpcm_params->fe->dai_link->name);
1673
1674 ret = soc_pcm_prepare(be_substream);
1675 if (ret < 0) {
1676 dev_err(be->dev, "dpcm: backend prepare failed %d\n",
1677 ret);
1678 break;
1679 }
1680
1681 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
1682 }
1683 return ret;
1684}
1685
1686int soc_dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
1687{
1688 struct snd_soc_pcm_runtime *fe = substream->private_data;
1689 int stream = substream->stream, ret = 0;
1690
1691 mutex_lock(&fe->card->dpcm_mutex);
1692
1693 dev_dbg(fe->dev, "dpcm: prepare FE %s\n", fe->dai_link->name);
1694
1695 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
1696
1697 /* there is no point preparing this FE if there are no BEs */
1698 if (list_empty(&fe->dpcm[stream].be_clients)) {
1699 dev_err(fe->dev, "dpcm: no backend DAIs enabled for %s\n",
1700 fe->dai_link->name);
1701 ret = -EINVAL;
1702 goto out;
1703 }
1704
Liam Girdwood748da442013-05-21 10:26:42 +01001705 ret = dpcm_be_dai_prepare(fe, substream->stream);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001706 if (ret < 0)
1707 goto out;
1708
1709 /* call prepare on the frontend */
Liam Girdwood748da442013-05-21 10:26:42 +01001710 if (!fe->fe_compr) {
1711 ret = soc_pcm_prepare(substream);
1712 if (ret < 0) {
1713 dev_err(fe->dev,"ASoC: prepare FE %s failed\n",
1714 fe->dai_link->name);
1715 goto out;
1716 }
1717 }
1718
Steve Mucklef132c6c2012-06-06 18:30:57 -07001719 ret = soc_pcm_prepare(substream);
1720 if (ret < 0) {
1721 dev_err(fe->dev,"dpcm: prepare FE %s failed\n", fe->dai_link->name);
1722 goto out;
1723 }
1724
1725 /* run the stream event for each BE */
1726 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
Eric Laurentdb88f282013-07-15 10:00:45 -07001727 dpcm_dapm_stream_event(fe, stream,
Steve Mucklef132c6c2012-06-06 18:30:57 -07001728 fe->cpu_dai->driver->playback.stream_name,
1729 SND_SOC_DAPM_STREAM_START);
1730 else
Eric Laurentdb88f282013-07-15 10:00:45 -07001731 dpcm_dapm_stream_event(fe, stream,
Steve Mucklef132c6c2012-06-06 18:30:57 -07001732 fe->cpu_dai->driver->capture.stream_name,
1733 SND_SOC_DAPM_STREAM_START);
1734
1735 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
1736
1737out:
1738 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
1739 mutex_unlock(&fe->card->dpcm_mutex);
1740 return ret;
1741}
1742
Liam Girdwood748da442013-05-21 10:26:42 +01001743int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001744{
1745 struct snd_soc_dpcm_params *dpcm_params;
1746
1747 /* only hw_params backends that are either sinks or sources
1748 * to this frontend DAI */
1749 list_for_each_entry(dpcm_params, &fe->dpcm[stream].be_clients, list_be) {
1750
1751 struct snd_soc_pcm_runtime *be = dpcm_params->be;
1752 struct snd_pcm_substream *be_substream =
1753 snd_soc_dpcm_get_substream(be, stream);
1754
1755 /* is this op for this BE ? */
1756 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1757 continue;
1758
1759 /* only free hw when no longer used - check all FEs */
1760 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1761 continue;
1762
1763 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1764 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
1765 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Phani Kumar Uppalapatidb4416e2012-10-25 13:21:15 -07001766 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
Laxminath Kasam09e7ab62013-04-03 14:03:17 +05301767 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
1768 !((be->dpcm[stream].state == SND_SOC_DPCM_STATE_START) &&
1769 ((fe->dpcm[stream].state != SND_SOC_DPCM_STATE_START) &&
1770 (fe->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
1771 (fe->dpcm[stream].state !=
1772 SND_SOC_DPCM_STATE_SUSPEND))))
Steve Mucklef132c6c2012-06-06 18:30:57 -07001773 continue;
1774
1775 dev_dbg(be->dev, "dpcm: hw_free BE %s\n",
1776 dpcm_params->fe->dai_link->name);
1777
1778 soc_pcm_hw_free(be_substream);
1779
1780 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1781 }
1782
1783 return 0;
1784}
1785
1786int soc_dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
1787{
1788 struct snd_soc_pcm_runtime *fe = substream->private_data;
1789 int err, stream = substream->stream;
1790
1791 mutex_lock(&fe->card->dpcm_mutex);
1792 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
1793
1794 dev_dbg(fe->dev, "dpcm: hw_free FE %s\n", fe->dai_link->name);
1795
1796 /* call hw_free on the frontend */
1797 err = soc_pcm_hw_free(substream);
1798 if (err < 0)
1799 dev_err(fe->dev,"dpcm: hw_free FE %s failed\n", fe->dai_link->name);
1800
1801 /* only hw_params backends that are either sinks or sources
1802 * to this frontend DAI */
Liam Girdwood748da442013-05-21 10:26:42 +01001803 err = dpcm_be_dai_hw_free(fe, stream);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001804
1805 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1806 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
1807
1808 mutex_unlock(&fe->card->dpcm_mutex);
1809 return 0;
1810}
1811
1812static int soc_pcm_ioctl(struct snd_pcm_substream *substream,
1813 unsigned int cmd, void *arg)
1814{
1815 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1816 struct snd_soc_platform *platform = rtd->platform;
1817
1818 if (platform->driver->ops->ioctl)
1819 return platform->driver->ops->ioctl(substream, cmd, arg);
1820 return snd_pcm_lib_ioctl(substream, cmd, arg);
1821}
1822
1823static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
1824{
1825 struct snd_pcm_substream *substream = snd_soc_dpcm_get_substream(fe, stream);
1826 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
1827 int err;
1828
1829 dev_dbg(fe->dev, "runtime %s close on FE %s\n",
1830 stream ? "capture" : "playback", fe->dai_link->name);
1831
1832 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
1833 /* call bespoke trigger - FE takes care of all BE triggers */
1834 dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd stop\n",
1835 fe->dai_link->name);
1836
1837 err = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
1838 if (err < 0)
1839 dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err);
1840 } else {
1841 dev_dbg(fe->dev, "dpcm: trigger FE %s cmd stop\n",
1842 fe->dai_link->name);
1843
Liam Girdwood748da442013-05-21 10:26:42 +01001844 err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001845 if (err < 0)
1846 dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err);
1847 }
1848
Liam Girdwood748da442013-05-21 10:26:42 +01001849 err = dpcm_be_dai_hw_free(fe, stream);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001850 if (err < 0)
1851 dev_err(fe->dev,"dpcm: hw_free FE failed %d\n", err);
1852
Liam Girdwood748da442013-05-21 10:26:42 +01001853 err = dpcm_be_dai_shutdown(fe, stream);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001854 if (err < 0)
1855 dev_err(fe->dev,"dpcm: shutdown FE failed %d\n", err);
1856
1857 /* run the stream event for each BE */
1858 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
Eric Laurentdb88f282013-07-15 10:00:45 -07001859 dpcm_dapm_stream_event(fe, stream,
Steve Mucklef132c6c2012-06-06 18:30:57 -07001860 fe->cpu_dai->driver->playback.stream_name,
1861 SND_SOC_DAPM_STREAM_NOP);
1862 else
Eric Laurentdb88f282013-07-15 10:00:45 -07001863 dpcm_dapm_stream_event(fe, stream,
Steve Mucklef132c6c2012-06-06 18:30:57 -07001864 fe->cpu_dai->driver->capture.stream_name,
1865 SND_SOC_DAPM_STREAM_NOP);
1866
1867 return 0;
1868}
1869
1870static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
1871{
1872 struct snd_pcm_substream *substream = snd_soc_dpcm_get_substream(fe, stream);
1873 struct snd_soc_dpcm_params *dpcm_params;
1874 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
1875 int ret;
1876
1877 dev_dbg(fe->dev, "runtime %s open on FE %s\n",
1878 stream ? "capture" : "playback", fe->dai_link->name);
1879
1880 /* Only start the BE if the FE is ready */
1881 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
1882 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE)
1883 return -EINVAL;
1884
1885 /* startup must always be called for new BEs */
Liam Girdwood748da442013-05-21 10:26:42 +01001886 ret = dpcm_be_dai_startup(fe, stream);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001887 if (ret < 0) {
1888 goto disconnect;
1889 return ret;
1890 }
1891
1892 /* keep going if FE state is > open */
1893 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN)
1894 return 0;
1895
Liam Girdwood748da442013-05-21 10:26:42 +01001896 ret = dpcm_be_dai_hw_params(fe, stream);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001897 if (ret < 0) {
1898 goto close;
1899 return ret;
1900 }
1901
1902 /* keep going if FE state is > hw_params */
1903 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS)
1904 return 0;
1905
1906
Liam Girdwood748da442013-05-21 10:26:42 +01001907 ret = dpcm_be_dai_prepare(fe, stream);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001908 if (ret < 0) {
1909 goto hw_free;
1910 return ret;
1911 }
1912
1913 /* run the stream event for each BE */
1914 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
Eric Laurentdb88f282013-07-15 10:00:45 -07001915 dpcm_dapm_stream_event(fe, stream,
Steve Mucklef132c6c2012-06-06 18:30:57 -07001916 fe->cpu_dai->driver->playback.stream_name,
1917 SND_SOC_DAPM_STREAM_NOP);
1918 else
Eric Laurentdb88f282013-07-15 10:00:45 -07001919 dpcm_dapm_stream_event(fe, stream,
Steve Mucklef132c6c2012-06-06 18:30:57 -07001920 fe->cpu_dai->driver->capture.stream_name,
1921 SND_SOC_DAPM_STREAM_NOP);
1922
1923 /* keep going if FE state is > prepare */
1924 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE ||
1925 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP)
1926 return 0;
1927
1928 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
1929 /* call trigger on the frontend - FE takes care of all BE triggers */
1930 dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd start\n",
1931 fe->dai_link->name);
1932
1933 ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
1934 if (ret < 0) {
1935 dev_err(fe->dev,"dpcm: bespoke trigger FE failed %d\n", ret);
1936 goto hw_free;
1937 }
1938 } else {
1939 dev_dbg(fe->dev, "dpcm: trigger FE %s cmd start\n",
1940 fe->dai_link->name);
1941
Liam Girdwood748da442013-05-21 10:26:42 +01001942 ret = dpcm_be_dai_trigger(fe, stream,
Steve Mucklef132c6c2012-06-06 18:30:57 -07001943 SNDRV_PCM_TRIGGER_START);
1944 if (ret < 0) {
1945 dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret);
1946 goto hw_free;
1947 }
1948 }
1949
1950 return 0;
1951
1952hw_free:
Liam Girdwood748da442013-05-21 10:26:42 +01001953 dpcm_be_dai_hw_free(fe, stream);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001954close:
Liam Girdwood748da442013-05-21 10:26:42 +01001955 dpcm_be_dai_shutdown(fe, stream);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001956disconnect:
1957 /* disconnect any non started BEs */
1958 list_for_each_entry(dpcm_params, &fe->dpcm[stream].be_clients, list_be) {
1959 struct snd_soc_pcm_runtime *be = dpcm_params->be;
1960 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
1961 dpcm_params->state = SND_SOC_DPCM_LINK_STATE_FREE;
1962 }
1963
1964 return ret;
1965}
1966
1967static int dpcm_run_new_update(struct snd_soc_pcm_runtime *fe, int stream)
1968{
1969 int ret;
1970
1971 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1972 ret = dpcm_run_update_startup(fe, stream);
1973 if (ret < 0)
1974 dev_err(fe->dev, "failed to startup some BEs\n");
1975 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
1976
1977 return ret;
1978}
1979
1980static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream)
1981{
1982 int ret;
1983
1984 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1985 ret = dpcm_run_update_shutdown(fe, stream);
1986 if (ret < 0)
1987 dev_err(fe->dev, "failed to shutdown some BEs\n");
1988 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
1989
1990 return ret;
1991}
1992
1993/* called when any mixer updates change FE -> BE the stream */
1994int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *widget)
1995{
1996 struct snd_soc_card *card;
1997 int i, ret = 0, old, new, paths;
1998
1999 if (widget->codec)
2000 card = widget->codec->card;
2001 else if (widget->platform)
2002 card = widget->platform->card;
2003 else
2004 return -EINVAL;
2005
2006 mutex_lock(&card->dpcm_mutex);
2007
2008 for (i = 0; i < card->num_rtd; i++) {
2009 struct snd_soc_dapm_widget_list *list;
2010 struct snd_soc_pcm_runtime *fe = &card->rtd[i];
2011
2012 /* make sure link is FE */
2013 if (!fe->dai_link->dynamic)
2014 continue;
2015
2016 /* only check active links */
2017 if (!fe->cpu_dai->active)
2018 continue;
2019
2020 /* DAPM sync will call this to update DSP paths */
2021 dev_dbg(fe->dev, "DPCM runtime update for FE %s\n", fe->dai_link->name);
2022
2023 /* skip if FE doesn't have playback capability */
2024 if (!fe->cpu_dai->driver->playback.channels_min)
2025 goto capture;
2026
Liam Girdwood748da442013-05-21 10:26:42 +01002027 paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002028 if (paths < 0) {
2029 dev_warn(fe->dev, "%s no valid %s route from source to sink\n",
2030 fe->dai_link->name, "playback");
2031 ret = paths;
2032 goto out;
2033 }
2034
2035 /* update any new playback paths */
2036 new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 1);
2037 if (new) {
2038 dpcm_run_new_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
Liam Girdwood748da442013-05-21 10:26:42 +01002039 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
2040 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002041 }
2042
2043 /* update any old playback paths */
2044 old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 0);
2045 if (old) {
2046 dpcm_run_old_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
Liam Girdwood748da442013-05-21 10:26:42 +01002047 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
2048 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002049 }
2050
Liam Girdwood748da442013-05-21 10:26:42 +01002051 dpcm_path_put(&list);
Banajit Goswamic2b05992012-08-19 23:09:58 -07002052
Steve Mucklef132c6c2012-06-06 18:30:57 -07002053capture:
2054 /* skip if FE doesn't have capture capability */
2055 if (!fe->cpu_dai->driver->capture.channels_min)
2056 continue;
2057
Liam Girdwood748da442013-05-21 10:26:42 +01002058 paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002059 if (paths < 0) {
2060 dev_warn(fe->dev, "%s no valid %s route from source to sink\n",
2061 fe->dai_link->name, "capture");
2062 ret = paths;
2063 goto out;
2064 }
2065
2066 /* update any new capture paths */
2067 new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 1);
2068 if (new) {
2069 dpcm_run_new_update(fe, SNDRV_PCM_STREAM_CAPTURE);
Liam Girdwood748da442013-05-21 10:26:42 +01002070 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
2071 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002072 }
2073
2074 /* update any old capture paths */
2075 old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 0);
2076 if (old) {
2077 dpcm_run_old_update(fe, SNDRV_PCM_STREAM_CAPTURE);
Liam Girdwood748da442013-05-21 10:26:42 +01002078 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
2079 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002080 }
2081
Liam Girdwood748da442013-05-21 10:26:42 +01002082 dpcm_path_put(&list);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002083 }
2084
2085out:
2086 mutex_unlock(&card->dpcm_mutex);
2087 return ret;
2088}
2089
2090int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute)
2091{
2092 struct snd_soc_dpcm_params *dpcm_params;
2093
2094 list_for_each_entry(dpcm_params,
2095 &fe->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
2096
2097 struct snd_soc_pcm_runtime *be = dpcm_params->be;
2098 struct snd_soc_dai *dai = be->codec_dai;
2099 struct snd_soc_dai_driver *drv = dai->driver;
2100
2101 if (be->dai_link->ignore_suspend)
2102 continue;
2103
2104 dev_dbg(be->dev, "BE digital mute %s\n", be->dai_link->name);
2105
2106 if (drv->ops->digital_mute && dai->playback_active)
2107 drv->ops->digital_mute(dai, mute);
2108 }
2109
2110 return 0;
2111}
2112
2113int soc_dpcm_be_cpu_dai_suspend(struct snd_soc_pcm_runtime *fe)
2114{
2115 struct snd_soc_dpcm_params *dpcm_params;
2116
2117 /* suspend for playback */
2118 list_for_each_entry(dpcm_params,
2119 &fe->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
2120
2121 struct snd_soc_pcm_runtime *be = dpcm_params->be;
2122 struct snd_soc_dai *dai = be->cpu_dai;
2123 struct snd_soc_dai_driver *drv = dai->driver;
2124
2125 if (be->dai_link->ignore_suspend)
2126 continue;
2127
2128 dev_dbg(be->dev, "pm: BE CPU DAI playback suspend %s\n",
2129 be->dai_link->name);
2130
2131 if (drv->suspend && !drv->ac97_control)
2132 drv->suspend(dai);
2133 }
2134
2135 /* suspend for capture */
2136 list_for_each_entry(dpcm_params,
2137 &fe->dpcm[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) {
2138
2139 struct snd_soc_pcm_runtime *be = dpcm_params->be;
2140 struct snd_soc_dai *dai = be->cpu_dai;
2141 struct snd_soc_dai_driver *drv = dai->driver;
2142
2143 if (be->dai_link->ignore_suspend)
2144 continue;
2145
2146 dev_dbg(be->dev, "pm: BE CPU DAI capture suspend %s\n",
2147 be->dai_link->name);
2148
2149 if (drv->suspend && !drv->ac97_control)
2150 drv->suspend(dai);
2151 }
2152
2153 return 0;
2154}
2155
2156int soc_dpcm_be_ac97_cpu_dai_suspend(struct snd_soc_pcm_runtime *fe)
2157{
2158 struct snd_soc_dpcm_params *dpcm_params;
2159
2160 /* suspend for playback */
2161 list_for_each_entry(dpcm_params,
2162 &fe->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
2163
2164 struct snd_soc_pcm_runtime *be = dpcm_params->be;
2165 struct snd_soc_dai *dai = be->cpu_dai;
2166 struct snd_soc_dai_driver *drv = dai->driver;
2167
2168 if (be->dai_link->ignore_suspend)
2169 continue;
2170
2171 dev_dbg(be->dev, "pm: BE CPU DAI playback suspend %s\n",
2172 be->dai_link->name);
2173
2174 if (drv->suspend && drv->ac97_control)
2175 drv->suspend(dai);
2176 }
2177
2178 /* suspend for capture */
2179 list_for_each_entry(dpcm_params,
2180 &fe->dpcm[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) {
2181
2182 struct snd_soc_pcm_runtime *be = dpcm_params->be;
2183 struct snd_soc_dai *dai = be->cpu_dai;
2184 struct snd_soc_dai_driver *drv = dai->driver;
2185
2186 if (be->dai_link->ignore_suspend)
2187 continue;
2188
2189 dev_dbg(be->dev, "pm: BE CPU DAI capture suspend %s\n",
2190 be->dai_link->name);
2191
2192 if (drv->suspend && drv->ac97_control)
2193 drv->suspend(dai);
2194 }
2195
2196 return 0;
2197}
2198
2199int soc_dpcm_be_platform_suspend(struct snd_soc_pcm_runtime *fe)
2200{
2201 struct snd_soc_dpcm_params *dpcm_params;
2202
2203 /* suspend for playback */
2204 list_for_each_entry(dpcm_params,
2205 &fe->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
2206
2207 struct snd_soc_pcm_runtime *be = dpcm_params->be;
2208 struct snd_soc_platform *platform = be->platform;
2209 struct snd_soc_platform_driver *drv = platform->driver;
2210 struct snd_soc_dai *dai = be->cpu_dai;
2211
2212 if (be->dai_link->ignore_suspend)
2213 continue;
2214
2215 dev_dbg(be->dev, "pm: BE platform playback suspend %s\n",
2216 be->dai_link->name);
2217
2218 if (drv->suspend && !platform->suspended) {
2219 drv->suspend(dai);
2220 platform->suspended = 1;
2221 }
2222 }
2223
2224 /* suspend for capture */
2225 list_for_each_entry(dpcm_params,
2226 &fe->dpcm[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) {
2227
2228 struct snd_soc_pcm_runtime *be = dpcm_params->be;
2229 struct snd_soc_platform *platform = be->platform;
2230 struct snd_soc_platform_driver *drv = platform->driver;
2231 struct snd_soc_dai *dai = be->cpu_dai;
2232
2233 if (be->dai_link->ignore_suspend)
2234 continue;
2235
2236 dev_dbg(be->dev, "pm: BE platform capture suspend %s\n",
2237 be->dai_link->name);
2238
2239 if (drv->suspend && !platform->suspended) {
2240 drv->suspend(dai);
2241 platform->suspended = 1;
2242 }
2243 }
2244 return 0;
2245}
2246
2247int soc_dpcm_fe_suspend(struct snd_soc_pcm_runtime *fe)
2248{
2249 struct snd_soc_dai *dai = fe->cpu_dai;
2250 struct snd_soc_dai_driver *dai_drv = dai->driver;
2251 struct snd_soc_platform *platform = fe->platform;
2252 struct snd_soc_platform_driver *plat_drv = platform->driver;
2253
2254 if (dai_drv->suspend && !dai_drv->ac97_control)
2255 dai_drv->suspend(dai);
2256
2257 if (plat_drv->suspend && !platform->suspended) {
2258 plat_drv->suspend(dai);
2259 platform->suspended = 1;
2260 }
2261
2262 soc_dpcm_be_cpu_dai_suspend(fe);
2263 soc_dpcm_be_platform_suspend(fe);
2264
2265 return 0;
2266}
2267
2268int soc_dpcm_be_cpu_dai_resume(struct snd_soc_pcm_runtime *fe)
2269{
2270 struct snd_soc_dpcm_params *dpcm_params;
2271
2272 /* resume for playback */
2273 list_for_each_entry(dpcm_params,
2274 &fe->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
2275
2276 struct snd_soc_pcm_runtime *be = dpcm_params->be;
2277 struct snd_soc_dai *dai = be->cpu_dai;
2278 struct snd_soc_dai_driver *drv = dai->driver;
2279
2280 if (be->dai_link->ignore_suspend)
2281 continue;
2282
2283 dev_dbg(be->dev, "pm: BE CPU DAI playback resume %s\n",
2284 be->dai_link->name);
2285
2286 if (drv->resume && !drv->ac97_control)
2287 drv->resume(dai);
2288 }
2289
2290 /* suspend for capture */
2291 list_for_each_entry(dpcm_params,
2292 &fe->dpcm[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) {
2293
2294 struct snd_soc_pcm_runtime *be = dpcm_params->be;
2295 struct snd_soc_dai *dai = be->cpu_dai;
2296 struct snd_soc_dai_driver *drv = dai->driver;
2297
2298 if (be->dai_link->ignore_suspend)
2299 continue;
2300
2301 dev_dbg(be->dev, "pm: BE CPU DAI capture resume %s\n",
2302 be->dai_link->name);
2303
2304 if (drv->resume && !drv->ac97_control)
2305 drv->resume(dai);
2306 }
2307
2308 return 0;
2309}
2310
2311int soc_dpcm_be_ac97_cpu_dai_resume(struct snd_soc_pcm_runtime *fe)
2312{
2313 struct snd_soc_dpcm_params *dpcm_params;
2314
2315 /* resume for playback */
2316 list_for_each_entry(dpcm_params,
2317 &fe->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
2318
2319 struct snd_soc_pcm_runtime *be = dpcm_params->be;
2320 struct snd_soc_dai *dai = be->cpu_dai;
2321 struct snd_soc_dai_driver *drv = dai->driver;
2322
2323 if (be->dai_link->ignore_suspend)
2324 continue;
2325
2326 dev_dbg(be->dev, "pm: BE CPU DAI playback resume %s\n",
2327 be->dai_link->name);
2328
2329 if (drv->resume && drv->ac97_control)
2330 drv->resume(dai);
2331 }
2332
2333 /* suspend for capture */
2334 list_for_each_entry(dpcm_params,
2335 &fe->dpcm[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) {
2336
2337 struct snd_soc_pcm_runtime *be = dpcm_params->be;
2338 struct snd_soc_dai *dai = be->cpu_dai;
2339 struct snd_soc_dai_driver *drv = dai->driver;
2340
2341 if (be->dai_link->ignore_suspend)
2342 continue;
2343
2344 dev_dbg(be->dev, "pm: BE CPU DAI capture resume %s\n",
2345 be->dai_link->name);
2346
2347 if (drv->resume && drv->ac97_control)
2348 drv->resume(dai);
2349 }
2350
2351 return 0;
2352}
2353
2354int soc_dpcm_be_platform_resume(struct snd_soc_pcm_runtime *fe)
2355{
2356 struct snd_soc_dpcm_params *dpcm_params;
2357
2358 /* resume for playback */
2359 list_for_each_entry(dpcm_params,
2360 &fe->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) {
2361
2362 struct snd_soc_pcm_runtime *be = dpcm_params->be;
2363 struct snd_soc_platform *platform = be->platform;
2364 struct snd_soc_platform_driver *drv = platform->driver;
2365 struct snd_soc_dai *dai = be->cpu_dai;
2366
2367 if (be->dai_link->ignore_suspend)
2368 continue;
2369
2370 dev_dbg(be->dev, "pm: BE platform playback resume %s\n",
2371 be->dai_link->name);
2372
2373 if (drv->resume && platform->suspended) {
2374 drv->resume(dai);
2375 platform->suspended = 0;
2376 }
2377 }
2378
2379 /* resume for capture */
2380 list_for_each_entry(dpcm_params,
2381 &fe->dpcm[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) {
2382
2383 struct snd_soc_pcm_runtime *be = dpcm_params->be;
2384 struct snd_soc_platform *platform = be->platform;
2385 struct snd_soc_platform_driver *drv = platform->driver;
2386 struct snd_soc_dai *dai = be->cpu_dai;
2387
2388 if (be->dai_link->ignore_suspend)
2389 continue;
2390
2391 dev_dbg(be->dev, "pm: BE platform capture resume %s\n",
2392 be->dai_link->name);
2393
2394 if (drv->resume && platform->suspended) {
2395 drv->resume(dai);
2396 platform->suspended = 0;
2397 }
2398 }
2399
2400 return 0;
2401}
2402
2403int soc_dpcm_fe_resume(struct snd_soc_pcm_runtime *fe)
2404{
2405 struct snd_soc_dai *dai = fe->cpu_dai;
2406 struct snd_soc_dai_driver *dai_drv = dai->driver;
2407 struct snd_soc_platform *platform = fe->platform;
2408 struct snd_soc_platform_driver *plat_drv = platform->driver;
2409
2410 soc_dpcm_be_cpu_dai_resume(fe);
2411 soc_dpcm_be_platform_resume(fe);
2412
2413 if (dai_drv->resume && !dai_drv->ac97_control)
2414 dai_drv->resume(dai);
2415
2416 if (plat_drv->resume && platform->suspended) {
2417 plat_drv->resume(dai);
2418 platform->suspended = 0;
2419 }
2420
2421 return 0;
2422}
2423
2424/* called when opening FE stream */
2425int soc_dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
2426{
2427 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
2428 struct snd_soc_dpcm_params *dpcm_params;
2429 struct snd_soc_dapm_widget_list *list;
2430 int ret;
2431 int stream = fe_substream->stream;
2432
sangwooed404e62013-08-15 17:10:33 +09002433 mutex_lock(&fe->card->dpcm_mutex);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002434 fe->dpcm[stream].runtime = fe_substream->runtime;
2435
Liam Girdwood748da442013-05-21 10:26:42 +01002436 if (dpcm_path_get(fe, stream, &list) <= 0) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002437 dev_warn(fe->dev, "asoc: %s no valid %s route from source to sink\n",
2438 fe->dai_link->name, stream ? "capture" : "playback");
sangwooed404e62013-08-15 17:10:33 +09002439 mutex_unlock(&fe->card->dpcm_mutex);
2440 return -EINVAL;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002441 }
2442
2443 /* calculate valid and active FE <-> BE dpcm_paramss */
2444 dpcm_process_paths(fe, stream, &list, 1);
2445
2446 ret = soc_dpcm_fe_dai_startup(fe_substream);
2447 if (ret < 0) {
2448 /* clean up all links */
2449 list_for_each_entry(dpcm_params, &fe->dpcm[stream].be_clients, list_be)
2450 dpcm_params->state = SND_SOC_DPCM_LINK_STATE_FREE;
2451
Liam Girdwood748da442013-05-21 10:26:42 +01002452 dpcm_be_disconnect(fe, stream);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002453 fe->dpcm[stream].runtime = NULL;
2454 }
2455
Liam Girdwood748da442013-05-21 10:26:42 +01002456 dpcm_clear_pending_state(fe, stream);
2457 dpcm_path_put(&list);
sangwooed404e62013-08-15 17:10:33 +09002458 mutex_unlock(&fe->card->dpcm_mutex);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002459 return ret;
2460}
2461
2462/* called when closing FE stream */
2463int soc_dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
2464{
2465 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
2466 struct snd_soc_dpcm_params *dpcm_params;
2467 int stream = fe_substream->stream, ret;
2468
sangwooed404e62013-08-15 17:10:33 +09002469 mutex_lock(&fe->card->dpcm_mutex);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002470 ret = soc_dpcm_fe_dai_shutdown(fe_substream);
2471
2472 /* mark FE's links ready to prune */
2473 list_for_each_entry(dpcm_params, &fe->dpcm[stream].be_clients, list_be)
2474 dpcm_params->state = SND_SOC_DPCM_LINK_STATE_FREE;
2475
Liam Girdwood748da442013-05-21 10:26:42 +01002476 dpcm_be_disconnect(fe, stream);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002477
2478 fe->dpcm[stream].runtime = NULL;
sangwooed404e62013-08-15 17:10:33 +09002479 mutex_unlock(&fe->card->dpcm_mutex);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002480 return ret;
2481}
2482
Liam Girdwoodddee6272011-06-09 14:45:53 +01002483/* create a new pcm */
2484int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
2485{
2486 struct snd_soc_codec *codec = rtd->codec;
2487 struct snd_soc_platform *platform = rtd->platform;
2488 struct snd_soc_dai *codec_dai = rtd->codec_dai;
2489 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002490 struct snd_pcm_substream *substream[2];
Liam Girdwoodddee6272011-06-09 14:45:53 +01002491 struct snd_pcm *pcm;
2492 char new_name[64];
2493 int ret = 0, playback = 0, capture = 0;
2494
Steve Mucklef132c6c2012-06-06 18:30:57 -07002495 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
2496 if (cpu_dai->driver->playback.channels_min)
2497 playback = 1;
2498 if (cpu_dai->driver->capture.channels_min)
2499 capture = 1;
2500 } else {
2501 if (codec_dai->driver->playback.channels_min)
2502 playback = 1;
2503 if (codec_dai->driver->capture.channels_min)
2504 capture = 1;
2505 }
Sangsu Parka5002312012-01-02 17:15:10 +09002506
Steve Mucklef132c6c2012-06-06 18:30:57 -07002507 /* create the PCM */
2508 if (rtd->dai_link->no_pcm) {
2509 snprintf(new_name, sizeof(new_name), "(%s)",
2510 rtd->dai_link->stream_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002511
Steve Mucklef132c6c2012-06-06 18:30:57 -07002512 ret = snd_pcm_new_soc_be(rtd->card->snd_card, new_name, num,
2513 playback, capture, &pcm);
2514 } else {
2515 if (rtd->dai_link->dynamic)
2516 snprintf(new_name, sizeof(new_name), "%s (*)",
2517 rtd->dai_link->stream_name);
2518 else
2519 snprintf(new_name, sizeof(new_name), "%s %s-%d",
2520 rtd->dai_link->stream_name, codec_dai->name, num);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002521
Steve Mucklef132c6c2012-06-06 18:30:57 -07002522 ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
2523 capture, &pcm);
2524 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01002525 if (ret < 0) {
2526 printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name);
2527 return ret;
2528 }
Steve Mucklef132c6c2012-06-06 18:30:57 -07002529 dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num, new_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002530
2531 rtd->pcm = pcm;
2532 pcm->private_data = rtd;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002533 INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
2534
2535 substream[SNDRV_PCM_STREAM_PLAYBACK] =
2536 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
2537 substream[SNDRV_PCM_STREAM_CAPTURE] =
2538 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
2539
2540 if (rtd->dai_link->no_pcm) {
2541 if (playback)
2542 substream[SNDRV_PCM_STREAM_PLAYBACK]->private_data = rtd;
2543 if (capture)
2544 substream[SNDRV_PCM_STREAM_CAPTURE]->private_data = rtd;
2545 goto out;
2546 }
2547
2548 /* setup any hostless PCMs - i.e. no host IO is performed */
2549 if (rtd->dai_link->no_host_mode) {
2550 if (substream[SNDRV_PCM_STREAM_PLAYBACK]) {
2551 substream[SNDRV_PCM_STREAM_PLAYBACK]->hw_no_buffer = 1;
2552 snd_soc_set_runtime_hwparams(
2553 substream[SNDRV_PCM_STREAM_PLAYBACK],
2554 &no_host_hardware);
2555 }
2556 if (substream[SNDRV_PCM_STREAM_CAPTURE]) {
2557 substream[SNDRV_PCM_STREAM_CAPTURE]->hw_no_buffer = 1;
2558 snd_soc_set_runtime_hwparams(
2559 substream[SNDRV_PCM_STREAM_CAPTURE],
2560 &no_host_hardware);
2561 }
2562 }
2563
2564 /* ASoC PCM operations */
2565 if (rtd->dai_link->dynamic) {
2566 rtd->ops.open = soc_dpcm_fe_dai_open;
2567 rtd->ops.hw_params = soc_dpcm_fe_dai_hw_params;
2568 rtd->ops.prepare = soc_dpcm_fe_dai_prepare;
2569 rtd->ops.trigger = soc_dpcm_fe_dai_trigger;
2570 rtd->ops.hw_free = soc_dpcm_fe_dai_hw_free;
2571 rtd->ops.close = soc_dpcm_fe_dai_close;
2572 rtd->ops.pointer = soc_pcm_pointer;
2573 rtd->ops.ioctl = soc_pcm_ioctl;
2574 } else {
2575 rtd->ops.open = soc_pcm_open;
2576 rtd->ops.hw_params = soc_pcm_hw_params;
2577 rtd->ops.prepare = soc_pcm_prepare;
2578 rtd->ops.trigger = soc_pcm_trigger;
2579 rtd->ops.hw_free = soc_pcm_hw_free;
2580 rtd->ops.close = soc_pcm_close;
2581 rtd->ops.pointer = soc_pcm_pointer;
2582 rtd->ops.ioctl = soc_pcm_ioctl;
2583 }
2584
Liam Girdwoodddee6272011-06-09 14:45:53 +01002585 if (platform->driver->ops) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002586 rtd->ops.ack = platform->driver->ops->ack;
2587 rtd->ops.copy = platform->driver->ops->copy;
2588 rtd->ops.silence = platform->driver->ops->silence;
2589 rtd->ops.page = platform->driver->ops->page;
2590 rtd->ops.mmap = platform->driver->ops->mmap;
Santosh Mardie56cad02012-10-09 10:40:17 +05302591 rtd->ops.restart = platform->driver->ops->restart;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002592 }
2593
2594 if (playback)
Steve Mucklef132c6c2012-06-06 18:30:57 -07002595 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002596
2597 if (capture)
Steve Mucklef132c6c2012-06-06 18:30:57 -07002598 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002599
2600 if (platform->driver->pcm_new) {
2601 ret = platform->driver->pcm_new(rtd);
2602 if (ret < 0) {
2603 pr_err("asoc: platform pcm constructor failed\n");
2604 return ret;
2605 }
2606 }
2607
2608 pcm->private_free = platform->driver->pcm_free;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002609out:
Liam Girdwoodddee6272011-06-09 14:45:53 +01002610 printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name,
2611 cpu_dai->name);
2612 return ret;
2613}
Steve Mucklef132c6c2012-06-06 18:30:57 -07002614
2615#ifdef CONFIG_DEBUG_FS
2616static char *dpcm_state_string(enum snd_soc_dpcm_state state)
2617{
2618 switch (state) {
2619 case SND_SOC_DPCM_STATE_NEW:
2620 return "new";
2621 case SND_SOC_DPCM_STATE_OPEN:
2622 return "open";
2623 case SND_SOC_DPCM_STATE_HW_PARAMS:
2624 return "hw_params";
2625 case SND_SOC_DPCM_STATE_PREPARE:
2626 return "prepare";
2627 case SND_SOC_DPCM_STATE_START:
2628 return "start";
2629 case SND_SOC_DPCM_STATE_STOP:
2630 return "stop";
2631 case SND_SOC_DPCM_STATE_SUSPEND:
2632 return "suspend";
2633 case SND_SOC_DPCM_STATE_PAUSED:
2634 return "paused";
2635 case SND_SOC_DPCM_STATE_HW_FREE:
2636 return "hw_free";
2637 case SND_SOC_DPCM_STATE_CLOSE:
2638 return "close";
2639 }
2640
2641 return "unknown";
2642}
2643
2644static int soc_dpcm_state_open_file(struct inode *inode, struct file *file)
2645{
2646 file->private_data = inode->i_private;
2647 return 0;
2648}
2649
2650static ssize_t soc_dpcm_show_state(struct snd_soc_pcm_runtime *fe,
2651 int stream, char *buf, size_t size)
2652{
2653 struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params;
2654 struct snd_soc_dpcm_params *dpcm_params;
2655 ssize_t offset = 0;
2656
2657 /* FE state */
2658 offset += snprintf(buf + offset, size - offset,
2659 "[%s - %s]\n", fe->dai_link->name,
2660 stream ? "Capture" : "Playback");
2661
2662 offset += snprintf(buf + offset, size - offset, "State: %s\n",
2663 dpcm_state_string(fe->dpcm[stream].state));
2664
2665 if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
2666 (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
2667 offset += snprintf(buf + offset, size - offset,
2668 "Hardware Params: "
2669 "Format = %s, Channels = %d, Rate = %d\n",
2670 snd_pcm_format_name(params_format(params)),
2671 params_channels(params),
2672 params_rate(params));
2673
2674 /* BEs state */
2675 offset += snprintf(buf + offset, size - offset, "Backends:\n");
2676
2677 if (list_empty(&fe->dpcm[stream].be_clients)) {
2678 offset += snprintf(buf + offset, size - offset,
2679 " No active DSP links\n");
2680 goto out;
2681 }
2682
2683 list_for_each_entry(dpcm_params, &fe->dpcm[stream].be_clients, list_be) {
2684 struct snd_soc_pcm_runtime *be = dpcm_params->be;
2685
2686 offset += snprintf(buf + offset, size - offset,
2687 "- %s\n", be->dai_link->name);
2688
2689 offset += snprintf(buf + offset, size - offset,
2690 " State: %s\n",
2691 dpcm_state_string(fe->dpcm[stream].state));
2692
2693 if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
2694 (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
2695 offset += snprintf(buf + offset, size - offset,
2696 " Hardware Params: "
2697 "Format = %s, Channels = %d, Rate = %d\n",
2698 snd_pcm_format_name(params_format(params)),
2699 params_channels(params),
2700 params_rate(params));
2701 }
2702
2703out:
2704 return offset;
2705}
2706
2707static ssize_t soc_dpcm_state_read_file(struct file *file, char __user *user_buf,
2708 size_t count, loff_t *ppos)
2709{
2710 struct snd_soc_pcm_runtime *fe = file->private_data;
2711 ssize_t out_count = PAGE_SIZE, offset = 0, ret = 0;
2712 char *buf;
2713
2714 buf = kmalloc(out_count, GFP_KERNEL);
2715 if (!buf)
2716 return -ENOMEM;
2717
2718 if (fe->cpu_dai->driver->playback.channels_min)
2719 offset += soc_dpcm_show_state(fe, SNDRV_PCM_STREAM_PLAYBACK,
2720 buf + offset, out_count - offset);
2721
2722 if (fe->cpu_dai->driver->capture.channels_min)
2723 offset += soc_dpcm_show_state(fe, SNDRV_PCM_STREAM_CAPTURE,
2724 buf + offset, out_count - offset);
2725
2726 ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
2727
2728 kfree(buf);
2729
2730 return ret;
2731}
2732
2733static const struct file_operations soc_dpcm_state_fops = {
2734 .open = soc_dpcm_state_open_file,
2735 .read = soc_dpcm_state_read_file,
2736 .llseek = default_llseek,
2737};
2738
2739int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
2740{
2741 rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name,
2742 rtd->card->debugfs_card_root);
2743 if (!rtd->debugfs_dpcm_root) {
2744 dev_dbg(rtd->dev,
2745 "ASoC: Failed to create dpcm debugfs directory %s\n",
2746 rtd->dai_link->name);
2747 return -EINVAL;
2748 }
2749
2750 rtd->debugfs_dpcm_state = debugfs_create_file("state", 0644,
2751 rtd->debugfs_dpcm_root,
2752 rtd, &soc_dpcm_state_fops);
2753
2754 return 0;
2755}
2756#endif