blob: f098c8007cbe336a83f325a72613798012794253 [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>
Nicolin Chen988e8cc2013-11-04 14:57:31 +080022#include <linux/pinctrl/consumer.h>
Mark Brownd6652ef2011-12-03 20:14:31 +000023#include <linux/pm_runtime.h>
Liam Girdwoodddee6272011-06-09 14:45:53 +010024#include <linux/slab.h>
25#include <linux/workqueue.h>
Liam Girdwood01d75842012-04-25 12:12:49 +010026#include <linux/export.h>
Liam Girdwoodf86dcef2012-04-25 12:12:50 +010027#include <linux/debugfs.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>
Liam Girdwood01d75842012-04-25 12:12:49 +010032#include <sound/soc-dpcm.h>
Liam Girdwoodddee6272011-06-09 14:45:53 +010033#include <sound/initval.h>
34
Liam Girdwood01d75842012-04-25 12:12:49 +010035#define DPCM_MAX_BE_USERS 8
36
Lars-Peter Clausen90996f42013-05-14 11:05:30 +020037/**
Lars-Peter Clausen208a1582014-03-05 13:17:42 +010038 * snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay
39 * @rtd: The ASoC PCM runtime that should be checked.
40 *
41 * This function checks whether the power down delay should be ignored for a
42 * specific PCM runtime. Returns true if the delay is 0, if it the DAI link has
43 * been configured to ignore the delay, or if none of the components benefits
44 * from having the delay.
45 */
46bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
47{
48 bool ignore = true;
49
50 if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
51 return true;
52
53 if (rtd->cpu_dai->codec)
54 ignore &= rtd->cpu_dai->codec->ignore_pmdown_time;
55
56 ignore &= rtd->codec_dai->codec->ignore_pmdown_time;
57
58 return ignore;
59}
60
61/**
Lars-Peter Clausen90996f42013-05-14 11:05:30 +020062 * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
63 * @substream: the pcm substream
64 * @hw: the hardware parameters
65 *
66 * Sets the substream runtime hardware parameters.
67 */
68int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
69 const struct snd_pcm_hardware *hw)
70{
71 struct snd_pcm_runtime *runtime = substream->runtime;
72 runtime->hw.info = hw->info;
73 runtime->hw.formats = hw->formats;
74 runtime->hw.period_bytes_min = hw->period_bytes_min;
75 runtime->hw.period_bytes_max = hw->period_bytes_max;
76 runtime->hw.periods_min = hw->periods_min;
77 runtime->hw.periods_max = hw->periods_max;
78 runtime->hw.buffer_bytes_max = hw->buffer_bytes_max;
79 runtime->hw.fifo_size = hw->fifo_size;
80 return 0;
81}
82EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
83
Liam Girdwood01d75842012-04-25 12:12:49 +010084/* DPCM stream event, send event to FE and all active BEs. */
Liam Girdwood23607022014-01-17 17:03:55 +000085int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
Liam Girdwood01d75842012-04-25 12:12:49 +010086 int event)
87{
88 struct snd_soc_dpcm *dpcm;
89
90 list_for_each_entry(dpcm, &fe->dpcm[dir].be_clients, list_be) {
91
92 struct snd_soc_pcm_runtime *be = dpcm->be;
93
Liam Girdwood103d84a2012-11-19 14:39:15 +000094 dev_dbg(be->dev, "ASoC: BE %s event %d dir %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +010095 be->dai_link->name, event, dir);
96
97 snd_soc_dapm_stream_event(be, dir, event);
98 }
99
100 snd_soc_dapm_stream_event(fe, dir, event);
101
102 return 0;
103}
104
Dong Aisheng17841022011-08-29 17:15:14 +0800105static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
106 struct snd_soc_dai *soc_dai)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100107{
108 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100109 int ret;
110
Nicolin Chen3635bf02013-11-13 18:56:24 +0800111 if (soc_dai->rate && (soc_dai->driver->symmetric_rates ||
112 rtd->dai_link->symmetric_rates)) {
113 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n",
114 soc_dai->rate);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100115
Nicolin Chen3635bf02013-11-13 18:56:24 +0800116 ret = snd_pcm_hw_constraint_minmax(substream->runtime,
117 SNDRV_PCM_HW_PARAM_RATE,
118 soc_dai->rate, soc_dai->rate);
119 if (ret < 0) {
120 dev_err(soc_dai->dev,
121 "ASoC: Unable to apply rate constraint: %d\n",
122 ret);
123 return ret;
124 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100125 }
126
Nicolin Chen3635bf02013-11-13 18:56:24 +0800127 if (soc_dai->channels && (soc_dai->driver->symmetric_channels ||
128 rtd->dai_link->symmetric_channels)) {
129 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d channel(s)\n",
130 soc_dai->channels);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100131
Nicolin Chen3635bf02013-11-13 18:56:24 +0800132 ret = snd_pcm_hw_constraint_minmax(substream->runtime,
133 SNDRV_PCM_HW_PARAM_CHANNELS,
134 soc_dai->channels,
135 soc_dai->channels);
136 if (ret < 0) {
137 dev_err(soc_dai->dev,
138 "ASoC: Unable to apply channel symmetry constraint: %d\n",
139 ret);
140 return ret;
141 }
142 }
143
144 if (soc_dai->sample_bits && (soc_dai->driver->symmetric_samplebits ||
145 rtd->dai_link->symmetric_samplebits)) {
146 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d sample bits\n",
147 soc_dai->sample_bits);
148
149 ret = snd_pcm_hw_constraint_minmax(substream->runtime,
150 SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
151 soc_dai->sample_bits,
152 soc_dai->sample_bits);
153 if (ret < 0) {
154 dev_err(soc_dai->dev,
155 "ASoC: Unable to apply sample bits symmetry constraint: %d\n",
156 ret);
157 return ret;
158 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100159 }
160
161 return 0;
162}
163
Nicolin Chen3635bf02013-11-13 18:56:24 +0800164static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
165 struct snd_pcm_hw_params *params)
166{
167 struct snd_soc_pcm_runtime *rtd = substream->private_data;
168 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
169 struct snd_soc_dai *codec_dai = rtd->codec_dai;
170 unsigned int rate, channels, sample_bits, symmetry;
171
172 rate = params_rate(params);
173 channels = params_channels(params);
174 sample_bits = snd_pcm_format_physical_width(params_format(params));
175
176 /* reject unmatched parameters when applying symmetry */
177 symmetry = cpu_dai->driver->symmetric_rates ||
178 codec_dai->driver->symmetric_rates ||
179 rtd->dai_link->symmetric_rates;
180 if (symmetry && cpu_dai->rate && cpu_dai->rate != rate) {
181 dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n",
182 cpu_dai->rate, rate);
183 return -EINVAL;
184 }
185
186 symmetry = cpu_dai->driver->symmetric_channels ||
187 codec_dai->driver->symmetric_channels ||
188 rtd->dai_link->symmetric_channels;
189 if (symmetry && cpu_dai->channels && cpu_dai->channels != channels) {
190 dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n",
191 cpu_dai->channels, channels);
192 return -EINVAL;
193 }
194
195 symmetry = cpu_dai->driver->symmetric_samplebits ||
196 codec_dai->driver->symmetric_samplebits ||
197 rtd->dai_link->symmetric_samplebits;
198 if (symmetry && cpu_dai->sample_bits && cpu_dai->sample_bits != sample_bits) {
199 dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n",
200 cpu_dai->sample_bits, sample_bits);
201 return -EINVAL;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100202 }
203
204 return 0;
205}
206
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100207static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream)
208{
209 struct snd_soc_pcm_runtime *rtd = substream->private_data;
210 struct snd_soc_dai_driver *cpu_driver = rtd->cpu_dai->driver;
211 struct snd_soc_dai_driver *codec_driver = rtd->codec_dai->driver;
212 struct snd_soc_dai_link *link = rtd->dai_link;
213
214 return cpu_driver->symmetric_rates || codec_driver->symmetric_rates ||
215 link->symmetric_rates || cpu_driver->symmetric_channels ||
216 codec_driver->symmetric_channels || link->symmetric_channels ||
217 cpu_driver->symmetric_samplebits ||
218 codec_driver->symmetric_samplebits ||
219 link->symmetric_samplebits;
220}
221
Liam Girdwoodddee6272011-06-09 14:45:53 +0100222/*
Mark Brown58ba9b22012-01-16 18:38:51 +0000223 * List of sample sizes that might go over the bus for parameter
224 * application. There ought to be a wildcard sample size for things
225 * like the DAC/ADC resolution to use but there isn't right now.
226 */
227static int sample_sizes[] = {
Peter Ujfalusi88e33952012-01-25 10:09:41 +0200228 24, 32,
Mark Brown58ba9b22012-01-16 18:38:51 +0000229};
230
231static void soc_pcm_apply_msb(struct snd_pcm_substream *substream,
232 struct snd_soc_dai *dai)
233{
234 int ret, i, bits;
235
236 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
237 bits = dai->driver->playback.sig_bits;
238 else
239 bits = dai->driver->capture.sig_bits;
240
241 if (!bits)
242 return;
243
244 for (i = 0; i < ARRAY_SIZE(sample_sizes); i++) {
Mark Brown278047f2012-01-19 18:04:18 +0000245 if (bits >= sample_sizes[i])
246 continue;
247
248 ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0,
249 sample_sizes[i], bits);
Mark Brown58ba9b22012-01-16 18:38:51 +0000250 if (ret != 0)
251 dev_warn(dai->dev,
Liam Girdwood103d84a2012-11-19 14:39:15 +0000252 "ASoC: Failed to set MSB %d/%d: %d\n",
Mark Brown58ba9b22012-01-16 18:38:51 +0000253 bits, sample_sizes[i], ret);
254 }
255}
256
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100257static void soc_pcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200258 struct snd_soc_pcm_stream *codec_stream,
259 struct snd_soc_pcm_stream *cpu_stream)
260{
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100261 struct snd_pcm_hardware *hw = &runtime->hw;
262
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200263 hw->channels_min = max(codec_stream->channels_min,
264 cpu_stream->channels_min);
265 hw->channels_max = min(codec_stream->channels_max,
266 cpu_stream->channels_max);
Lars-Peter Clausen16d7ea92014-01-06 14:19:16 +0100267 if (hw->formats)
268 hw->formats &= codec_stream->formats & cpu_stream->formats;
269 else
270 hw->formats = codec_stream->formats & cpu_stream->formats;
Lars-Peter Clausen55dcdb52014-01-11 10:24:44 +0100271 hw->rates = snd_pcm_rate_mask_intersect(codec_stream->rates,
272 cpu_stream->rates);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100273
Lars-Peter Clausen817873f2014-01-11 10:24:40 +0100274 hw->rate_min = 0;
275 hw->rate_max = UINT_MAX;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100276
277 snd_pcm_limit_hw_rates(runtime);
278
279 hw->rate_min = max(hw->rate_min, cpu_stream->rate_min);
280 hw->rate_min = max(hw->rate_min, codec_stream->rate_min);
281 hw->rate_max = min_not_zero(hw->rate_max, cpu_stream->rate_max);
282 hw->rate_max = min_not_zero(hw->rate_max, codec_stream->rate_max);
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200283}
284
Mark Brown58ba9b22012-01-16 18:38:51 +0000285/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100286 * Called by ALSA when a PCM substream is opened, the runtime->hw record is
287 * then initialized and any private data can be allocated. This also calls
288 * startup for the cpu DAI, platform, machine and codec DAI.
289 */
290static int soc_pcm_open(struct snd_pcm_substream *substream)
291{
292 struct snd_soc_pcm_runtime *rtd = substream->private_data;
293 struct snd_pcm_runtime *runtime = substream->runtime;
294 struct snd_soc_platform *platform = rtd->platform;
295 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
296 struct snd_soc_dai *codec_dai = rtd->codec_dai;
297 struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
298 struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver;
299 int ret = 0;
300
Nicolin Chen988e8cc2013-11-04 14:57:31 +0800301 pinctrl_pm_select_default_state(cpu_dai->dev);
302 pinctrl_pm_select_default_state(codec_dai->dev);
Mark Brownd6652ef2011-12-03 20:14:31 +0000303 pm_runtime_get_sync(cpu_dai->dev);
304 pm_runtime_get_sync(codec_dai->dev);
305 pm_runtime_get_sync(platform->dev);
306
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100307 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100308
309 /* startup the audio subsystem */
Mark Brownc5914b02013-10-30 17:47:39 -0700310 if (cpu_dai->driver->ops && cpu_dai->driver->ops->startup) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100311 ret = cpu_dai->driver->ops->startup(substream, cpu_dai);
312 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000313 dev_err(cpu_dai->dev, "ASoC: can't open interface"
314 " %s: %d\n", cpu_dai->name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100315 goto out;
316 }
317 }
318
319 if (platform->driver->ops && platform->driver->ops->open) {
320 ret = platform->driver->ops->open(substream);
321 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000322 dev_err(platform->dev, "ASoC: can't open platform"
323 " %s: %d\n", platform->name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100324 goto platform_err;
325 }
326 }
327
Mark Brownc5914b02013-10-30 17:47:39 -0700328 if (codec_dai->driver->ops && codec_dai->driver->ops->startup) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100329 ret = codec_dai->driver->ops->startup(substream, codec_dai);
330 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000331 dev_err(codec_dai->dev, "ASoC: can't open codec"
332 " %s: %d\n", codec_dai->name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100333 goto codec_dai_err;
334 }
335 }
336
337 if (rtd->dai_link->ops && rtd->dai_link->ops->startup) {
338 ret = rtd->dai_link->ops->startup(substream);
339 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000340 pr_err("ASoC: %s startup failed: %d\n",
Mark Brown25bfe662012-02-01 21:30:32 +0000341 rtd->dai_link->name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100342 goto machine_err;
343 }
344 }
345
Liam Girdwood01d75842012-04-25 12:12:49 +0100346 /* Dynamic PCM DAI links compat checks use dynamic capabilities */
347 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm)
348 goto dynamic;
349
Liam Girdwoodddee6272011-06-09 14:45:53 +0100350 /* Check that the codec and cpu DAIs are compatible */
351 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100352 soc_pcm_init_runtime_hw(runtime, &codec_dai_drv->playback,
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200353 &cpu_dai_drv->playback);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100354 } else {
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100355 soc_pcm_init_runtime_hw(runtime, &codec_dai_drv->capture,
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200356 &cpu_dai_drv->capture);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100357 }
358
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100359 if (soc_pcm_has_symmetry(substream))
360 runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
361
Liam Girdwoodddee6272011-06-09 14:45:53 +0100362 ret = -EINVAL;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100363 if (!runtime->hw.rates) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000364 printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n",
Liam Girdwoodddee6272011-06-09 14:45:53 +0100365 codec_dai->name, cpu_dai->name);
366 goto config_err;
367 }
368 if (!runtime->hw.formats) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000369 printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n",
Liam Girdwoodddee6272011-06-09 14:45:53 +0100370 codec_dai->name, cpu_dai->name);
371 goto config_err;
372 }
373 if (!runtime->hw.channels_min || !runtime->hw.channels_max ||
374 runtime->hw.channels_min > runtime->hw.channels_max) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000375 printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n",
Liam Girdwoodddee6272011-06-09 14:45:53 +0100376 codec_dai->name, cpu_dai->name);
377 goto config_err;
378 }
379
Mark Brown58ba9b22012-01-16 18:38:51 +0000380 soc_pcm_apply_msb(substream, codec_dai);
381 soc_pcm_apply_msb(substream, cpu_dai);
382
Liam Girdwoodddee6272011-06-09 14:45:53 +0100383 /* Symmetry only applies if we've already got an active stream. */
Dong Aisheng17841022011-08-29 17:15:14 +0800384 if (cpu_dai->active) {
385 ret = soc_pcm_apply_symmetry(substream, cpu_dai);
386 if (ret != 0)
387 goto config_err;
388 }
389
390 if (codec_dai->active) {
391 ret = soc_pcm_apply_symmetry(substream, codec_dai);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100392 if (ret != 0)
393 goto config_err;
394 }
395
Liam Girdwood103d84a2012-11-19 14:39:15 +0000396 pr_debug("ASoC: %s <-> %s info:\n",
Liam Girdwoodddee6272011-06-09 14:45:53 +0100397 codec_dai->name, cpu_dai->name);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000398 pr_debug("ASoC: rate mask 0x%x\n", runtime->hw.rates);
399 pr_debug("ASoC: min ch %d max ch %d\n", runtime->hw.channels_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100400 runtime->hw.channels_max);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000401 pr_debug("ASoC: min rate %d max rate %d\n", runtime->hw.rate_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100402 runtime->hw.rate_max);
403
Liam Girdwood01d75842012-04-25 12:12:49 +0100404dynamic:
Liam Girdwoodddee6272011-06-09 14:45:53 +0100405 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
406 cpu_dai->playback_active++;
407 codec_dai->playback_active++;
408 } else {
409 cpu_dai->capture_active++;
410 codec_dai->capture_active++;
411 }
412 cpu_dai->active++;
413 codec_dai->active++;
414 rtd->codec->active++;
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100415 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100416 return 0;
417
418config_err:
419 if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
420 rtd->dai_link->ops->shutdown(substream);
421
422machine_err:
423 if (codec_dai->driver->ops->shutdown)
424 codec_dai->driver->ops->shutdown(substream, codec_dai);
425
426codec_dai_err:
427 if (platform->driver->ops && platform->driver->ops->close)
428 platform->driver->ops->close(substream);
429
430platform_err:
431 if (cpu_dai->driver->ops->shutdown)
432 cpu_dai->driver->ops->shutdown(substream, cpu_dai);
433out:
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100434 mutex_unlock(&rtd->pcm_mutex);
Mark Brownd6652ef2011-12-03 20:14:31 +0000435
436 pm_runtime_put(platform->dev);
437 pm_runtime_put(codec_dai->dev);
438 pm_runtime_put(cpu_dai->dev);
Nicolin Chen988e8cc2013-11-04 14:57:31 +0800439 if (!codec_dai->active)
440 pinctrl_pm_select_sleep_state(codec_dai->dev);
441 if (!cpu_dai->active)
442 pinctrl_pm_select_sleep_state(cpu_dai->dev);
Mark Brownd6652ef2011-12-03 20:14:31 +0000443
Liam Girdwoodddee6272011-06-09 14:45:53 +0100444 return ret;
445}
446
447/*
448 * Power down the audio subsystem pmdown_time msecs after close is called.
449 * This is to ensure there are no pops or clicks in between any music tracks
450 * due to DAPM power cycling.
451 */
452static void close_delayed_work(struct work_struct *work)
453{
454 struct snd_soc_pcm_runtime *rtd =
455 container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
456 struct snd_soc_dai *codec_dai = rtd->codec_dai;
457
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100458 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100459
Liam Girdwood103d84a2012-11-19 14:39:15 +0000460 dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n",
Liam Girdwoodddee6272011-06-09 14:45:53 +0100461 codec_dai->driver->playback.stream_name,
462 codec_dai->playback_active ? "active" : "inactive",
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600463 rtd->pop_wait ? "yes" : "no");
Liam Girdwoodddee6272011-06-09 14:45:53 +0100464
465 /* are we waiting on this codec DAI stream */
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600466 if (rtd->pop_wait == 1) {
467 rtd->pop_wait = 0;
Mark Brown7bd3a6f2012-02-16 15:03:27 -0800468 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000469 SND_SOC_DAPM_STREAM_STOP);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100470 }
471
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100472 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100473}
474
475/*
476 * Called by ALSA when a PCM substream is closed. Private data can be
477 * freed here. The cpu DAI, codec DAI, machine and platform are also
478 * shutdown.
479 */
Liam Girdwood91d5e6b2011-06-09 17:04:59 +0100480static int soc_pcm_close(struct snd_pcm_substream *substream)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100481{
482 struct snd_soc_pcm_runtime *rtd = substream->private_data;
483 struct snd_soc_platform *platform = rtd->platform;
484 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
485 struct snd_soc_dai *codec_dai = rtd->codec_dai;
486 struct snd_soc_codec *codec = rtd->codec;
487
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100488 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100489
490 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
491 cpu_dai->playback_active--;
492 codec_dai->playback_active--;
493 } else {
494 cpu_dai->capture_active--;
495 codec_dai->capture_active--;
496 }
497
498 cpu_dai->active--;
499 codec_dai->active--;
500 codec->active--;
501
Dong Aisheng17841022011-08-29 17:15:14 +0800502 /* clear the corresponding DAIs rate when inactive */
503 if (!cpu_dai->active)
504 cpu_dai->rate = 0;
505
506 if (!codec_dai->active)
507 codec_dai->rate = 0;
Sascha Hauer25b76792011-08-17 09:20:01 +0200508
Liam Girdwoodddee6272011-06-09 14:45:53 +0100509 if (cpu_dai->driver->ops->shutdown)
510 cpu_dai->driver->ops->shutdown(substream, cpu_dai);
511
512 if (codec_dai->driver->ops->shutdown)
513 codec_dai->driver->ops->shutdown(substream, codec_dai);
514
515 if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
516 rtd->dai_link->ops->shutdown(substream);
517
518 if (platform->driver->ops && platform->driver->ops->close)
519 platform->driver->ops->close(substream);
520 cpu_dai->runtime = NULL;
521
522 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100523 if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
Peter Ujfalusi1d69c5c2011-10-14 14:43:33 +0300524 /* powered down playback stream now */
525 snd_soc_dapm_stream_event(rtd,
Mark Brown7bd3a6f2012-02-16 15:03:27 -0800526 SNDRV_PCM_STREAM_PLAYBACK,
Mark Brown7bd3a6f2012-02-16 15:03:27 -0800527 SND_SOC_DAPM_STREAM_STOP);
Peter Ujfalusi1d69c5c2011-10-14 14:43:33 +0300528 } else {
529 /* start delayed pop wq here for playback streams */
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600530 rtd->pop_wait = 1;
Mark Brownd4e1a732013-07-18 11:52:17 +0100531 queue_delayed_work(system_power_efficient_wq,
532 &rtd->delayed_work,
533 msecs_to_jiffies(rtd->pmdown_time));
Peter Ujfalusi1d69c5c2011-10-14 14:43:33 +0300534 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100535 } else {
536 /* capture streams can be powered down now */
Mark Brown7bd3a6f2012-02-16 15:03:27 -0800537 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000538 SND_SOC_DAPM_STREAM_STOP);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100539 }
540
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100541 mutex_unlock(&rtd->pcm_mutex);
Mark Brownd6652ef2011-12-03 20:14:31 +0000542
543 pm_runtime_put(platform->dev);
544 pm_runtime_put(codec_dai->dev);
545 pm_runtime_put(cpu_dai->dev);
Nicolin Chen988e8cc2013-11-04 14:57:31 +0800546 if (!codec_dai->active)
547 pinctrl_pm_select_sleep_state(codec_dai->dev);
548 if (!cpu_dai->active)
549 pinctrl_pm_select_sleep_state(cpu_dai->dev);
Mark Brownd6652ef2011-12-03 20:14:31 +0000550
Liam Girdwoodddee6272011-06-09 14:45:53 +0100551 return 0;
552}
553
554/*
555 * Called by ALSA when the PCM substream is prepared, can set format, sample
556 * rate, etc. This function is non atomic and can be called multiple times,
557 * it can refer to the runtime info.
558 */
559static int soc_pcm_prepare(struct snd_pcm_substream *substream)
560{
561 struct snd_soc_pcm_runtime *rtd = substream->private_data;
562 struct snd_soc_platform *platform = rtd->platform;
563 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
564 struct snd_soc_dai *codec_dai = rtd->codec_dai;
565 int ret = 0;
566
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100567 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100568
569 if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) {
570 ret = rtd->dai_link->ops->prepare(substream);
571 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000572 dev_err(rtd->card->dev, "ASoC: machine prepare error:"
573 " %d\n", ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100574 goto out;
575 }
576 }
577
578 if (platform->driver->ops && platform->driver->ops->prepare) {
579 ret = platform->driver->ops->prepare(substream);
580 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000581 dev_err(platform->dev, "ASoC: platform prepare error:"
582 " %d\n", ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100583 goto out;
584 }
585 }
586
Mark Brownc5914b02013-10-30 17:47:39 -0700587 if (codec_dai->driver->ops && codec_dai->driver->ops->prepare) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100588 ret = codec_dai->driver->ops->prepare(substream, codec_dai);
589 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000590 dev_err(codec_dai->dev, "ASoC: DAI prepare error: %d\n",
Mark Brown25bfe662012-02-01 21:30:32 +0000591 ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100592 goto out;
593 }
594 }
595
Mark Brownc5914b02013-10-30 17:47:39 -0700596 if (cpu_dai->driver->ops && cpu_dai->driver->ops->prepare) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100597 ret = cpu_dai->driver->ops->prepare(substream, cpu_dai);
598 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000599 dev_err(cpu_dai->dev, "ASoC: DAI prepare error: %d\n",
Mark Brown25bfe662012-02-01 21:30:32 +0000600 ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100601 goto out;
602 }
603 }
604
605 /* cancel any delayed stream shutdown that is pending */
606 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600607 rtd->pop_wait) {
608 rtd->pop_wait = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100609 cancel_delayed_work(&rtd->delayed_work);
610 }
611
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000612 snd_soc_dapm_stream_event(rtd, substream->stream,
613 SND_SOC_DAPM_STREAM_START);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100614
Mark Brownda183962013-02-06 15:44:07 +0000615 snd_soc_dai_digital_mute(codec_dai, 0, substream->stream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100616
617out:
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100618 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100619 return ret;
620}
621
622/*
623 * Called by ALSA when the hardware params are set by application. This
624 * function can also be called multiple times and can allocate buffers
625 * (using snd_pcm_lib_* ). It's non-atomic.
626 */
627static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
628 struct snd_pcm_hw_params *params)
629{
630 struct snd_soc_pcm_runtime *rtd = substream->private_data;
631 struct snd_soc_platform *platform = rtd->platform;
632 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
633 struct snd_soc_dai *codec_dai = rtd->codec_dai;
634 int ret = 0;
635
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100636 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100637
Nicolin Chen3635bf02013-11-13 18:56:24 +0800638 ret = soc_pcm_params_symmetry(substream, params);
639 if (ret)
640 goto out;
641
Liam Girdwoodddee6272011-06-09 14:45:53 +0100642 if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) {
643 ret = rtd->dai_link->ops->hw_params(substream, params);
644 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000645 dev_err(rtd->card->dev, "ASoC: machine hw_params"
646 " failed: %d\n", ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100647 goto out;
648 }
649 }
650
Mark Brownc5914b02013-10-30 17:47:39 -0700651 if (codec_dai->driver->ops && codec_dai->driver->ops->hw_params) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100652 ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai);
653 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000654 dev_err(codec_dai->dev, "ASoC: can't set %s hw params:"
655 " %d\n", codec_dai->name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100656 goto codec_err;
657 }
658 }
659
Mark Brownc5914b02013-10-30 17:47:39 -0700660 if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_params) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100661 ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai);
662 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000663 dev_err(cpu_dai->dev, "ASoC: %s hw params failed: %d\n",
Mark Brown25bfe662012-02-01 21:30:32 +0000664 cpu_dai->name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100665 goto interface_err;
666 }
667 }
668
669 if (platform->driver->ops && platform->driver->ops->hw_params) {
670 ret = platform->driver->ops->hw_params(substream, params);
671 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000672 dev_err(platform->dev, "ASoC: %s hw params failed: %d\n",
Mark Brown25bfe662012-02-01 21:30:32 +0000673 platform->name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100674 goto platform_err;
675 }
676 }
677
Nicolin Chen3635bf02013-11-13 18:56:24 +0800678 /* store the parameters for each DAIs */
Dong Aisheng17841022011-08-29 17:15:14 +0800679 cpu_dai->rate = params_rate(params);
Nicolin Chen3635bf02013-11-13 18:56:24 +0800680 cpu_dai->channels = params_channels(params);
681 cpu_dai->sample_bits =
682 snd_pcm_format_physical_width(params_format(params));
683
Dong Aisheng17841022011-08-29 17:15:14 +0800684 codec_dai->rate = params_rate(params);
Nicolin Chen3635bf02013-11-13 18:56:24 +0800685 codec_dai->channels = params_channels(params);
686 codec_dai->sample_bits =
687 snd_pcm_format_physical_width(params_format(params));
Liam Girdwoodddee6272011-06-09 14:45:53 +0100688
689out:
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100690 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100691 return ret;
692
693platform_err:
Mark Brownc5914b02013-10-30 17:47:39 -0700694 if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_free)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100695 cpu_dai->driver->ops->hw_free(substream, cpu_dai);
696
697interface_err:
Mark Brownc5914b02013-10-30 17:47:39 -0700698 if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100699 codec_dai->driver->ops->hw_free(substream, codec_dai);
700
701codec_err:
702 if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
703 rtd->dai_link->ops->hw_free(substream);
704
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100705 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100706 return ret;
707}
708
709/*
710 * Frees resources allocated by hw_params, can be called multiple times
711 */
712static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
713{
714 struct snd_soc_pcm_runtime *rtd = substream->private_data;
715 struct snd_soc_platform *platform = rtd->platform;
716 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
717 struct snd_soc_dai *codec_dai = rtd->codec_dai;
Nicolin Chen7f62b6e2013-12-04 11:18:36 +0800718 bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100719
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100720 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100721
Nicolin Chend3383422013-11-20 18:37:09 +0800722 /* clear the corresponding DAIs parameters when going to be inactive */
723 if (cpu_dai->active == 1) {
724 cpu_dai->rate = 0;
725 cpu_dai->channels = 0;
726 cpu_dai->sample_bits = 0;
727 }
728
729 if (codec_dai->active == 1) {
730 codec_dai->rate = 0;
731 codec_dai->channels = 0;
732 codec_dai->sample_bits = 0;
733 }
734
Liam Girdwoodddee6272011-06-09 14:45:53 +0100735 /* apply codec digital mute */
Nicolin Chen7f62b6e2013-12-04 11:18:36 +0800736 if ((playback && codec_dai->playback_active == 1) ||
737 (!playback && codec_dai->capture_active == 1))
Mark Brownda183962013-02-06 15:44:07 +0000738 snd_soc_dai_digital_mute(codec_dai, 1, substream->stream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100739
740 /* free any machine hw params */
741 if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
742 rtd->dai_link->ops->hw_free(substream);
743
744 /* free any DMA resources */
745 if (platform->driver->ops && platform->driver->ops->hw_free)
746 platform->driver->ops->hw_free(substream);
747
748 /* now free hw params for the DAIs */
Mark Brownc5914b02013-10-30 17:47:39 -0700749 if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100750 codec_dai->driver->ops->hw_free(substream, codec_dai);
751
Mark Brownc5914b02013-10-30 17:47:39 -0700752 if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_free)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100753 cpu_dai->driver->ops->hw_free(substream, cpu_dai);
754
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100755 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100756 return 0;
757}
758
759static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
760{
761 struct snd_soc_pcm_runtime *rtd = substream->private_data;
762 struct snd_soc_platform *platform = rtd->platform;
763 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
764 struct snd_soc_dai *codec_dai = rtd->codec_dai;
765 int ret;
766
Mark Brownc5914b02013-10-30 17:47:39 -0700767 if (codec_dai->driver->ops && codec_dai->driver->ops->trigger) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100768 ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai);
769 if (ret < 0)
770 return ret;
771 }
772
773 if (platform->driver->ops && platform->driver->ops->trigger) {
774 ret = platform->driver->ops->trigger(substream, cmd);
775 if (ret < 0)
776 return ret;
777 }
778
Mark Brownc5914b02013-10-30 17:47:39 -0700779 if (cpu_dai->driver->ops && cpu_dai->driver->ops->trigger) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100780 ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai);
781 if (ret < 0)
782 return ret;
783 }
784 return 0;
785}
786
Mark Brown45c0a182012-05-09 21:46:27 +0100787static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
788 int cmd)
Liam Girdwood07bf84a2012-04-25 12:12:52 +0100789{
790 struct snd_soc_pcm_runtime *rtd = substream->private_data;
791 struct snd_soc_platform *platform = rtd->platform;
792 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
793 struct snd_soc_dai *codec_dai = rtd->codec_dai;
794 int ret;
795
Mark Brownc5914b02013-10-30 17:47:39 -0700796 if (codec_dai->driver->ops &&
797 codec_dai->driver->ops->bespoke_trigger) {
Liam Girdwood07bf84a2012-04-25 12:12:52 +0100798 ret = codec_dai->driver->ops->bespoke_trigger(substream, cmd, codec_dai);
799 if (ret < 0)
800 return ret;
801 }
802
Jean-Francois Moinedcf0fa22014-01-03 09:19:18 +0100803 if (platform->driver->bespoke_trigger) {
Liam Girdwood07bf84a2012-04-25 12:12:52 +0100804 ret = platform->driver->bespoke_trigger(substream, cmd);
805 if (ret < 0)
806 return ret;
807 }
808
Mark Brownc5914b02013-10-30 17:47:39 -0700809 if (cpu_dai->driver->ops && cpu_dai->driver->ops->bespoke_trigger) {
Liam Girdwood07bf84a2012-04-25 12:12:52 +0100810 ret = cpu_dai->driver->ops->bespoke_trigger(substream, cmd, cpu_dai);
811 if (ret < 0)
812 return ret;
813 }
814 return 0;
815}
Liam Girdwoodddee6272011-06-09 14:45:53 +0100816/*
817 * soc level wrapper for pointer callback
818 * If cpu_dai, codec_dai, platform driver has the delay callback, than
819 * the runtime->delay will be updated accordingly.
820 */
821static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
822{
823 struct snd_soc_pcm_runtime *rtd = substream->private_data;
824 struct snd_soc_platform *platform = rtd->platform;
825 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
826 struct snd_soc_dai *codec_dai = rtd->codec_dai;
827 struct snd_pcm_runtime *runtime = substream->runtime;
828 snd_pcm_uframes_t offset = 0;
829 snd_pcm_sframes_t delay = 0;
830
831 if (platform->driver->ops && platform->driver->ops->pointer)
832 offset = platform->driver->ops->pointer(substream);
833
Mark Brownc5914b02013-10-30 17:47:39 -0700834 if (cpu_dai->driver->ops && cpu_dai->driver->ops->delay)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100835 delay += cpu_dai->driver->ops->delay(substream, cpu_dai);
836
Mark Brownc5914b02013-10-30 17:47:39 -0700837 if (codec_dai->driver->ops && codec_dai->driver->ops->delay)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100838 delay += codec_dai->driver->ops->delay(substream, codec_dai);
839
840 if (platform->driver->delay)
841 delay += platform->driver->delay(substream, codec_dai);
842
843 runtime->delay = delay;
844
845 return offset;
846}
847
Liam Girdwood01d75842012-04-25 12:12:49 +0100848/* connect a FE and BE */
849static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
850 struct snd_soc_pcm_runtime *be, int stream)
851{
852 struct snd_soc_dpcm *dpcm;
853
854 /* only add new dpcms */
855 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
856 if (dpcm->be == be && dpcm->fe == fe)
857 return 0;
858 }
859
860 dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_KERNEL);
861 if (!dpcm)
862 return -ENOMEM;
863
864 dpcm->be = be;
865 dpcm->fe = fe;
866 be->dpcm[stream].runtime = fe->dpcm[stream].runtime;
867 dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW;
868 list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients);
869 list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients);
870
Jarkko Nikula7cc302d2013-09-30 17:08:15 +0300871 dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +0100872 stream ? "capture" : "playback", fe->dai_link->name,
873 stream ? "<-" : "->", be->dai_link->name);
874
Liam Girdwoodf86dcef2012-04-25 12:12:50 +0100875#ifdef CONFIG_DEBUG_FS
876 dpcm->debugfs_state = debugfs_create_u32(be->dai_link->name, 0644,
877 fe->debugfs_dpcm_root, &dpcm->state);
878#endif
Liam Girdwood01d75842012-04-25 12:12:49 +0100879 return 1;
880}
881
882/* reparent a BE onto another FE */
883static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
884 struct snd_soc_pcm_runtime *be, int stream)
885{
886 struct snd_soc_dpcm *dpcm;
887 struct snd_pcm_substream *fe_substream, *be_substream;
888
889 /* reparent if BE is connected to other FEs */
890 if (!be->dpcm[stream].users)
891 return;
892
893 be_substream = snd_soc_dpcm_get_substream(be, stream);
894
895 list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {
896 if (dpcm->fe == fe)
897 continue;
898
Jarkko Nikula7cc302d2013-09-30 17:08:15 +0300899 dev_dbg(fe->dev, "reparent %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +0100900 stream ? "capture" : "playback",
901 dpcm->fe->dai_link->name,
902 stream ? "<-" : "->", dpcm->be->dai_link->name);
903
904 fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, stream);
905 be_substream->runtime = fe_substream->runtime;
906 break;
907 }
908}
909
910/* disconnect a BE and FE */
Liam Girdwood23607022014-01-17 17:03:55 +0000911void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +0100912{
913 struct snd_soc_dpcm *dpcm, *d;
914
915 list_for_each_entry_safe(dpcm, d, &fe->dpcm[stream].be_clients, list_be) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000916 dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +0100917 stream ? "capture" : "playback",
918 dpcm->be->dai_link->name);
919
920 if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE)
921 continue;
922
Jarkko Nikula7cc302d2013-09-30 17:08:15 +0300923 dev_dbg(fe->dev, "freed DSP %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +0100924 stream ? "capture" : "playback", fe->dai_link->name,
925 stream ? "<-" : "->", dpcm->be->dai_link->name);
926
927 /* BEs still alive need new FE */
928 dpcm_be_reparent(fe, dpcm->be, stream);
929
Liam Girdwoodf86dcef2012-04-25 12:12:50 +0100930#ifdef CONFIG_DEBUG_FS
931 debugfs_remove(dpcm->debugfs_state);
932#endif
Liam Girdwood01d75842012-04-25 12:12:49 +0100933 list_del(&dpcm->list_be);
934 list_del(&dpcm->list_fe);
935 kfree(dpcm);
936 }
937}
938
939/* get BE for DAI widget and stream */
940static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
941 struct snd_soc_dapm_widget *widget, int stream)
942{
943 struct snd_soc_pcm_runtime *be;
944 int i;
945
946 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
947 for (i = 0; i < card->num_links; i++) {
948 be = &card->rtd[i];
949
Liam Girdwood35ea0652012-06-05 19:26:59 +0100950 if (!be->dai_link->no_pcm)
951 continue;
952
Liam Girdwood01d75842012-04-25 12:12:49 +0100953 if (be->cpu_dai->playback_widget == widget ||
954 be->codec_dai->playback_widget == widget)
955 return be;
956 }
957 } else {
958
959 for (i = 0; i < card->num_links; i++) {
960 be = &card->rtd[i];
961
Liam Girdwood35ea0652012-06-05 19:26:59 +0100962 if (!be->dai_link->no_pcm)
963 continue;
964
Liam Girdwood01d75842012-04-25 12:12:49 +0100965 if (be->cpu_dai->capture_widget == widget ||
966 be->codec_dai->capture_widget == widget)
967 return be;
968 }
969 }
970
Liam Girdwood103d84a2012-11-19 14:39:15 +0000971 dev_err(card->dev, "ASoC: can't get %s BE for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +0100972 stream ? "capture" : "playback", widget->name);
973 return NULL;
974}
975
976static inline struct snd_soc_dapm_widget *
977 rtd_get_cpu_widget(struct snd_soc_pcm_runtime *rtd, int stream)
978{
979 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
980 return rtd->cpu_dai->playback_widget;
981 else
982 return rtd->cpu_dai->capture_widget;
983}
984
985static inline struct snd_soc_dapm_widget *
986 rtd_get_codec_widget(struct snd_soc_pcm_runtime *rtd, int stream)
987{
988 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
989 return rtd->codec_dai->playback_widget;
990 else
991 return rtd->codec_dai->capture_widget;
992}
993
994static int widget_in_list(struct snd_soc_dapm_widget_list *list,
995 struct snd_soc_dapm_widget *widget)
996{
997 int i;
998
999 for (i = 0; i < list->num_widgets; i++) {
1000 if (widget == list->widgets[i])
1001 return 1;
1002 }
1003
1004 return 0;
1005}
1006
Liam Girdwood23607022014-01-17 17:03:55 +00001007int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
Liam Girdwood01d75842012-04-25 12:12:49 +01001008 int stream, struct snd_soc_dapm_widget_list **list_)
1009{
1010 struct snd_soc_dai *cpu_dai = fe->cpu_dai;
1011 struct snd_soc_dapm_widget_list *list;
1012 int paths;
1013
1014 list = kzalloc(sizeof(struct snd_soc_dapm_widget_list) +
1015 sizeof(struct snd_soc_dapm_widget *), GFP_KERNEL);
1016 if (list == NULL)
1017 return -ENOMEM;
1018
1019 /* get number of valid DAI paths and their widgets */
1020 paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, &list);
1021
Liam Girdwood103d84a2012-11-19 14:39:15 +00001022 dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths,
Liam Girdwood01d75842012-04-25 12:12:49 +01001023 stream ? "capture" : "playback");
1024
1025 *list_ = list;
1026 return paths;
1027}
1028
Liam Girdwood01d75842012-04-25 12:12:49 +01001029static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
1030 struct snd_soc_dapm_widget_list **list_)
1031{
1032 struct snd_soc_dpcm *dpcm;
1033 struct snd_soc_dapm_widget_list *list = *list_;
1034 struct snd_soc_dapm_widget *widget;
1035 int prune = 0;
1036
1037 /* Destroy any old FE <--> BE connections */
1038 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1039
1040 /* is there a valid CPU DAI widget for this BE */
1041 widget = rtd_get_cpu_widget(dpcm->be, stream);
1042
1043 /* prune the BE if it's no longer in our active list */
1044 if (widget && widget_in_list(list, widget))
1045 continue;
1046
1047 /* is there a valid CODEC DAI widget for this BE */
1048 widget = rtd_get_codec_widget(dpcm->be, stream);
1049
1050 /* prune the BE if it's no longer in our active list */
1051 if (widget && widget_in_list(list, widget))
1052 continue;
1053
Liam Girdwood103d84a2012-11-19 14:39:15 +00001054 dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001055 stream ? "capture" : "playback",
1056 dpcm->be->dai_link->name, fe->dai_link->name);
1057 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
1058 dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1059 prune++;
1060 }
1061
Liam Girdwood103d84a2012-11-19 14:39:15 +00001062 dev_dbg(fe->dev, "ASoC: found %d old BE paths for pruning\n", prune);
Liam Girdwood01d75842012-04-25 12:12:49 +01001063 return prune;
1064}
1065
1066static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
1067 struct snd_soc_dapm_widget_list **list_)
1068{
1069 struct snd_soc_card *card = fe->card;
1070 struct snd_soc_dapm_widget_list *list = *list_;
1071 struct snd_soc_pcm_runtime *be;
1072 int i, new = 0, err;
1073
1074 /* Create any new FE <--> BE connections */
1075 for (i = 0; i < list->num_widgets; i++) {
1076
Mark Brown46162742013-06-05 19:36:11 +01001077 switch (list->widgets[i]->id) {
1078 case snd_soc_dapm_dai_in:
1079 case snd_soc_dapm_dai_out:
1080 break;
1081 default:
Liam Girdwood01d75842012-04-25 12:12:49 +01001082 continue;
Mark Brown46162742013-06-05 19:36:11 +01001083 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001084
1085 /* is there a valid BE rtd for this widget */
1086 be = dpcm_get_be(card, list->widgets[i], stream);
1087 if (!be) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001088 dev_err(fe->dev, "ASoC: no BE found for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001089 list->widgets[i]->name);
1090 continue;
1091 }
1092
1093 /* make sure BE is a real BE */
1094 if (!be->dai_link->no_pcm)
1095 continue;
1096
1097 /* don't connect if FE is not running */
Liam Girdwood23607022014-01-17 17:03:55 +00001098 if (!fe->dpcm[stream].runtime && !fe->fe_compr)
Liam Girdwood01d75842012-04-25 12:12:49 +01001099 continue;
1100
1101 /* newly connected FE and BE */
1102 err = dpcm_be_connect(fe, be, stream);
1103 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001104 dev_err(fe->dev, "ASoC: can't connect %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001105 list->widgets[i]->name);
1106 break;
1107 } else if (err == 0) /* already connected */
1108 continue;
1109
1110 /* new */
1111 be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1112 new++;
1113 }
1114
Liam Girdwood103d84a2012-11-19 14:39:15 +00001115 dev_dbg(fe->dev, "ASoC: found %d new BE paths\n", new);
Liam Girdwood01d75842012-04-25 12:12:49 +01001116 return new;
1117}
1118
1119/*
1120 * Find the corresponding BE DAIs that source or sink audio to this
1121 * FE substream.
1122 */
Liam Girdwood23607022014-01-17 17:03:55 +00001123int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
Liam Girdwood01d75842012-04-25 12:12:49 +01001124 int stream, struct snd_soc_dapm_widget_list **list, int new)
1125{
1126 if (new)
1127 return dpcm_add_paths(fe, stream, list);
1128 else
1129 return dpcm_prune_paths(fe, stream, list);
1130}
1131
Liam Girdwood23607022014-01-17 17:03:55 +00001132void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001133{
1134 struct snd_soc_dpcm *dpcm;
1135
1136 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
1137 dpcm->be->dpcm[stream].runtime_update =
1138 SND_SOC_DPCM_UPDATE_NO;
1139}
1140
1141static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe,
1142 int stream)
1143{
1144 struct snd_soc_dpcm *dpcm;
1145
1146 /* disable any enabled and non active backends */
1147 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1148
1149 struct snd_soc_pcm_runtime *be = dpcm->be;
1150 struct snd_pcm_substream *be_substream =
1151 snd_soc_dpcm_get_substream(be, stream);
1152
1153 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001154 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001155 stream ? "capture" : "playback",
1156 be->dpcm[stream].state);
1157
1158 if (--be->dpcm[stream].users != 0)
1159 continue;
1160
1161 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1162 continue;
1163
1164 soc_pcm_close(be_substream);
1165 be_substream->runtime = NULL;
1166 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1167 }
1168}
1169
Liam Girdwood23607022014-01-17 17:03:55 +00001170int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001171{
1172 struct snd_soc_dpcm *dpcm;
1173 int err, count = 0;
1174
1175 /* only startup BE DAIs that are either sinks or sources to this FE DAI */
1176 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1177
1178 struct snd_soc_pcm_runtime *be = dpcm->be;
1179 struct snd_pcm_substream *be_substream =
1180 snd_soc_dpcm_get_substream(be, stream);
1181
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001182 if (!be_substream) {
1183 dev_err(be->dev, "ASoC: no backend %s stream\n",
1184 stream ? "capture" : "playback");
1185 continue;
1186 }
1187
Liam Girdwood01d75842012-04-25 12:12:49 +01001188 /* is this op for this BE ? */
1189 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1190 continue;
1191
1192 /* first time the dpcm is open ? */
1193 if (be->dpcm[stream].users == DPCM_MAX_BE_USERS)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001194 dev_err(be->dev, "ASoC: too many users %s at open %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001195 stream ? "capture" : "playback",
1196 be->dpcm[stream].state);
1197
1198 if (be->dpcm[stream].users++ != 0)
1199 continue;
1200
1201 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
1202 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
1203 continue;
1204
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001205 dev_dbg(be->dev, "ASoC: open %s BE %s\n",
1206 stream ? "capture" : "playback", be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001207
1208 be_substream->runtime = be->dpcm[stream].runtime;
1209 err = soc_pcm_open(be_substream);
1210 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001211 dev_err(be->dev, "ASoC: BE open failed %d\n", err);
Liam Girdwood01d75842012-04-25 12:12:49 +01001212 be->dpcm[stream].users--;
1213 if (be->dpcm[stream].users < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001214 dev_err(be->dev, "ASoC: no users %s at unwind %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001215 stream ? "capture" : "playback",
1216 be->dpcm[stream].state);
1217
1218 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1219 goto unwind;
1220 }
1221
1222 be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1223 count++;
1224 }
1225
1226 return count;
1227
1228unwind:
1229 /* disable any enabled and non active backends */
1230 list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1231 struct snd_soc_pcm_runtime *be = dpcm->be;
1232 struct snd_pcm_substream *be_substream =
1233 snd_soc_dpcm_get_substream(be, stream);
1234
1235 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1236 continue;
1237
1238 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001239 dev_err(be->dev, "ASoC: no users %s at close %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001240 stream ? "capture" : "playback",
1241 be->dpcm[stream].state);
1242
1243 if (--be->dpcm[stream].users != 0)
1244 continue;
1245
1246 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1247 continue;
1248
1249 soc_pcm_close(be_substream);
1250 be_substream->runtime = NULL;
1251 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1252 }
1253
1254 return err;
1255}
1256
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001257static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
1258 struct snd_soc_pcm_stream *stream)
1259{
1260 runtime->hw.rate_min = stream->rate_min;
1261 runtime->hw.rate_max = stream->rate_max;
1262 runtime->hw.channels_min = stream->channels_min;
1263 runtime->hw.channels_max = stream->channels_max;
Lars-Peter Clausen002220a2014-01-06 14:19:07 +01001264 if (runtime->hw.formats)
1265 runtime->hw.formats &= stream->formats;
1266 else
1267 runtime->hw.formats = stream->formats;
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001268 runtime->hw.rates = stream->rates;
1269}
1270
Mark Brown45c0a182012-05-09 21:46:27 +01001271static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001272{
1273 struct snd_pcm_runtime *runtime = substream->runtime;
1274 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1275 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
1276 struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
1277
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001278 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1279 dpcm_init_runtime_hw(runtime, &cpu_dai_drv->playback);
1280 else
1281 dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture);
Liam Girdwood01d75842012-04-25 12:12:49 +01001282}
1283
1284static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
1285{
1286 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
1287 struct snd_pcm_runtime *runtime = fe_substream->runtime;
1288 int stream = fe_substream->stream, ret = 0;
1289
1290 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
1291
1292 ret = dpcm_be_dai_startup(fe, fe_substream->stream);
1293 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001294 dev_err(fe->dev,"ASoC: failed to start some BEs %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001295 goto be_err;
1296 }
1297
Liam Girdwood103d84a2012-11-19 14:39:15 +00001298 dev_dbg(fe->dev, "ASoC: open FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001299
1300 /* start the DAI frontend */
1301 ret = soc_pcm_open(fe_substream);
1302 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001303 dev_err(fe->dev,"ASoC: failed to start FE %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001304 goto unwind;
1305 }
1306
1307 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1308
1309 dpcm_set_fe_runtime(fe_substream);
1310 snd_pcm_limit_hw_rates(runtime);
1311
1312 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
1313 return 0;
1314
1315unwind:
1316 dpcm_be_dai_startup_unwind(fe, fe_substream->stream);
1317be_err:
1318 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
1319 return ret;
1320}
1321
Liam Girdwood23607022014-01-17 17:03:55 +00001322int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001323{
1324 struct snd_soc_dpcm *dpcm;
1325
1326 /* only shutdown BEs that are either sinks or sources to this FE DAI */
1327 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1328
1329 struct snd_soc_pcm_runtime *be = dpcm->be;
1330 struct snd_pcm_substream *be_substream =
1331 snd_soc_dpcm_get_substream(be, stream);
1332
1333 /* is this op for this BE ? */
1334 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1335 continue;
1336
1337 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001338 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001339 stream ? "capture" : "playback",
1340 be->dpcm[stream].state);
1341
1342 if (--be->dpcm[stream].users != 0)
1343 continue;
1344
1345 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
1346 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN))
1347 continue;
1348
Liam Girdwood103d84a2012-11-19 14:39:15 +00001349 dev_dbg(be->dev, "ASoC: close BE %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001350 dpcm->fe->dai_link->name);
1351
1352 soc_pcm_close(be_substream);
1353 be_substream->runtime = NULL;
1354
1355 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1356 }
1357 return 0;
1358}
1359
1360static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
1361{
1362 struct snd_soc_pcm_runtime *fe = substream->private_data;
1363 int stream = substream->stream;
1364
1365 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
1366
1367 /* shutdown the BEs */
1368 dpcm_be_dai_shutdown(fe, substream->stream);
1369
Liam Girdwood103d84a2012-11-19 14:39:15 +00001370 dev_dbg(fe->dev, "ASoC: close FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001371
1372 /* now shutdown the frontend */
1373 soc_pcm_close(substream);
1374
1375 /* run the stream event for each BE */
1376 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
1377
1378 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1379 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
1380 return 0;
1381}
1382
Liam Girdwood23607022014-01-17 17:03:55 +00001383int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001384{
1385 struct snd_soc_dpcm *dpcm;
1386
1387 /* only hw_params backends that are either sinks or sources
1388 * to this frontend DAI */
1389 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1390
1391 struct snd_soc_pcm_runtime *be = dpcm->be;
1392 struct snd_pcm_substream *be_substream =
1393 snd_soc_dpcm_get_substream(be, stream);
1394
1395 /* is this op for this BE ? */
1396 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1397 continue;
1398
1399 /* only free hw when no longer used - check all FEs */
1400 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1401 continue;
1402
1403 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1404 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
1405 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Patrick Lai08b27842012-12-19 19:36:02 -08001406 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
Liam Girdwood01d75842012-04-25 12:12:49 +01001407 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
1408 continue;
1409
Liam Girdwood103d84a2012-11-19 14:39:15 +00001410 dev_dbg(be->dev, "ASoC: hw_free BE %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001411 dpcm->fe->dai_link->name);
1412
1413 soc_pcm_hw_free(be_substream);
1414
1415 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1416 }
1417
1418 return 0;
1419}
1420
Mark Brown45c0a182012-05-09 21:46:27 +01001421static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001422{
1423 struct snd_soc_pcm_runtime *fe = substream->private_data;
1424 int err, stream = substream->stream;
1425
1426 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
1427 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
1428
Liam Girdwood103d84a2012-11-19 14:39:15 +00001429 dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001430
1431 /* call hw_free on the frontend */
1432 err = soc_pcm_hw_free(substream);
1433 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001434 dev_err(fe->dev,"ASoC: hw_free FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001435 fe->dai_link->name);
1436
1437 /* only hw_params backends that are either sinks or sources
1438 * to this frontend DAI */
1439 err = dpcm_be_dai_hw_free(fe, stream);
1440
1441 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1442 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
1443
1444 mutex_unlock(&fe->card->mutex);
1445 return 0;
1446}
1447
Liam Girdwood23607022014-01-17 17:03:55 +00001448int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001449{
1450 struct snd_soc_dpcm *dpcm;
1451 int ret;
1452
1453 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1454
1455 struct snd_soc_pcm_runtime *be = dpcm->be;
1456 struct snd_pcm_substream *be_substream =
1457 snd_soc_dpcm_get_substream(be, stream);
1458
1459 /* is this op for this BE ? */
1460 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1461 continue;
1462
1463 /* only allow hw_params() if no connected FEs are running */
1464 if (!snd_soc_dpcm_can_be_params(fe, be, stream))
1465 continue;
1466
1467 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
1468 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1469 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE))
1470 continue;
1471
Liam Girdwood103d84a2012-11-19 14:39:15 +00001472 dev_dbg(be->dev, "ASoC: hw_params BE %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001473 dpcm->fe->dai_link->name);
1474
1475 /* copy params for each dpcm */
1476 memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params,
1477 sizeof(struct snd_pcm_hw_params));
1478
1479 /* perform any hw_params fixups */
1480 if (be->dai_link->be_hw_params_fixup) {
1481 ret = be->dai_link->be_hw_params_fixup(be,
1482 &dpcm->hw_params);
1483 if (ret < 0) {
1484 dev_err(be->dev,
Liam Girdwood103d84a2012-11-19 14:39:15 +00001485 "ASoC: hw_params BE fixup failed %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001486 ret);
1487 goto unwind;
1488 }
1489 }
1490
1491 ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params);
1492 if (ret < 0) {
1493 dev_err(dpcm->be->dev,
Liam Girdwood103d84a2012-11-19 14:39:15 +00001494 "ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001495 goto unwind;
1496 }
1497
1498 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
1499 }
1500 return 0;
1501
1502unwind:
1503 /* disable any enabled and non active backends */
1504 list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1505 struct snd_soc_pcm_runtime *be = dpcm->be;
1506 struct snd_pcm_substream *be_substream =
1507 snd_soc_dpcm_get_substream(be, stream);
1508
1509 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1510 continue;
1511
1512 /* only allow hw_free() if no connected FEs are running */
1513 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1514 continue;
1515
1516 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
1517 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1518 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
1519 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
1520 continue;
1521
1522 soc_pcm_hw_free(be_substream);
1523 }
1524
1525 return ret;
1526}
1527
Mark Brown45c0a182012-05-09 21:46:27 +01001528static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
1529 struct snd_pcm_hw_params *params)
Liam Girdwood01d75842012-04-25 12:12:49 +01001530{
1531 struct snd_soc_pcm_runtime *fe = substream->private_data;
1532 int ret, stream = substream->stream;
1533
1534 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
1535 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
1536
1537 memcpy(&fe->dpcm[substream->stream].hw_params, params,
1538 sizeof(struct snd_pcm_hw_params));
1539 ret = dpcm_be_dai_hw_params(fe, substream->stream);
1540 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001541 dev_err(fe->dev,"ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001542 goto out;
1543 }
1544
Liam Girdwood103d84a2012-11-19 14:39:15 +00001545 dev_dbg(fe->dev, "ASoC: hw_params FE %s rate %d chan %x fmt %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001546 fe->dai_link->name, params_rate(params),
1547 params_channels(params), params_format(params));
1548
1549 /* call hw_params on the frontend */
1550 ret = soc_pcm_hw_params(substream, params);
1551 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001552 dev_err(fe->dev,"ASoC: hw_params FE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001553 dpcm_be_dai_hw_free(fe, stream);
1554 } else
1555 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
1556
1557out:
1558 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
1559 mutex_unlock(&fe->card->mutex);
1560 return ret;
1561}
1562
1563static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm,
1564 struct snd_pcm_substream *substream, int cmd)
1565{
1566 int ret;
1567
Liam Girdwood103d84a2012-11-19 14:39:15 +00001568 dev_dbg(dpcm->be->dev, "ASoC: trigger BE %s cmd %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001569 dpcm->fe->dai_link->name, cmd);
1570
1571 ret = soc_pcm_trigger(substream, cmd);
1572 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001573 dev_err(dpcm->be->dev,"ASoC: trigger BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001574
1575 return ret;
1576}
1577
Liam Girdwood23607022014-01-17 17:03:55 +00001578int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
Mark Brown45c0a182012-05-09 21:46:27 +01001579 int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01001580{
1581 struct snd_soc_dpcm *dpcm;
1582 int ret = 0;
1583
1584 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1585
1586 struct snd_soc_pcm_runtime *be = dpcm->be;
1587 struct snd_pcm_substream *be_substream =
1588 snd_soc_dpcm_get_substream(be, stream);
1589
1590 /* is this op for this BE ? */
1591 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1592 continue;
1593
1594 switch (cmd) {
1595 case SNDRV_PCM_TRIGGER_START:
1596 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
1597 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
1598 continue;
1599
1600 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
1601 if (ret)
1602 return ret;
1603
1604 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
1605 break;
1606 case SNDRV_PCM_TRIGGER_RESUME:
1607 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
1608 continue;
1609
1610 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
1611 if (ret)
1612 return ret;
1613
1614 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
1615 break;
1616 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1617 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
1618 continue;
1619
1620 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
1621 if (ret)
1622 return ret;
1623
1624 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
1625 break;
1626 case SNDRV_PCM_TRIGGER_STOP:
1627 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
1628 continue;
1629
1630 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1631 continue;
1632
1633 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
1634 if (ret)
1635 return ret;
1636
1637 be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
1638 break;
1639 case SNDRV_PCM_TRIGGER_SUSPEND:
1640 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)
1641 continue;
1642
1643 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1644 continue;
1645
1646 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
1647 if (ret)
1648 return ret;
1649
1650 be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND;
1651 break;
1652 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
1653 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
1654 continue;
1655
1656 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1657 continue;
1658
1659 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
1660 if (ret)
1661 return ret;
1662
1663 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
1664 break;
1665 }
1666 }
1667
1668 return ret;
1669}
1670EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
1671
Mark Brown45c0a182012-05-09 21:46:27 +01001672static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01001673{
1674 struct snd_soc_pcm_runtime *fe = substream->private_data;
1675 int stream = substream->stream, ret;
1676 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
1677
1678 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
1679
1680 switch (trigger) {
1681 case SND_SOC_DPCM_TRIGGER_PRE:
1682 /* call trigger on the frontend before the backend. */
1683
Liam Girdwood103d84a2012-11-19 14:39:15 +00001684 dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001685 fe->dai_link->name, cmd);
1686
1687 ret = soc_pcm_trigger(substream, cmd);
1688 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001689 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001690 goto out;
1691 }
1692
1693 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
1694 break;
1695 case SND_SOC_DPCM_TRIGGER_POST:
1696 /* call trigger on the frontend after the backend. */
1697
1698 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
1699 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001700 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001701 goto out;
1702 }
1703
Liam Girdwood103d84a2012-11-19 14:39:15 +00001704 dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001705 fe->dai_link->name, cmd);
1706
1707 ret = soc_pcm_trigger(substream, cmd);
1708 break;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001709 case SND_SOC_DPCM_TRIGGER_BESPOKE:
1710 /* bespoke trigger() - handles both FE and BEs */
1711
Liam Girdwood103d84a2012-11-19 14:39:15 +00001712 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd %d\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001713 fe->dai_link->name, cmd);
1714
1715 ret = soc_pcm_bespoke_trigger(substream, cmd);
1716 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001717 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001718 goto out;
1719 }
1720 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01001721 default:
Liam Girdwood103d84a2012-11-19 14:39:15 +00001722 dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd,
Liam Girdwood01d75842012-04-25 12:12:49 +01001723 fe->dai_link->name);
1724 ret = -EINVAL;
1725 goto out;
1726 }
1727
1728 switch (cmd) {
1729 case SNDRV_PCM_TRIGGER_START:
1730 case SNDRV_PCM_TRIGGER_RESUME:
1731 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1732 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
1733 break;
1734 case SNDRV_PCM_TRIGGER_STOP:
1735 case SNDRV_PCM_TRIGGER_SUSPEND:
1736 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
1737 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
1738 break;
1739 }
1740
1741out:
1742 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
1743 return ret;
1744}
1745
Liam Girdwood23607022014-01-17 17:03:55 +00001746int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001747{
1748 struct snd_soc_dpcm *dpcm;
1749 int ret = 0;
1750
1751 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1752
1753 struct snd_soc_pcm_runtime *be = dpcm->be;
1754 struct snd_pcm_substream *be_substream =
1755 snd_soc_dpcm_get_substream(be, stream);
1756
1757 /* is this op for this BE ? */
1758 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1759 continue;
1760
1761 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1762 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
1763 continue;
1764
Liam Girdwood103d84a2012-11-19 14:39:15 +00001765 dev_dbg(be->dev, "ASoC: prepare BE %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001766 dpcm->fe->dai_link->name);
1767
1768 ret = soc_pcm_prepare(be_substream);
1769 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001770 dev_err(be->dev, "ASoC: backend prepare failed %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001771 ret);
1772 break;
1773 }
1774
1775 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
1776 }
1777 return ret;
1778}
1779
Mark Brown45c0a182012-05-09 21:46:27 +01001780static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001781{
1782 struct snd_soc_pcm_runtime *fe = substream->private_data;
1783 int stream = substream->stream, ret = 0;
1784
1785 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
1786
Liam Girdwood103d84a2012-11-19 14:39:15 +00001787 dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001788
1789 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
1790
1791 /* there is no point preparing this FE if there are no BEs */
1792 if (list_empty(&fe->dpcm[stream].be_clients)) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001793 dev_err(fe->dev, "ASoC: no backend DAIs enabled for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001794 fe->dai_link->name);
1795 ret = -EINVAL;
1796 goto out;
1797 }
1798
1799 ret = dpcm_be_dai_prepare(fe, substream->stream);
1800 if (ret < 0)
1801 goto out;
1802
1803 /* call prepare on the frontend */
1804 ret = soc_pcm_prepare(substream);
1805 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001806 dev_err(fe->dev,"ASoC: prepare FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001807 fe->dai_link->name);
1808 goto out;
1809 }
1810
1811 /* run the stream event for each BE */
1812 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
1813 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
1814
1815out:
1816 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
1817 mutex_unlock(&fe->card->mutex);
1818
1819 return ret;
1820}
1821
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01001822static int soc_pcm_ioctl(struct snd_pcm_substream *substream,
1823 unsigned int cmd, void *arg)
1824{
1825 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1826 struct snd_soc_platform *platform = rtd->platform;
1827
Mark Brownc5914b02013-10-30 17:47:39 -07001828 if (platform->driver->ops && platform->driver->ops->ioctl)
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01001829 return platform->driver->ops->ioctl(substream, cmd, arg);
1830 return snd_pcm_lib_ioctl(substream, cmd, arg);
1831}
1832
Liam Girdwood618dae12012-04-25 12:12:51 +01001833static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
1834{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001835 struct snd_pcm_substream *substream =
1836 snd_soc_dpcm_get_substream(fe, stream);
1837 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01001838 int err;
Liam Girdwood01d75842012-04-25 12:12:49 +01001839
Liam Girdwood103d84a2012-11-19 14:39:15 +00001840 dev_dbg(fe->dev, "ASoC: runtime %s close on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01001841 stream ? "capture" : "playback", fe->dai_link->name);
1842
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001843 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
1844 /* call bespoke trigger - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00001845 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001846 fe->dai_link->name);
1847
1848 err = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
1849 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001850 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001851 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001852 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001853 fe->dai_link->name);
1854
1855 err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
1856 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001857 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001858 }
Liam Girdwood618dae12012-04-25 12:12:51 +01001859
1860 err = dpcm_be_dai_hw_free(fe, stream);
1861 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001862 dev_err(fe->dev,"ASoC: hw_free FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01001863
1864 err = dpcm_be_dai_shutdown(fe, stream);
1865 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001866 dev_err(fe->dev,"ASoC: shutdown FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01001867
1868 /* run the stream event for each BE */
1869 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
1870
1871 return 0;
1872}
1873
1874static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
1875{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001876 struct snd_pcm_substream *substream =
1877 snd_soc_dpcm_get_substream(fe, stream);
Liam Girdwood618dae12012-04-25 12:12:51 +01001878 struct snd_soc_dpcm *dpcm;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001879 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01001880 int ret;
1881
Liam Girdwood103d84a2012-11-19 14:39:15 +00001882 dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01001883 stream ? "capture" : "playback", fe->dai_link->name);
1884
1885 /* Only start the BE if the FE is ready */
1886 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
1887 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE)
1888 return -EINVAL;
1889
1890 /* startup must always be called for new BEs */
1891 ret = dpcm_be_dai_startup(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03001892 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01001893 goto disconnect;
Liam Girdwood618dae12012-04-25 12:12:51 +01001894
1895 /* keep going if FE state is > open */
1896 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN)
1897 return 0;
1898
1899 ret = dpcm_be_dai_hw_params(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03001900 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01001901 goto close;
Liam Girdwood618dae12012-04-25 12:12:51 +01001902
1903 /* keep going if FE state is > hw_params */
1904 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS)
1905 return 0;
1906
1907
1908 ret = dpcm_be_dai_prepare(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03001909 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01001910 goto hw_free;
Liam Girdwood618dae12012-04-25 12:12:51 +01001911
1912 /* run the stream event for each BE */
1913 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
1914
1915 /* keep going if FE state is > prepare */
1916 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE ||
1917 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP)
1918 return 0;
1919
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001920 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
1921 /* call trigger on the frontend - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00001922 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001923 fe->dai_link->name);
Liam Girdwood618dae12012-04-25 12:12:51 +01001924
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001925 ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
1926 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001927 dev_err(fe->dev,"ASoC: bespoke trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001928 goto hw_free;
1929 }
1930 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001931 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001932 fe->dai_link->name);
1933
1934 ret = dpcm_be_dai_trigger(fe, stream,
1935 SNDRV_PCM_TRIGGER_START);
1936 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001937 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001938 goto hw_free;
1939 }
Liam Girdwood618dae12012-04-25 12:12:51 +01001940 }
1941
1942 return 0;
1943
1944hw_free:
1945 dpcm_be_dai_hw_free(fe, stream);
1946close:
1947 dpcm_be_dai_shutdown(fe, stream);
1948disconnect:
1949 /* disconnect any non started BEs */
1950 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1951 struct snd_soc_pcm_runtime *be = dpcm->be;
1952 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
1953 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
1954 }
1955
1956 return ret;
1957}
1958
1959static int dpcm_run_new_update(struct snd_soc_pcm_runtime *fe, int stream)
1960{
1961 int ret;
1962
1963 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1964 ret = dpcm_run_update_startup(fe, stream);
1965 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001966 dev_err(fe->dev, "ASoC: failed to startup some BEs\n");
Liam Girdwood618dae12012-04-25 12:12:51 +01001967 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
1968
1969 return ret;
1970}
1971
1972static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream)
1973{
1974 int ret;
1975
1976 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1977 ret = dpcm_run_update_shutdown(fe, stream);
1978 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001979 dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n");
Liam Girdwood618dae12012-04-25 12:12:51 +01001980 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
1981
1982 return ret;
1983}
1984
1985/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
1986 * any DAI links.
1987 */
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02001988int soc_dpcm_runtime_update(struct snd_soc_card *card)
Liam Girdwood618dae12012-04-25 12:12:51 +01001989{
Liam Girdwood618dae12012-04-25 12:12:51 +01001990 int i, old, new, paths;
1991
Liam Girdwood618dae12012-04-25 12:12:51 +01001992 mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
1993 for (i = 0; i < card->num_rtd; i++) {
1994 struct snd_soc_dapm_widget_list *list;
1995 struct snd_soc_pcm_runtime *fe = &card->rtd[i];
1996
1997 /* make sure link is FE */
1998 if (!fe->dai_link->dynamic)
1999 continue;
2000
2001 /* only check active links */
2002 if (!fe->cpu_dai->active)
2003 continue;
2004
2005 /* DAPM sync will call this to update DSP paths */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002006 dev_dbg(fe->dev, "ASoC: DPCM runtime update for FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002007 fe->dai_link->name);
2008
2009 /* skip if FE doesn't have playback capability */
2010 if (!fe->cpu_dai->driver->playback.channels_min)
2011 goto capture;
2012
2013 paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list);
2014 if (paths < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002015 dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002016 fe->dai_link->name, "playback");
2017 mutex_unlock(&card->mutex);
2018 return paths;
2019 }
2020
2021 /* update any new playback paths */
2022 new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 1);
2023 if (new) {
2024 dpcm_run_new_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
2025 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
2026 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
2027 }
2028
2029 /* update any old playback paths */
2030 old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 0);
2031 if (old) {
2032 dpcm_run_old_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
2033 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
2034 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
2035 }
2036
2037capture:
2038 /* skip if FE doesn't have capture capability */
2039 if (!fe->cpu_dai->driver->capture.channels_min)
2040 continue;
2041
2042 paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list);
2043 if (paths < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002044 dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002045 fe->dai_link->name, "capture");
2046 mutex_unlock(&card->mutex);
2047 return paths;
2048 }
2049
2050 /* update any new capture paths */
2051 new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 1);
2052 if (new) {
2053 dpcm_run_new_update(fe, SNDRV_PCM_STREAM_CAPTURE);
2054 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
2055 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
2056 }
2057
2058 /* update any old capture paths */
2059 old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 0);
2060 if (old) {
2061 dpcm_run_old_update(fe, SNDRV_PCM_STREAM_CAPTURE);
2062 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
2063 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
2064 }
2065
2066 dpcm_path_put(&list);
2067 }
2068
2069 mutex_unlock(&card->mutex);
2070 return 0;
2071}
Liam Girdwood01d75842012-04-25 12:12:49 +01002072int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute)
2073{
2074 struct snd_soc_dpcm *dpcm;
2075 struct list_head *clients =
2076 &fe->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients;
2077
2078 list_for_each_entry(dpcm, clients, list_be) {
2079
2080 struct snd_soc_pcm_runtime *be = dpcm->be;
2081 struct snd_soc_dai *dai = be->codec_dai;
2082 struct snd_soc_dai_driver *drv = dai->driver;
2083
2084 if (be->dai_link->ignore_suspend)
2085 continue;
2086
Liam Girdwood103d84a2012-11-19 14:39:15 +00002087 dev_dbg(be->dev, "ASoC: BE digital mute %s\n", be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002088
Mark Brownc5914b02013-10-30 17:47:39 -07002089 if (drv->ops && drv->ops->digital_mute && dai->playback_active)
2090 drv->ops->digital_mute(dai, mute);
Liam Girdwood01d75842012-04-25 12:12:49 +01002091 }
2092
2093 return 0;
2094}
2095
Mark Brown45c0a182012-05-09 21:46:27 +01002096static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002097{
2098 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
2099 struct snd_soc_dpcm *dpcm;
2100 struct snd_soc_dapm_widget_list *list;
2101 int ret;
2102 int stream = fe_substream->stream;
2103
2104 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2105 fe->dpcm[stream].runtime = fe_substream->runtime;
2106
2107 if (dpcm_path_get(fe, stream, &list) <= 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002108 dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002109 fe->dai_link->name, stream ? "capture" : "playback");
Liam Girdwood01d75842012-04-25 12:12:49 +01002110 }
2111
2112 /* calculate valid and active FE <-> BE dpcms */
2113 dpcm_process_paths(fe, stream, &list, 1);
2114
2115 ret = dpcm_fe_dai_startup(fe_substream);
2116 if (ret < 0) {
2117 /* clean up all links */
2118 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
2119 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2120
2121 dpcm_be_disconnect(fe, stream);
2122 fe->dpcm[stream].runtime = NULL;
2123 }
2124
2125 dpcm_clear_pending_state(fe, stream);
2126 dpcm_path_put(&list);
2127 mutex_unlock(&fe->card->mutex);
2128 return ret;
2129}
2130
Mark Brown45c0a182012-05-09 21:46:27 +01002131static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002132{
2133 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
2134 struct snd_soc_dpcm *dpcm;
2135 int stream = fe_substream->stream, ret;
2136
2137 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2138 ret = dpcm_fe_dai_shutdown(fe_substream);
2139
2140 /* mark FE's links ready to prune */
2141 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
2142 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2143
2144 dpcm_be_disconnect(fe, stream);
2145
2146 fe->dpcm[stream].runtime = NULL;
2147 mutex_unlock(&fe->card->mutex);
2148 return ret;
2149}
2150
Liam Girdwoodddee6272011-06-09 14:45:53 +01002151/* create a new pcm */
2152int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
2153{
Liam Girdwoodddee6272011-06-09 14:45:53 +01002154 struct snd_soc_platform *platform = rtd->platform;
2155 struct snd_soc_dai *codec_dai = rtd->codec_dai;
2156 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
2157 struct snd_pcm *pcm;
2158 char new_name[64];
2159 int ret = 0, playback = 0, capture = 0;
2160
Liam Girdwood01d75842012-04-25 12:12:49 +01002161 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
Liam Girdwood1e9de422014-01-07 17:51:42 +00002162 playback = rtd->dai_link->dpcm_playback;
2163 capture = rtd->dai_link->dpcm_capture;
Liam Girdwood01d75842012-04-25 12:12:49 +01002164 } else {
Mark Brown05679092013-06-01 23:13:53 +01002165 if (codec_dai->driver->playback.channels_min &&
2166 cpu_dai->driver->playback.channels_min)
Liam Girdwood01d75842012-04-25 12:12:49 +01002167 playback = 1;
Mark Brown05679092013-06-01 23:13:53 +01002168 if (codec_dai->driver->capture.channels_min &&
2169 cpu_dai->driver->capture.channels_min)
Liam Girdwood01d75842012-04-25 12:12:49 +01002170 capture = 1;
2171 }
Sangsu Parka5002312012-01-02 17:15:10 +09002172
Fabio Estevamd6bead02013-08-29 10:32:13 -03002173 if (rtd->dai_link->playback_only) {
2174 playback = 1;
2175 capture = 0;
2176 }
2177
2178 if (rtd->dai_link->capture_only) {
2179 playback = 0;
2180 capture = 1;
2181 }
2182
Liam Girdwood01d75842012-04-25 12:12:49 +01002183 /* create the PCM */
2184 if (rtd->dai_link->no_pcm) {
2185 snprintf(new_name, sizeof(new_name), "(%s)",
2186 rtd->dai_link->stream_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002187
Liam Girdwood01d75842012-04-25 12:12:49 +01002188 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
2189 playback, capture, &pcm);
2190 } else {
2191 if (rtd->dai_link->dynamic)
2192 snprintf(new_name, sizeof(new_name), "%s (*)",
2193 rtd->dai_link->stream_name);
2194 else
2195 snprintf(new_name, sizeof(new_name), "%s %s-%d",
2196 rtd->dai_link->stream_name, codec_dai->name, num);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002197
Liam Girdwood01d75842012-04-25 12:12:49 +01002198 ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
2199 capture, &pcm);
2200 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01002201 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002202 dev_err(rtd->card->dev, "ASoC: can't create pcm for %s\n",
Liam Girdwood5cb9b742012-07-06 16:54:52 +01002203 rtd->dai_link->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002204 return ret;
2205 }
Liam Girdwood103d84a2012-11-19 14:39:15 +00002206 dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002207
2208 /* DAPM dai link stream work */
2209 INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
2210
2211 rtd->pcm = pcm;
2212 pcm->private_data = rtd;
Liam Girdwood01d75842012-04-25 12:12:49 +01002213
2214 if (rtd->dai_link->no_pcm) {
2215 if (playback)
2216 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
2217 if (capture)
2218 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
2219 goto out;
2220 }
2221
2222 /* ASoC PCM operations */
2223 if (rtd->dai_link->dynamic) {
2224 rtd->ops.open = dpcm_fe_dai_open;
2225 rtd->ops.hw_params = dpcm_fe_dai_hw_params;
2226 rtd->ops.prepare = dpcm_fe_dai_prepare;
2227 rtd->ops.trigger = dpcm_fe_dai_trigger;
2228 rtd->ops.hw_free = dpcm_fe_dai_hw_free;
2229 rtd->ops.close = dpcm_fe_dai_close;
2230 rtd->ops.pointer = soc_pcm_pointer;
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01002231 rtd->ops.ioctl = soc_pcm_ioctl;
Liam Girdwood01d75842012-04-25 12:12:49 +01002232 } else {
2233 rtd->ops.open = soc_pcm_open;
2234 rtd->ops.hw_params = soc_pcm_hw_params;
2235 rtd->ops.prepare = soc_pcm_prepare;
2236 rtd->ops.trigger = soc_pcm_trigger;
2237 rtd->ops.hw_free = soc_pcm_hw_free;
2238 rtd->ops.close = soc_pcm_close;
2239 rtd->ops.pointer = soc_pcm_pointer;
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01002240 rtd->ops.ioctl = soc_pcm_ioctl;
Liam Girdwood01d75842012-04-25 12:12:49 +01002241 }
2242
Liam Girdwoodddee6272011-06-09 14:45:53 +01002243 if (platform->driver->ops) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002244 rtd->ops.ack = platform->driver->ops->ack;
2245 rtd->ops.copy = platform->driver->ops->copy;
2246 rtd->ops.silence = platform->driver->ops->silence;
2247 rtd->ops.page = platform->driver->ops->page;
2248 rtd->ops.mmap = platform->driver->ops->mmap;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002249 }
2250
2251 if (playback)
Liam Girdwood01d75842012-04-25 12:12:49 +01002252 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002253
2254 if (capture)
Liam Girdwood01d75842012-04-25 12:12:49 +01002255 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002256
2257 if (platform->driver->pcm_new) {
2258 ret = platform->driver->pcm_new(rtd);
2259 if (ret < 0) {
Mark Brownb1bc7b32012-09-26 14:25:17 +01002260 dev_err(platform->dev,
2261 "ASoC: pcm constructor failed: %d\n",
2262 ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002263 return ret;
2264 }
2265 }
2266
2267 pcm->private_free = platform->driver->pcm_free;
Liam Girdwood01d75842012-04-25 12:12:49 +01002268out:
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03002269 dev_info(rtd->card->dev, "%s <-> %s mapping ok\n", codec_dai->name,
Liam Girdwoodddee6272011-06-09 14:45:53 +01002270 cpu_dai->name);
2271 return ret;
2272}
Liam Girdwood01d75842012-04-25 12:12:49 +01002273
2274/* is the current PCM operation for this FE ? */
2275int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream)
2276{
2277 if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE)
2278 return 1;
2279 return 0;
2280}
2281EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update);
2282
2283/* is the current PCM operation for this BE ? */
2284int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
2285 struct snd_soc_pcm_runtime *be, int stream)
2286{
2287 if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) ||
2288 ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) &&
2289 be->dpcm[stream].runtime_update))
2290 return 1;
2291 return 0;
2292}
2293EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update);
2294
2295/* get the substream for this BE */
2296struct snd_pcm_substream *
2297 snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream)
2298{
2299 return be->pcm->streams[stream].substream;
2300}
2301EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream);
2302
2303/* get the BE runtime state */
2304enum snd_soc_dpcm_state
2305 snd_soc_dpcm_be_get_state(struct snd_soc_pcm_runtime *be, int stream)
2306{
2307 return be->dpcm[stream].state;
2308}
2309EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_get_state);
2310
2311/* set the BE runtime state */
2312void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be,
2313 int stream, enum snd_soc_dpcm_state state)
2314{
2315 be->dpcm[stream].state = state;
2316}
2317EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_set_state);
2318
2319/*
2320 * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE
2321 * are not running, paused or suspended for the specified stream direction.
2322 */
2323int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
2324 struct snd_soc_pcm_runtime *be, int stream)
2325{
2326 struct snd_soc_dpcm *dpcm;
2327 int state;
2328
2329 list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {
2330
2331 if (dpcm->fe == fe)
2332 continue;
2333
2334 state = dpcm->fe->dpcm[stream].state;
2335 if (state == SND_SOC_DPCM_STATE_START ||
2336 state == SND_SOC_DPCM_STATE_PAUSED ||
2337 state == SND_SOC_DPCM_STATE_SUSPEND)
2338 return 0;
2339 }
2340
2341 /* it's safe to free/stop this BE DAI */
2342 return 1;
2343}
2344EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop);
2345
2346/*
2347 * We can only change hw params a BE DAI if any of it's FE are not prepared,
2348 * running, paused or suspended for the specified stream direction.
2349 */
2350int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
2351 struct snd_soc_pcm_runtime *be, int stream)
2352{
2353 struct snd_soc_dpcm *dpcm;
2354 int state;
2355
2356 list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {
2357
2358 if (dpcm->fe == fe)
2359 continue;
2360
2361 state = dpcm->fe->dpcm[stream].state;
2362 if (state == SND_SOC_DPCM_STATE_START ||
2363 state == SND_SOC_DPCM_STATE_PAUSED ||
2364 state == SND_SOC_DPCM_STATE_SUSPEND ||
2365 state == SND_SOC_DPCM_STATE_PREPARE)
2366 return 0;
2367 }
2368
2369 /* it's safe to change hw_params */
2370 return 1;
2371}
2372EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01002373
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002374int snd_soc_platform_trigger(struct snd_pcm_substream *substream,
2375 int cmd, struct snd_soc_platform *platform)
2376{
Mark Brownc5914b02013-10-30 17:47:39 -07002377 if (platform->driver->ops && platform->driver->ops->trigger)
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002378 return platform->driver->ops->trigger(substream, cmd);
2379 return 0;
2380}
2381EXPORT_SYMBOL_GPL(snd_soc_platform_trigger);
2382
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01002383#ifdef CONFIG_DEBUG_FS
2384static char *dpcm_state_string(enum snd_soc_dpcm_state state)
2385{
2386 switch (state) {
2387 case SND_SOC_DPCM_STATE_NEW:
2388 return "new";
2389 case SND_SOC_DPCM_STATE_OPEN:
2390 return "open";
2391 case SND_SOC_DPCM_STATE_HW_PARAMS:
2392 return "hw_params";
2393 case SND_SOC_DPCM_STATE_PREPARE:
2394 return "prepare";
2395 case SND_SOC_DPCM_STATE_START:
2396 return "start";
2397 case SND_SOC_DPCM_STATE_STOP:
2398 return "stop";
2399 case SND_SOC_DPCM_STATE_SUSPEND:
2400 return "suspend";
2401 case SND_SOC_DPCM_STATE_PAUSED:
2402 return "paused";
2403 case SND_SOC_DPCM_STATE_HW_FREE:
2404 return "hw_free";
2405 case SND_SOC_DPCM_STATE_CLOSE:
2406 return "close";
2407 }
2408
2409 return "unknown";
2410}
2411
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01002412static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
2413 int stream, char *buf, size_t size)
2414{
2415 struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params;
2416 struct snd_soc_dpcm *dpcm;
2417 ssize_t offset = 0;
2418
2419 /* FE state */
2420 offset += snprintf(buf + offset, size - offset,
2421 "[%s - %s]\n", fe->dai_link->name,
2422 stream ? "Capture" : "Playback");
2423
2424 offset += snprintf(buf + offset, size - offset, "State: %s\n",
2425 dpcm_state_string(fe->dpcm[stream].state));
2426
2427 if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
2428 (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
2429 offset += snprintf(buf + offset, size - offset,
2430 "Hardware Params: "
2431 "Format = %s, Channels = %d, Rate = %d\n",
2432 snd_pcm_format_name(params_format(params)),
2433 params_channels(params),
2434 params_rate(params));
2435
2436 /* BEs state */
2437 offset += snprintf(buf + offset, size - offset, "Backends:\n");
2438
2439 if (list_empty(&fe->dpcm[stream].be_clients)) {
2440 offset += snprintf(buf + offset, size - offset,
2441 " No active DSP links\n");
2442 goto out;
2443 }
2444
2445 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
2446 struct snd_soc_pcm_runtime *be = dpcm->be;
2447 params = &dpcm->hw_params;
2448
2449 offset += snprintf(buf + offset, size - offset,
2450 "- %s\n", be->dai_link->name);
2451
2452 offset += snprintf(buf + offset, size - offset,
2453 " State: %s\n",
2454 dpcm_state_string(be->dpcm[stream].state));
2455
2456 if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
2457 (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
2458 offset += snprintf(buf + offset, size - offset,
2459 " Hardware Params: "
2460 "Format = %s, Channels = %d, Rate = %d\n",
2461 snd_pcm_format_name(params_format(params)),
2462 params_channels(params),
2463 params_rate(params));
2464 }
2465
2466out:
2467 return offset;
2468}
2469
2470static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf,
2471 size_t count, loff_t *ppos)
2472{
2473 struct snd_soc_pcm_runtime *fe = file->private_data;
2474 ssize_t out_count = PAGE_SIZE, offset = 0, ret = 0;
2475 char *buf;
2476
2477 buf = kmalloc(out_count, GFP_KERNEL);
2478 if (!buf)
2479 return -ENOMEM;
2480
2481 if (fe->cpu_dai->driver->playback.channels_min)
2482 offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_PLAYBACK,
2483 buf + offset, out_count - offset);
2484
2485 if (fe->cpu_dai->driver->capture.channels_min)
2486 offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_CAPTURE,
2487 buf + offset, out_count - offset);
2488
Liam Girdwoodf57b8482012-04-27 11:33:46 +01002489 ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01002490
Liam Girdwoodf57b8482012-04-27 11:33:46 +01002491 kfree(buf);
2492 return ret;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01002493}
2494
2495static const struct file_operations dpcm_state_fops = {
Liam Girdwoodf57b8482012-04-27 11:33:46 +01002496 .open = simple_open,
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01002497 .read = dpcm_state_read_file,
2498 .llseek = default_llseek,
2499};
2500
2501int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
2502{
Mark Brownb3bba9a2012-05-08 10:33:47 +01002503 if (!rtd->dai_link)
2504 return 0;
2505
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01002506 rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name,
2507 rtd->card->debugfs_card_root);
2508 if (!rtd->debugfs_dpcm_root) {
2509 dev_dbg(rtd->dev,
2510 "ASoC: Failed to create dpcm debugfs directory %s\n",
2511 rtd->dai_link->name);
2512 return -EINVAL;
2513 }
2514
Liam Girdwoodf57b8482012-04-27 11:33:46 +01002515 rtd->debugfs_dpcm_state = debugfs_create_file("state", 0444,
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01002516 rtd->debugfs_dpcm_root,
2517 rtd, &dpcm_state_fops);
2518
2519 return 0;
2520}
2521#endif