blob: ce7297c375372c69e000c410f2b2eb32010ac61f [file] [log] [blame]
Kuninori Morimotoed517582018-07-02 06:22:44 +00001// SPDX-License-Identifier: GPL-2.0+
2//
3// soc-pcm.c -- ALSA SoC PCM
4//
5// Copyright 2005 Wolfson Microelectronics PLC.
6// Copyright 2005 Openedhand Ltd.
7// Copyright (C) 2010 Slimlogic Ltd.
8// Copyright (C) 2010 Texas Instruments Inc.
9//
10// Authors: Liam Girdwood <lrg@ti.com>
11// Mark Brown <broonie@opensource.wolfsonmicro.com>
Liam Girdwoodddee6272011-06-09 14:45:53 +010012
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/delay.h>
Nicolin Chen988e8cc2013-11-04 14:57:31 +080016#include <linux/pinctrl/consumer.h>
Mark Brownd6652ef2011-12-03 20:14:31 +000017#include <linux/pm_runtime.h>
Ranjani Sridharan52034ad2019-04-05 09:57:09 -070018#include <linux/module.h>
Liam Girdwoodddee6272011-06-09 14:45:53 +010019#include <linux/slab.h>
20#include <linux/workqueue.h>
Liam Girdwood01d75842012-04-25 12:12:49 +010021#include <linux/export.h>
Liam Girdwoodf86dcef2012-04-25 12:12:50 +010022#include <linux/debugfs.h>
Liam Girdwoodddee6272011-06-09 14:45:53 +010023#include <sound/core.h>
24#include <sound/pcm.h>
25#include <sound/pcm_params.h>
26#include <sound/soc.h>
Liam Girdwood01d75842012-04-25 12:12:49 +010027#include <sound/soc-dpcm.h>
Liam Girdwoodddee6272011-06-09 14:45:53 +010028#include <sound/initval.h>
29
Liam Girdwood01d75842012-04-25 12:12:49 +010030#define DPCM_MAX_BE_USERS 8
31
Lars-Peter Clausen90996f42013-05-14 11:05:30 +020032/**
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010033 * snd_soc_runtime_activate() - Increment active count for PCM runtime components
34 * @rtd: ASoC PCM runtime that is activated
35 * @stream: Direction of the PCM stream
36 *
37 * Increments the active count for all the DAIs and components attached to a PCM
38 * runtime. Should typically be called when a stream is opened.
39 *
40 * Must be called with the rtd->pcm_mutex being held
41 */
42void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream)
43{
44 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +000045 struct snd_soc_dai *codec_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +020046 int i;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010047
48 lockdep_assert_held(&rtd->pcm_mutex);
49
50 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
51 cpu_dai->playback_active++;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +000052 for_each_rtd_codec_dai(rtd, i, codec_dai)
53 codec_dai->playback_active++;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010054 } else {
55 cpu_dai->capture_active++;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +000056 for_each_rtd_codec_dai(rtd, i, codec_dai)
57 codec_dai->capture_active++;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010058 }
59
60 cpu_dai->active++;
Lars-Peter Clausencdde4cc2014-03-05 13:17:47 +010061 cpu_dai->component->active++;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +000062 for_each_rtd_codec_dai(rtd, i, codec_dai) {
63 codec_dai->active++;
64 codec_dai->component->active++;
Benoit Cousson2e5894d2014-07-08 23:19:35 +020065 }
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010066}
67
68/**
69 * snd_soc_runtime_deactivate() - Decrement active count for PCM runtime components
70 * @rtd: ASoC PCM runtime that is deactivated
71 * @stream: Direction of the PCM stream
72 *
73 * Decrements the active count for all the DAIs and components attached to a PCM
74 * runtime. Should typically be called when a stream is closed.
75 *
76 * Must be called with the rtd->pcm_mutex being held
77 */
78void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream)
79{
80 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +000081 struct snd_soc_dai *codec_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +020082 int i;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010083
84 lockdep_assert_held(&rtd->pcm_mutex);
85
86 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
87 cpu_dai->playback_active--;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +000088 for_each_rtd_codec_dai(rtd, i, codec_dai)
89 codec_dai->playback_active--;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010090 } else {
91 cpu_dai->capture_active--;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +000092 for_each_rtd_codec_dai(rtd, i, codec_dai)
93 codec_dai->capture_active--;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010094 }
95
96 cpu_dai->active--;
Lars-Peter Clausencdde4cc2014-03-05 13:17:47 +010097 cpu_dai->component->active--;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +000098 for_each_rtd_codec_dai(rtd, i, codec_dai) {
99 codec_dai->component->active--;
100 codec_dai->active--;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200101 }
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100102}
103
104/**
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100105 * snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay
106 * @rtd: The ASoC PCM runtime that should be checked.
107 *
108 * This function checks whether the power down delay should be ignored for a
109 * specific PCM runtime. Returns true if the delay is 0, if it the DAI link has
110 * been configured to ignore the delay, or if none of the components benefits
111 * from having the delay.
112 */
113bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
114{
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000115 struct snd_soc_rtdcom_list *rtdcom;
116 struct snd_soc_component *component;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200117 bool ignore = true;
118
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100119 if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
120 return true;
121
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000122 for_each_rtdcom(rtd, rtdcom) {
123 component = rtdcom->component;
124
Kuninori Morimoto72c38182018-01-19 05:21:19 +0000125 ignore &= !component->driver->use_pmdown_time;
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000126 }
127
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000128 return ignore;
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100129}
130
131/**
Lars-Peter Clausen90996f42013-05-14 11:05:30 +0200132 * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
133 * @substream: the pcm substream
134 * @hw: the hardware parameters
135 *
136 * Sets the substream runtime hardware parameters.
137 */
138int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
139 const struct snd_pcm_hardware *hw)
140{
141 struct snd_pcm_runtime *runtime = substream->runtime;
142 runtime->hw.info = hw->info;
143 runtime->hw.formats = hw->formats;
144 runtime->hw.period_bytes_min = hw->period_bytes_min;
145 runtime->hw.period_bytes_max = hw->period_bytes_max;
146 runtime->hw.periods_min = hw->periods_min;
147 runtime->hw.periods_max = hw->periods_max;
148 runtime->hw.buffer_bytes_max = hw->buffer_bytes_max;
149 runtime->hw.fifo_size = hw->fifo_size;
150 return 0;
151}
152EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
153
Liam Girdwood01d75842012-04-25 12:12:49 +0100154/* DPCM stream event, send event to FE and all active BEs. */
Liam Girdwood23607022014-01-17 17:03:55 +0000155int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
Liam Girdwood01d75842012-04-25 12:12:49 +0100156 int event)
157{
158 struct snd_soc_dpcm *dpcm;
159
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +0000160 for_each_dpcm_be(fe, dir, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +0100161
162 struct snd_soc_pcm_runtime *be = dpcm->be;
163
Liam Girdwood103d84a2012-11-19 14:39:15 +0000164 dev_dbg(be->dev, "ASoC: BE %s event %d dir %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +0100165 be->dai_link->name, event, dir);
166
Banajit Goswamib1cd2e32017-07-14 23:15:05 -0700167 if ((event == SND_SOC_DAPM_STREAM_STOP) &&
168 (be->dpcm[dir].users >= 1))
169 continue;
170
Liam Girdwood01d75842012-04-25 12:12:49 +0100171 snd_soc_dapm_stream_event(be, dir, event);
172 }
173
174 snd_soc_dapm_stream_event(fe, dir, event);
175
176 return 0;
177}
178
Dong Aisheng17841022011-08-29 17:15:14 +0800179static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
180 struct snd_soc_dai *soc_dai)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100181{
182 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100183 int ret;
184
Nicolin Chen3635bf02013-11-13 18:56:24 +0800185 if (soc_dai->rate && (soc_dai->driver->symmetric_rates ||
186 rtd->dai_link->symmetric_rates)) {
187 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n",
188 soc_dai->rate);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100189
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200190 ret = snd_pcm_hw_constraint_single(substream->runtime,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800191 SNDRV_PCM_HW_PARAM_RATE,
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200192 soc_dai->rate);
Nicolin Chen3635bf02013-11-13 18:56:24 +0800193 if (ret < 0) {
194 dev_err(soc_dai->dev,
195 "ASoC: Unable to apply rate constraint: %d\n",
196 ret);
197 return ret;
198 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100199 }
200
Nicolin Chen3635bf02013-11-13 18:56:24 +0800201 if (soc_dai->channels && (soc_dai->driver->symmetric_channels ||
202 rtd->dai_link->symmetric_channels)) {
203 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d channel(s)\n",
204 soc_dai->channels);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100205
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200206 ret = snd_pcm_hw_constraint_single(substream->runtime,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800207 SNDRV_PCM_HW_PARAM_CHANNELS,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800208 soc_dai->channels);
209 if (ret < 0) {
210 dev_err(soc_dai->dev,
211 "ASoC: Unable to apply channel symmetry constraint: %d\n",
212 ret);
213 return ret;
214 }
215 }
216
217 if (soc_dai->sample_bits && (soc_dai->driver->symmetric_samplebits ||
218 rtd->dai_link->symmetric_samplebits)) {
219 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d sample bits\n",
220 soc_dai->sample_bits);
221
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200222 ret = snd_pcm_hw_constraint_single(substream->runtime,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800223 SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800224 soc_dai->sample_bits);
225 if (ret < 0) {
226 dev_err(soc_dai->dev,
227 "ASoC: Unable to apply sample bits symmetry constraint: %d\n",
228 ret);
229 return ret;
230 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100231 }
232
233 return 0;
234}
235
Nicolin Chen3635bf02013-11-13 18:56:24 +0800236static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
237 struct snd_pcm_hw_params *params)
238{
239 struct snd_soc_pcm_runtime *rtd = substream->private_data;
240 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000241 struct snd_soc_dai *codec_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200242 unsigned int rate, channels, sample_bits, symmetry, i;
Nicolin Chen3635bf02013-11-13 18:56:24 +0800243
244 rate = params_rate(params);
245 channels = params_channels(params);
246 sample_bits = snd_pcm_format_physical_width(params_format(params));
247
248 /* reject unmatched parameters when applying symmetry */
249 symmetry = cpu_dai->driver->symmetric_rates ||
Nicolin Chen3635bf02013-11-13 18:56:24 +0800250 rtd->dai_link->symmetric_rates;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200251
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000252 for_each_rtd_codec_dai(rtd, i, codec_dai)
253 symmetry |= codec_dai->driver->symmetric_rates;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200254
Nicolin Chen3635bf02013-11-13 18:56:24 +0800255 if (symmetry && cpu_dai->rate && cpu_dai->rate != rate) {
256 dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n",
257 cpu_dai->rate, rate);
258 return -EINVAL;
259 }
260
261 symmetry = cpu_dai->driver->symmetric_channels ||
Nicolin Chen3635bf02013-11-13 18:56:24 +0800262 rtd->dai_link->symmetric_channels;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200263
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000264 for_each_rtd_codec_dai(rtd, i, codec_dai)
265 symmetry |= codec_dai->driver->symmetric_channels;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200266
Nicolin Chen3635bf02013-11-13 18:56:24 +0800267 if (symmetry && cpu_dai->channels && cpu_dai->channels != channels) {
268 dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n",
269 cpu_dai->channels, channels);
270 return -EINVAL;
271 }
272
273 symmetry = cpu_dai->driver->symmetric_samplebits ||
Nicolin Chen3635bf02013-11-13 18:56:24 +0800274 rtd->dai_link->symmetric_samplebits;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200275
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000276 for_each_rtd_codec_dai(rtd, i, codec_dai)
277 symmetry |= codec_dai->driver->symmetric_samplebits;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200278
Nicolin Chen3635bf02013-11-13 18:56:24 +0800279 if (symmetry && cpu_dai->sample_bits && cpu_dai->sample_bits != sample_bits) {
280 dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n",
281 cpu_dai->sample_bits, sample_bits);
282 return -EINVAL;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100283 }
284
285 return 0;
286}
287
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100288static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream)
289{
290 struct snd_soc_pcm_runtime *rtd = substream->private_data;
291 struct snd_soc_dai_driver *cpu_driver = rtd->cpu_dai->driver;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100292 struct snd_soc_dai_link *link = rtd->dai_link;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000293 struct snd_soc_dai *codec_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200294 unsigned int symmetry, i;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100295
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200296 symmetry = cpu_driver->symmetric_rates || link->symmetric_rates ||
297 cpu_driver->symmetric_channels || link->symmetric_channels ||
298 cpu_driver->symmetric_samplebits || link->symmetric_samplebits;
299
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000300 for_each_rtd_codec_dai(rtd, i, codec_dai)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200301 symmetry = symmetry ||
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000302 codec_dai->driver->symmetric_rates ||
303 codec_dai->driver->symmetric_channels ||
304 codec_dai->driver->symmetric_samplebits;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200305
306 return symmetry;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100307}
308
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200309static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits)
Mark Brown58ba9b22012-01-16 18:38:51 +0000310{
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200311 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Takashi Iwaic6068d32014-12-31 17:10:34 +0100312 int ret;
Mark Brown58ba9b22012-01-16 18:38:51 +0000313
314 if (!bits)
315 return;
316
Lars-Peter Clausen0e2a3752014-12-29 18:43:38 +0100317 ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 0, bits);
318 if (ret != 0)
319 dev_warn(rtd->dev, "ASoC: Failed to set MSB %d: %d\n",
320 bits, ret);
Mark Brown58ba9b22012-01-16 18:38:51 +0000321}
322
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200323static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200324{
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200325 struct snd_soc_pcm_runtime *rtd = substream->private_data;
326 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200327 struct snd_soc_dai *codec_dai;
328 int i;
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200329 unsigned int bits = 0, cpu_bits;
330
331 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000332 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200333 if (codec_dai->driver->playback.sig_bits == 0) {
334 bits = 0;
335 break;
336 }
337 bits = max(codec_dai->driver->playback.sig_bits, bits);
338 }
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200339 cpu_bits = cpu_dai->driver->playback.sig_bits;
340 } else {
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000341 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Daniel Mack5e63dfc2014-10-07 14:33:46 +0200342 if (codec_dai->driver->capture.sig_bits == 0) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200343 bits = 0;
344 break;
345 }
346 bits = max(codec_dai->driver->capture.sig_bits, bits);
347 }
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200348 cpu_bits = cpu_dai->driver->capture.sig_bits;
349 }
350
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200351 soc_pcm_set_msb(substream, bits);
352 soc_pcm_set_msb(substream, cpu_bits);
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200353}
354
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200355static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200356{
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200357 struct snd_pcm_runtime *runtime = substream->runtime;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100358 struct snd_pcm_hardware *hw = &runtime->hw;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200359 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000360 struct snd_soc_dai *codec_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200361 struct snd_soc_dai_driver *cpu_dai_drv = rtd->cpu_dai->driver;
362 struct snd_soc_dai_driver *codec_dai_drv;
363 struct snd_soc_pcm_stream *codec_stream;
364 struct snd_soc_pcm_stream *cpu_stream;
365 unsigned int chan_min = 0, chan_max = UINT_MAX;
366 unsigned int rate_min = 0, rate_max = UINT_MAX;
367 unsigned int rates = UINT_MAX;
368 u64 formats = ULLONG_MAX;
369 int i;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100370
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200371 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
372 cpu_stream = &cpu_dai_drv->playback;
Lars-Peter Clausen16d7ea92014-01-06 14:19:16 +0100373 else
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200374 cpu_stream = &cpu_dai_drv->capture;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100375
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200376 /* first calculate min/max only for CODECs in the DAI link */
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000377 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200378
379 /*
380 * Skip CODECs which don't support the current stream type.
381 * Otherwise, since the rate, channel, and format values will
382 * zero in that case, we would have no usable settings left,
383 * causing the resulting setup to fail.
384 * At least one CODEC should match, otherwise we should have
385 * bailed out on a higher level, since there would be no
386 * CODEC to support the transfer direction in that case.
387 */
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000388 if (!snd_soc_dai_stream_valid(codec_dai,
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200389 substream->stream))
390 continue;
391
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000392 codec_dai_drv = codec_dai->driver;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200393 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
394 codec_stream = &codec_dai_drv->playback;
395 else
396 codec_stream = &codec_dai_drv->capture;
397 chan_min = max(chan_min, codec_stream->channels_min);
398 chan_max = min(chan_max, codec_stream->channels_max);
399 rate_min = max(rate_min, codec_stream->rate_min);
400 rate_max = min_not_zero(rate_max, codec_stream->rate_max);
401 formats &= codec_stream->formats;
402 rates = snd_pcm_rate_mask_intersect(codec_stream->rates, rates);
403 }
404
405 /*
406 * chan min/max cannot be enforced if there are multiple CODEC DAIs
407 * connected to a single CPU DAI, use CPU DAI's directly and let
408 * channel allocation be fixed up later
409 */
410 if (rtd->num_codecs > 1) {
411 chan_min = cpu_stream->channels_min;
412 chan_max = cpu_stream->channels_max;
413 }
414
415 hw->channels_min = max(chan_min, cpu_stream->channels_min);
416 hw->channels_max = min(chan_max, cpu_stream->channels_max);
417 if (hw->formats)
418 hw->formats &= formats & cpu_stream->formats;
419 else
420 hw->formats = formats & cpu_stream->formats;
421 hw->rates = snd_pcm_rate_mask_intersect(rates, cpu_stream->rates);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100422
423 snd_pcm_limit_hw_rates(runtime);
424
425 hw->rate_min = max(hw->rate_min, cpu_stream->rate_min);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200426 hw->rate_min = max(hw->rate_min, rate_min);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100427 hw->rate_max = min_not_zero(hw->rate_max, cpu_stream->rate_max);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200428 hw->rate_max = min_not_zero(hw->rate_max, rate_max);
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200429}
430
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900431static int soc_pcm_components_open(struct snd_pcm_substream *substream,
432 struct snd_soc_component **last)
433{
434 struct snd_soc_pcm_runtime *rtd = substream->private_data;
435 struct snd_soc_rtdcom_list *rtdcom;
436 struct snd_soc_component *component;
437 int ret = 0;
438
439 for_each_rtdcom(rtd, rtdcom) {
440 component = rtdcom->component;
441 *last = component;
442
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900443 if (component->driver->module_get_upon_open &&
444 !try_module_get(component->dev->driver->owner)) {
445 dev_err(component->dev,
446 "ASoC: can't get module %s\n",
447 component->name);
448 return -ENODEV;
449 }
450
Kuninori Morimoto428306c2019-05-20 10:42:39 +0900451 if (!component->driver->ops ||
452 !component->driver->ops->open)
453 continue;
454
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900455 ret = component->driver->ops->open(substream);
456 if (ret < 0) {
457 dev_err(component->dev,
458 "ASoC: can't open component %s: %d\n",
459 component->name, ret);
460 return ret;
461 }
462 }
463 *last = NULL;
464 return 0;
465}
466
Charles Keepax244e2932018-06-19 16:22:09 +0100467static int soc_pcm_components_close(struct snd_pcm_substream *substream,
468 struct snd_soc_component *last)
469{
470 struct snd_soc_pcm_runtime *rtd = substream->private_data;
471 struct snd_soc_rtdcom_list *rtdcom;
472 struct snd_soc_component *component;
473
474 for_each_rtdcom(rtd, rtdcom) {
475 component = rtdcom->component;
476
477 if (component == last)
478 break;
479
Kuninori Morimoto428306c2019-05-20 10:42:39 +0900480 if (component->driver->ops &&
481 component->driver->ops->close)
482 component->driver->ops->close(substream);
Ranjani Sridharan52034ad2019-04-05 09:57:09 -0700483
484 if (component->driver->module_get_upon_open)
485 module_put(component->dev->driver->owner);
Charles Keepax244e2932018-06-19 16:22:09 +0100486 }
487
488 return 0;
489}
490
Mark Brown58ba9b22012-01-16 18:38:51 +0000491/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100492 * Called by ALSA when a PCM substream is opened, the runtime->hw record is
493 * then initialized and any private data can be allocated. This also calls
Charles Keepaxef050be2018-04-24 16:39:02 +0100494 * startup for the cpu DAI, component, machine and codec DAI.
Liam Girdwoodddee6272011-06-09 14:45:53 +0100495 */
496static int soc_pcm_open(struct snd_pcm_substream *substream)
497{
498 struct snd_soc_pcm_runtime *rtd = substream->private_data;
499 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000500 struct snd_soc_component *component;
501 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100502 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200503 struct snd_soc_dai *codec_dai;
504 const char *codec_dai_name = "multicodec";
Charles Keepax244e2932018-06-19 16:22:09 +0100505 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100506
Nicolin Chen988e8cc2013-11-04 14:57:31 +0800507 pinctrl_pm_select_default_state(cpu_dai->dev);
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000508 for_each_rtd_codec_dai(rtd, i, codec_dai)
509 pinctrl_pm_select_default_state(codec_dai->dev);
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000510
511 for_each_rtdcom(rtd, rtdcom) {
512 component = rtdcom->component;
513
514 pm_runtime_get_sync(component->dev);
515 }
Mark Brownd6652ef2011-12-03 20:14:31 +0000516
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100517 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100518
519 /* startup the audio subsystem */
Kuninori Morimoto5a52a042019-07-22 10:33:32 +0900520 ret = snd_soc_dai_startup(cpu_dai, substream);
521 if (ret < 0) {
522 dev_err(cpu_dai->dev, "ASoC: can't open interface %s: %d\n",
523 cpu_dai->name, ret);
524 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100525 }
526
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900527 ret = soc_pcm_components_open(substream, &component);
528 if (ret < 0)
529 goto component_err;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000530
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000531 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto5a52a042019-07-22 10:33:32 +0900532 ret = snd_soc_dai_startup(codec_dai, substream);
533 if (ret < 0) {
534 dev_err(codec_dai->dev,
535 "ASoC: can't open codec %s: %d\n",
536 codec_dai->name, ret);
537 goto codec_dai_err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100538 }
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200539
540 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
541 codec_dai->tx_mask = 0;
542 else
543 codec_dai->rx_mask = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100544 }
545
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000546 if (rtd->dai_link->ops->startup) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100547 ret = rtd->dai_link->ops->startup(substream);
548 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000549 pr_err("ASoC: %s startup failed: %d\n",
Mark Brown25bfe662012-02-01 21:30:32 +0000550 rtd->dai_link->name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100551 goto machine_err;
552 }
553 }
554
Liam Girdwood01d75842012-04-25 12:12:49 +0100555 /* Dynamic PCM DAI links compat checks use dynamic capabilities */
556 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm)
557 goto dynamic;
558
Liam Girdwoodddee6272011-06-09 14:45:53 +0100559 /* Check that the codec and cpu DAIs are compatible */
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200560 soc_pcm_init_runtime_hw(substream);
561
562 if (rtd->num_codecs == 1)
563 codec_dai_name = rtd->codec_dai->name;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100564
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100565 if (soc_pcm_has_symmetry(substream))
566 runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
567
Liam Girdwoodddee6272011-06-09 14:45:53 +0100568 ret = -EINVAL;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100569 if (!runtime->hw.rates) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000570 printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200571 codec_dai_name, cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100572 goto config_err;
573 }
574 if (!runtime->hw.formats) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000575 printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200576 codec_dai_name, cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100577 goto config_err;
578 }
579 if (!runtime->hw.channels_min || !runtime->hw.channels_max ||
580 runtime->hw.channels_min > runtime->hw.channels_max) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000581 printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200582 codec_dai_name, cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100583 goto config_err;
584 }
585
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200586 soc_pcm_apply_msb(substream);
Mark Brown58ba9b22012-01-16 18:38:51 +0000587
Liam Girdwoodddee6272011-06-09 14:45:53 +0100588 /* Symmetry only applies if we've already got an active stream. */
Dong Aisheng17841022011-08-29 17:15:14 +0800589 if (cpu_dai->active) {
590 ret = soc_pcm_apply_symmetry(substream, cpu_dai);
591 if (ret != 0)
592 goto config_err;
593 }
594
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000595 for_each_rtd_codec_dai(rtd, i, codec_dai) {
596 if (codec_dai->active) {
597 ret = soc_pcm_apply_symmetry(substream, codec_dai);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200598 if (ret != 0)
599 goto config_err;
600 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100601 }
602
Liam Girdwood103d84a2012-11-19 14:39:15 +0000603 pr_debug("ASoC: %s <-> %s info:\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200604 codec_dai_name, cpu_dai->name);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000605 pr_debug("ASoC: rate mask 0x%x\n", runtime->hw.rates);
606 pr_debug("ASoC: min ch %d max ch %d\n", runtime->hw.channels_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100607 runtime->hw.channels_max);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000608 pr_debug("ASoC: min rate %d max rate %d\n", runtime->hw.rate_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100609 runtime->hw.rate_max);
610
Liam Girdwood01d75842012-04-25 12:12:49 +0100611dynamic:
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100612
613 snd_soc_runtime_activate(rtd, substream->stream);
614
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100615 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100616 return 0;
617
618config_err:
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000619 if (rtd->dai_link->ops->shutdown)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100620 rtd->dai_link->ops->shutdown(substream);
621
622machine_err:
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200623 i = rtd->num_codecs;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100624
625codec_dai_err:
Kuninori Morimoto330fcb52019-07-22 10:33:39 +0900626 for_each_rtd_codec_dai_rollback(rtd, i, codec_dai)
627 snd_soc_dai_shutdown(codec_dai, substream);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200628
Kuninori Morimotob8135862017-10-11 01:37:23 +0000629component_err:
Charles Keepax244e2932018-06-19 16:22:09 +0100630 soc_pcm_components_close(substream, component);
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900631
Kuninori Morimoto330fcb52019-07-22 10:33:39 +0900632 snd_soc_dai_shutdown(cpu_dai, substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100633out:
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100634 mutex_unlock(&rtd->pcm_mutex);
Mark Brownd6652ef2011-12-03 20:14:31 +0000635
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000636 for_each_rtdcom(rtd, rtdcom) {
637 component = rtdcom->component;
638
639 pm_runtime_mark_last_busy(component->dev);
640 pm_runtime_put_autosuspend(component->dev);
Sanyog Kale3f809782016-01-05 17:14:49 +0530641 }
642
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000643 for_each_rtd_codec_dai(rtd, i, codec_dai) {
644 if (!codec_dai->active)
645 pinctrl_pm_select_sleep_state(codec_dai->dev);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200646 }
Nicolin Chen988e8cc2013-11-04 14:57:31 +0800647 if (!cpu_dai->active)
648 pinctrl_pm_select_sleep_state(cpu_dai->dev);
Mark Brownd6652ef2011-12-03 20:14:31 +0000649
Liam Girdwoodddee6272011-06-09 14:45:53 +0100650 return ret;
651}
652
653/*
654 * Power down the audio subsystem pmdown_time msecs after close is called.
655 * This is to ensure there are no pops or clicks in between any music tracks
656 * due to DAPM power cycling.
657 */
658static void close_delayed_work(struct work_struct *work)
659{
660 struct snd_soc_pcm_runtime *rtd =
661 container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200662 struct snd_soc_dai *codec_dai = rtd->codec_dais[0];
Liam Girdwoodddee6272011-06-09 14:45:53 +0100663
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100664 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100665
Liam Girdwood103d84a2012-11-19 14:39:15 +0000666 dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n",
Liam Girdwoodddee6272011-06-09 14:45:53 +0100667 codec_dai->driver->playback.stream_name,
668 codec_dai->playback_active ? "active" : "inactive",
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600669 rtd->pop_wait ? "yes" : "no");
Liam Girdwoodddee6272011-06-09 14:45:53 +0100670
671 /* are we waiting on this codec DAI stream */
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600672 if (rtd->pop_wait == 1) {
673 rtd->pop_wait = 0;
Mark Brown7bd3a6f2012-02-16 15:03:27 -0800674 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000675 SND_SOC_DAPM_STREAM_STOP);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100676 }
677
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100678 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100679}
680
Jerome Bruneta3420312019-07-25 18:59:47 +0200681static void codec2codec_close_delayed_work(struct work_struct *work)
682{
683 /*
684 * Currently nothing to do for c2c links
685 * Since c2c links are internal nodes in the DAPM graph and
686 * don't interface with the outside world or application layer
687 * we don't have to do any special handling on close.
688 */
689}
690
Liam Girdwoodddee6272011-06-09 14:45:53 +0100691/*
692 * Called by ALSA when a PCM substream is closed. Private data can be
Charles Keepaxef050be2018-04-24 16:39:02 +0100693 * freed here. The cpu DAI, codec DAI, machine and components are also
Liam Girdwoodddee6272011-06-09 14:45:53 +0100694 * shutdown.
695 */
Liam Girdwood91d5e6b2011-06-09 17:04:59 +0100696static int soc_pcm_close(struct snd_pcm_substream *substream)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100697{
698 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000699 struct snd_soc_component *component;
700 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100701 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200702 struct snd_soc_dai *codec_dai;
703 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100704
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100705 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100706
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100707 snd_soc_runtime_deactivate(rtd, substream->stream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100708
Dong Aisheng17841022011-08-29 17:15:14 +0800709 /* clear the corresponding DAIs rate when inactive */
710 if (!cpu_dai->active)
711 cpu_dai->rate = 0;
712
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000713 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200714 if (!codec_dai->active)
715 codec_dai->rate = 0;
716 }
Sascha Hauer25b76792011-08-17 09:20:01 +0200717
Ramesh Babuae116012014-10-15 12:34:59 +0530718 snd_soc_dai_digital_mute(cpu_dai, 1, substream->stream);
719
Kuninori Morimoto330fcb52019-07-22 10:33:39 +0900720 snd_soc_dai_shutdown(cpu_dai, substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100721
Kuninori Morimoto330fcb52019-07-22 10:33:39 +0900722 for_each_rtd_codec_dai(rtd, i, codec_dai)
723 snd_soc_dai_shutdown(codec_dai, substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100724
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000725 if (rtd->dai_link->ops->shutdown)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100726 rtd->dai_link->ops->shutdown(substream);
727
Charles Keepax244e2932018-06-19 16:22:09 +0100728 soc_pcm_components_close(substream, NULL);
Kuninori Morimotob8135862017-10-11 01:37:23 +0000729
Liam Girdwoodddee6272011-06-09 14:45:53 +0100730 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100731 if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
Peter Ujfalusi1d69c5c2011-10-14 14:43:33 +0300732 /* powered down playback stream now */
733 snd_soc_dapm_stream_event(rtd,
Mark Brown7bd3a6f2012-02-16 15:03:27 -0800734 SNDRV_PCM_STREAM_PLAYBACK,
Mark Brown7bd3a6f2012-02-16 15:03:27 -0800735 SND_SOC_DAPM_STREAM_STOP);
Peter Ujfalusi1d69c5c2011-10-14 14:43:33 +0300736 } else {
737 /* start delayed pop wq here for playback streams */
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600738 rtd->pop_wait = 1;
Mark Brownd4e1a732013-07-18 11:52:17 +0100739 queue_delayed_work(system_power_efficient_wq,
740 &rtd->delayed_work,
741 msecs_to_jiffies(rtd->pmdown_time));
Peter Ujfalusi1d69c5c2011-10-14 14:43:33 +0300742 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100743 } else {
744 /* capture streams can be powered down now */
Mark Brown7bd3a6f2012-02-16 15:03:27 -0800745 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000746 SND_SOC_DAPM_STREAM_STOP);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100747 }
748
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100749 mutex_unlock(&rtd->pcm_mutex);
Mark Brownd6652ef2011-12-03 20:14:31 +0000750
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000751 for_each_rtdcom(rtd, rtdcom) {
752 component = rtdcom->component;
Sanyog Kale3f809782016-01-05 17:14:49 +0530753
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000754 pm_runtime_mark_last_busy(component->dev);
755 pm_runtime_put_autosuspend(component->dev);
Sanyog Kale3f809782016-01-05 17:14:49 +0530756 }
757
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000758 for_each_rtd_codec_dai(rtd, i, codec_dai) {
759 if (!codec_dai->active)
760 pinctrl_pm_select_sleep_state(codec_dai->dev);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200761 }
Nicolin Chen988e8cc2013-11-04 14:57:31 +0800762 if (!cpu_dai->active)
763 pinctrl_pm_select_sleep_state(cpu_dai->dev);
Mark Brownd6652ef2011-12-03 20:14:31 +0000764
Liam Girdwoodddee6272011-06-09 14:45:53 +0100765 return 0;
766}
767
768/*
769 * Called by ALSA when the PCM substream is prepared, can set format, sample
770 * rate, etc. This function is non atomic and can be called multiple times,
771 * it can refer to the runtime info.
772 */
773static int soc_pcm_prepare(struct snd_pcm_substream *substream)
774{
775 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000776 struct snd_soc_component *component;
777 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100778 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200779 struct snd_soc_dai *codec_dai;
780 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100781
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100782 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100783
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000784 if (rtd->dai_link->ops->prepare) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100785 ret = rtd->dai_link->ops->prepare(substream);
786 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000787 dev_err(rtd->card->dev, "ASoC: machine prepare error:"
788 " %d\n", ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100789 goto out;
790 }
791 }
792
Kuninori Morimotob8135862017-10-11 01:37:23 +0000793 for_each_rtdcom(rtd, rtdcom) {
794 component = rtdcom->component;
795
Kuninori Morimotob8135862017-10-11 01:37:23 +0000796 if (!component->driver->ops ||
797 !component->driver->ops->prepare)
798 continue;
799
800 ret = component->driver->ops->prepare(substream);
801 if (ret < 0) {
802 dev_err(component->dev,
803 "ASoC: platform prepare error: %d\n", ret);
804 goto out;
805 }
806 }
807
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000808 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto4beb8e12019-07-22 10:33:45 +0900809 ret = snd_soc_dai_prepare(codec_dai, substream);
810 if (ret < 0) {
811 dev_err(codec_dai->dev,
812 "ASoC: codec DAI prepare error: %d\n",
813 ret);
814 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100815 }
816 }
817
Kuninori Morimoto4beb8e12019-07-22 10:33:45 +0900818 ret = snd_soc_dai_prepare(cpu_dai, substream);
819 if (ret < 0) {
820 dev_err(cpu_dai->dev,
821 "ASoC: cpu DAI prepare error: %d\n", ret);
822 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100823 }
824
825 /* cancel any delayed stream shutdown that is pending */
826 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600827 rtd->pop_wait) {
828 rtd->pop_wait = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100829 cancel_delayed_work(&rtd->delayed_work);
830 }
831
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000832 snd_soc_dapm_stream_event(rtd, substream->stream,
833 SND_SOC_DAPM_STREAM_START);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100834
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000835 for_each_rtd_codec_dai(rtd, i, codec_dai)
836 snd_soc_dai_digital_mute(codec_dai, 0,
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200837 substream->stream);
Ramesh Babuae116012014-10-15 12:34:59 +0530838 snd_soc_dai_digital_mute(cpu_dai, 0, substream->stream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100839
840out:
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100841 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100842 return ret;
843}
844
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200845static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params,
846 unsigned int mask)
847{
848 struct snd_interval *interval;
849 int channels = hweight_long(mask);
850
851 interval = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
852 interval->min = channels;
853 interval->max = channels;
854}
855
Charles Keepax244e2932018-06-19 16:22:09 +0100856static int soc_pcm_components_hw_free(struct snd_pcm_substream *substream,
857 struct snd_soc_component *last)
858{
859 struct snd_soc_pcm_runtime *rtd = substream->private_data;
860 struct snd_soc_rtdcom_list *rtdcom;
861 struct snd_soc_component *component;
862
863 for_each_rtdcom(rtd, rtdcom) {
864 component = rtdcom->component;
865
866 if (component == last)
867 break;
868
869 if (!component->driver->ops ||
870 !component->driver->ops->hw_free)
871 continue;
872
873 component->driver->ops->hw_free(substream);
874 }
875
876 return 0;
877}
878
Liam Girdwoodddee6272011-06-09 14:45:53 +0100879/*
880 * Called by ALSA when the hardware params are set by application. This
881 * function can also be called multiple times and can allocate buffers
882 * (using snd_pcm_lib_* ). It's non-atomic.
883 */
884static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
885 struct snd_pcm_hw_params *params)
886{
887 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000888 struct snd_soc_component *component;
889 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100890 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000891 struct snd_soc_dai *codec_dai;
Charles Keepax244e2932018-06-19 16:22:09 +0100892 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100893
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100894 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000895 if (rtd->dai_link->ops->hw_params) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100896 ret = rtd->dai_link->ops->hw_params(substream, params);
897 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000898 dev_err(rtd->card->dev, "ASoC: machine hw_params"
899 " failed: %d\n", ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100900 goto out;
901 }
902 }
903
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000904 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200905 struct snd_pcm_hw_params codec_params;
906
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200907 /*
908 * Skip CODECs which don't support the current stream type,
909 * the idea being that if a CODEC is not used for the currently
910 * set up transfer direction, it should not need to be
911 * configured, especially since the configuration used might
912 * not even be supported by that CODEC. There may be cases
913 * however where a CODEC needs to be set up although it is
914 * actually not being used for the transfer, e.g. if a
915 * capture-only CODEC is acting as an LRCLK and/or BCLK master
916 * for the DAI link including a playback-only CODEC.
917 * If this becomes necessary, we will have to augment the
918 * machine driver setup with information on how to act, so
919 * we can do the right thing here.
920 */
921 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
922 continue;
923
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200924 /* copy params for each codec */
925 codec_params = *params;
926
927 /* fixup params based on TDM slot masks */
Rander Wang570f18b2019-03-08 16:38:57 +0800928 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
929 codec_dai->tx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200930 soc_pcm_codec_params_fixup(&codec_params,
931 codec_dai->tx_mask);
Rander Wang570f18b2019-03-08 16:38:57 +0800932
933 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
934 codec_dai->rx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200935 soc_pcm_codec_params_fixup(&codec_params,
936 codec_dai->rx_mask);
937
Kuninori Morimotoaa6166c2019-07-22 10:33:04 +0900938 ret = snd_soc_dai_hw_params(codec_dai, substream,
939 &codec_params);
Benoit Cousson93e69582014-07-08 23:19:38 +0200940 if(ret < 0)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100941 goto codec_err;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200942
943 codec_dai->rate = params_rate(&codec_params);
944 codec_dai->channels = params_channels(&codec_params);
945 codec_dai->sample_bits = snd_pcm_format_physical_width(
946 params_format(&codec_params));
Charles Keepax078a85f2019-01-31 13:30:18 +0000947
948 snd_soc_dapm_update_dai(substream, &codec_params, codec_dai);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100949 }
950
Kuninori Morimotoaa6166c2019-07-22 10:33:04 +0900951 ret = snd_soc_dai_hw_params(cpu_dai, substream, params);
Benoit Cousson93e69582014-07-08 23:19:38 +0200952 if (ret < 0)
953 goto interface_err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100954
Kuninori Morimotoca58221d2019-05-13 16:07:43 +0900955 /* store the parameters for each DAIs */
956 cpu_dai->rate = params_rate(params);
957 cpu_dai->channels = params_channels(params);
958 cpu_dai->sample_bits =
959 snd_pcm_format_physical_width(params_format(params));
960
961 snd_soc_dapm_update_dai(substream, params, cpu_dai);
962
Kuninori Morimotob8135862017-10-11 01:37:23 +0000963 for_each_rtdcom(rtd, rtdcom) {
964 component = rtdcom->component;
965
Kuninori Morimotob8135862017-10-11 01:37:23 +0000966 if (!component->driver->ops ||
967 !component->driver->ops->hw_params)
968 continue;
969
Charles Keepax244e2932018-06-19 16:22:09 +0100970 ret = component->driver->ops->hw_params(substream, params);
971 if (ret < 0) {
Kuninori Morimotob8135862017-10-11 01:37:23 +0000972 dev_err(component->dev,
973 "ASoC: %s hw params failed: %d\n",
Charles Keepax244e2932018-06-19 16:22:09 +0100974 component->name, ret);
975 goto component_err;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000976 }
977 }
Charles Keepax244e2932018-06-19 16:22:09 +0100978 component = NULL;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000979
jiada wang957ce0c2017-09-20 15:25:30 +0900980 ret = soc_pcm_params_symmetry(substream, params);
981 if (ret)
Kuninori Morimotob8135862017-10-11 01:37:23 +0000982 goto component_err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100983out:
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100984 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100985 return ret;
986
Kuninori Morimotob8135862017-10-11 01:37:23 +0000987component_err:
Charles Keepax244e2932018-06-19 16:22:09 +0100988 soc_pcm_components_hw_free(substream, component);
Kuninori Morimotob8135862017-10-11 01:37:23 +0000989
Kuninori Morimoto846faae2019-07-22 10:33:19 +0900990 snd_soc_dai_hw_free(cpu_dai, substream);
Kuninori Morimoto2371abd2019-05-13 16:07:52 +0900991 cpu_dai->rate = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100992
993interface_err:
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200994 i = rtd->num_codecs;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100995
996codec_err:
Kuninori Morimoto6d11b122018-09-18 01:28:30 +0000997 for_each_rtd_codec_dai_rollback(rtd, i, codec_dai) {
Jerome Brunetf47b9ad2019-04-29 11:47:50 +0200998 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
999 continue;
1000
Kuninori Morimoto846faae2019-07-22 10:33:19 +09001001 snd_soc_dai_hw_free(codec_dai, substream);
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001002 codec_dai->rate = 0;
1003 }
1004
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +00001005 if (rtd->dai_link->ops->hw_free)
Liam Girdwoodddee6272011-06-09 14:45:53 +01001006 rtd->dai_link->ops->hw_free(substream);
1007
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +01001008 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001009 return ret;
1010}
1011
1012/*
1013 * Frees resources allocated by hw_params, can be called multiple times
1014 */
1015static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
1016{
1017 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001018 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001019 struct snd_soc_dai *codec_dai;
Nicolin Chen7f62b6e2013-12-04 11:18:36 +08001020 bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001021 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001022
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +01001023 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001024
Nicolin Chend3383422013-11-20 18:37:09 +08001025 /* clear the corresponding DAIs parameters when going to be inactive */
1026 if (cpu_dai->active == 1) {
1027 cpu_dai->rate = 0;
1028 cpu_dai->channels = 0;
1029 cpu_dai->sample_bits = 0;
1030 }
1031
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001032 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001033 if (codec_dai->active == 1) {
1034 codec_dai->rate = 0;
1035 codec_dai->channels = 0;
1036 codec_dai->sample_bits = 0;
1037 }
Nicolin Chend3383422013-11-20 18:37:09 +08001038 }
1039
Liam Girdwoodddee6272011-06-09 14:45:53 +01001040 /* apply codec digital mute */
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001041 for_each_rtd_codec_dai(rtd, i, codec_dai) {
1042 if ((playback && codec_dai->playback_active == 1) ||
1043 (!playback && codec_dai->capture_active == 1))
1044 snd_soc_dai_digital_mute(codec_dai, 1,
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001045 substream->stream);
1046 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01001047
1048 /* free any machine hw params */
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +00001049 if (rtd->dai_link->ops->hw_free)
Liam Girdwoodddee6272011-06-09 14:45:53 +01001050 rtd->dai_link->ops->hw_free(substream);
1051
Kuninori Morimotob8135862017-10-11 01:37:23 +00001052 /* free any component resources */
Charles Keepax244e2932018-06-19 16:22:09 +01001053 soc_pcm_components_hw_free(substream, NULL);
Kuninori Morimotob8135862017-10-11 01:37:23 +00001054
Liam Girdwoodddee6272011-06-09 14:45:53 +01001055 /* now free hw params for the DAIs */
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001056 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Jerome Brunetf47b9ad2019-04-29 11:47:50 +02001057 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
1058 continue;
1059
Kuninori Morimoto846faae2019-07-22 10:33:19 +09001060 snd_soc_dai_hw_free(codec_dai, substream);
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001061 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01001062
Kuninori Morimoto846faae2019-07-22 10:33:19 +09001063 snd_soc_dai_hw_free(cpu_dai, substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001064
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +01001065 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001066 return 0;
1067}
1068
1069static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1070{
1071 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +00001072 struct snd_soc_component *component;
1073 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001074 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001075 struct snd_soc_dai *codec_dai;
1076 int i, ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001077
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001078 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto95aef352019-07-22 10:33:51 +09001079 ret = snd_soc_dai_trigger(codec_dai, substream, cmd);
1080 if (ret < 0)
1081 return ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001082 }
1083
Kuninori Morimotob8135862017-10-11 01:37:23 +00001084 for_each_rtdcom(rtd, rtdcom) {
1085 component = rtdcom->component;
1086
Kuninori Morimotob8135862017-10-11 01:37:23 +00001087 if (!component->driver->ops ||
1088 !component->driver->ops->trigger)
1089 continue;
1090
1091 ret = component->driver->ops->trigger(substream, cmd);
1092 if (ret < 0)
1093 return ret;
1094 }
1095
Kuninori Morimoto95aef352019-07-22 10:33:51 +09001096 snd_soc_dai_trigger(cpu_dai, substream, cmd);
1097 if (ret < 0)
1098 return ret;
Jarkko Nikula4792b0d2014-04-28 14:17:52 +02001099
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +00001100 if (rtd->dai_link->ops->trigger) {
Jarkko Nikula4792b0d2014-04-28 14:17:52 +02001101 ret = rtd->dai_link->ops->trigger(substream, cmd);
1102 if (ret < 0)
1103 return ret;
1104 }
1105
Liam Girdwoodddee6272011-06-09 14:45:53 +01001106 return 0;
1107}
1108
Mark Brown45c0a182012-05-09 21:46:27 +01001109static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
1110 int cmd)
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001111{
1112 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001113 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001114 struct snd_soc_dai *codec_dai;
1115 int i, ret;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001116
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001117 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto5c0769af2019-07-22 10:33:56 +09001118 ret = snd_soc_dai_bespoke_trigger(codec_dai, substream, cmd);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001119 if (ret < 0)
1120 return ret;
1121 }
Kuninori Morimoto5c0769af2019-07-22 10:33:56 +09001122
1123 snd_soc_dai_bespoke_trigger(cpu_dai, substream, cmd);
1124 if (ret < 0)
1125 return ret;
1126
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001127 return 0;
1128}
Liam Girdwoodddee6272011-06-09 14:45:53 +01001129/*
1130 * soc level wrapper for pointer callback
Charles Keepaxef050be2018-04-24 16:39:02 +01001131 * If cpu_dai, codec_dai, component driver has the delay callback, then
Liam Girdwoodddee6272011-06-09 14:45:53 +01001132 * the runtime->delay will be updated accordingly.
1133 */
1134static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
1135{
1136 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +00001137 struct snd_soc_component *component;
1138 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001139 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001140 struct snd_soc_dai *codec_dai;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001141 struct snd_pcm_runtime *runtime = substream->runtime;
1142 snd_pcm_uframes_t offset = 0;
1143 snd_pcm_sframes_t delay = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001144 snd_pcm_sframes_t codec_delay = 0;
1145 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001146
Akshu Agrawal9fb4c2bf2018-08-01 15:37:33 +05301147 /* clearing the previous total delay */
1148 runtime->delay = 0;
1149
Kuninori Morimotob8135862017-10-11 01:37:23 +00001150 for_each_rtdcom(rtd, rtdcom) {
1151 component = rtdcom->component;
1152
Kuninori Morimotob8135862017-10-11 01:37:23 +00001153 if (!component->driver->ops ||
1154 !component->driver->ops->pointer)
1155 continue;
1156
1157 /* FIXME: use 1st pointer */
1158 offset = component->driver->ops->pointer(substream);
1159 break;
1160 }
Akshu Agrawal9fb4c2bf2018-08-01 15:37:33 +05301161 /* base delay if assigned in pointer callback */
1162 delay = runtime->delay;
Kuninori Morimotob8135862017-10-11 01:37:23 +00001163
Kuninori Morimoto1dea80d2019-07-22 10:34:09 +09001164 delay += snd_soc_dai_delay(cpu_dai, substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001165
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001166 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto1dea80d2019-07-22 10:34:09 +09001167 codec_delay = max(codec_delay,
1168 snd_soc_dai_delay(codec_dai, substream));
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001169 }
1170 delay += codec_delay;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001171
Liam Girdwoodddee6272011-06-09 14:45:53 +01001172 runtime->delay = delay;
1173
1174 return offset;
1175}
1176
Liam Girdwood01d75842012-04-25 12:12:49 +01001177/* connect a FE and BE */
1178static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
1179 struct snd_soc_pcm_runtime *be, int stream)
1180{
1181 struct snd_soc_dpcm *dpcm;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001182 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001183
1184 /* only add new dpcms */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001185 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001186 if (dpcm->be == be && dpcm->fe == fe)
1187 return 0;
1188 }
1189
1190 dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_KERNEL);
1191 if (!dpcm)
1192 return -ENOMEM;
1193
1194 dpcm->be = be;
1195 dpcm->fe = fe;
1196 be->dpcm[stream].runtime = fe->dpcm[stream].runtime;
1197 dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001198 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001199 list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients);
1200 list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001201 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001202
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001203 dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001204 stream ? "capture" : "playback", fe->dai_link->name,
1205 stream ? "<-" : "->", be->dai_link->name);
1206
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001207#ifdef CONFIG_DEBUG_FS
Greg Kroah-Hartmanfee531d2019-07-31 15:17:15 +02001208 dpcm->debugfs_state = debugfs_create_dir(be->dai_link->name,
1209 fe->debugfs_dpcm_root);
1210 debugfs_create_u32("state", 0644, dpcm->debugfs_state, &dpcm->state);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001211#endif
Liam Girdwood01d75842012-04-25 12:12:49 +01001212 return 1;
1213}
1214
1215/* reparent a BE onto another FE */
1216static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
1217 struct snd_soc_pcm_runtime *be, int stream)
1218{
1219 struct snd_soc_dpcm *dpcm;
1220 struct snd_pcm_substream *fe_substream, *be_substream;
1221
1222 /* reparent if BE is connected to other FEs */
1223 if (!be->dpcm[stream].users)
1224 return;
1225
1226 be_substream = snd_soc_dpcm_get_substream(be, stream);
1227
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00001228 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001229 if (dpcm->fe == fe)
1230 continue;
1231
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001232 dev_dbg(fe->dev, "reparent %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001233 stream ? "capture" : "playback",
1234 dpcm->fe->dai_link->name,
1235 stream ? "<-" : "->", dpcm->be->dai_link->name);
1236
1237 fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, stream);
1238 be_substream->runtime = fe_substream->runtime;
1239 break;
1240 }
1241}
1242
1243/* disconnect a BE and FE */
Liam Girdwood23607022014-01-17 17:03:55 +00001244void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001245{
1246 struct snd_soc_dpcm *dpcm, *d;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001247 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001248
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001249 for_each_dpcm_be_safe(fe, stream, dpcm, d) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001250 dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001251 stream ? "capture" : "playback",
1252 dpcm->be->dai_link->name);
1253
1254 if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE)
1255 continue;
1256
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001257 dev_dbg(fe->dev, "freed DSP %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001258 stream ? "capture" : "playback", fe->dai_link->name,
1259 stream ? "<-" : "->", dpcm->be->dai_link->name);
1260
1261 /* BEs still alive need new FE */
1262 dpcm_be_reparent(fe, dpcm->be, stream);
1263
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001264#ifdef CONFIG_DEBUG_FS
Greg Kroah-Hartmanfee531d2019-07-31 15:17:15 +02001265 debugfs_remove_recursive(dpcm->debugfs_state);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001266#endif
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001267 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001268 list_del(&dpcm->list_be);
1269 list_del(&dpcm->list_fe);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001270 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001271 kfree(dpcm);
1272 }
1273}
1274
1275/* get BE for DAI widget and stream */
1276static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
1277 struct snd_soc_dapm_widget *widget, int stream)
1278{
1279 struct snd_soc_pcm_runtime *be;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001280 struct snd_soc_dai *dai;
Mengdong Lin1a497982015-11-18 02:34:11 -05001281 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01001282
Liam Girdwood3c146462018-03-14 20:43:51 +00001283 dev_dbg(card->dev, "ASoC: find BE for widget %s\n", widget->name);
1284
Liam Girdwood01d75842012-04-25 12:12:49 +01001285 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00001286 for_each_card_rtds(card, be) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001287
Liam Girdwood35ea0652012-06-05 19:26:59 +01001288 if (!be->dai_link->no_pcm)
1289 continue;
1290
Liam Girdwood3c146462018-03-14 20:43:51 +00001291 dev_dbg(card->dev, "ASoC: try BE : %s\n",
1292 be->cpu_dai->playback_widget ?
1293 be->cpu_dai->playback_widget->name : "(not set)");
1294
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001295 if (be->cpu_dai->playback_widget == widget)
Liam Girdwood01d75842012-04-25 12:12:49 +01001296 return be;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001297
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001298 for_each_rtd_codec_dai(be, i, dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001299 if (dai->playback_widget == widget)
1300 return be;
1301 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001302 }
1303 } else {
1304
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00001305 for_each_card_rtds(card, be) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001306
Liam Girdwood35ea0652012-06-05 19:26:59 +01001307 if (!be->dai_link->no_pcm)
1308 continue;
1309
Liam Girdwood3c146462018-03-14 20:43:51 +00001310 dev_dbg(card->dev, "ASoC: try BE %s\n",
1311 be->cpu_dai->capture_widget ?
1312 be->cpu_dai->capture_widget->name : "(not set)");
1313
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001314 if (be->cpu_dai->capture_widget == widget)
Liam Girdwood01d75842012-04-25 12:12:49 +01001315 return be;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001316
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001317 for_each_rtd_codec_dai(be, i, dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001318 if (dai->capture_widget == widget)
1319 return be;
1320 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001321 }
1322 }
1323
Liam Girdwood3c146462018-03-14 20:43:51 +00001324 /* dai link name and stream name set correctly ? */
Liam Girdwood103d84a2012-11-19 14:39:15 +00001325 dev_err(card->dev, "ASoC: can't get %s BE for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001326 stream ? "capture" : "playback", widget->name);
1327 return NULL;
1328}
1329
1330static inline struct snd_soc_dapm_widget *
Benoit Cousson37018612014-04-24 14:01:45 +02001331 dai_get_widget(struct snd_soc_dai *dai, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001332{
1333 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
Benoit Cousson37018612014-04-24 14:01:45 +02001334 return dai->playback_widget;
Liam Girdwood01d75842012-04-25 12:12:49 +01001335 else
Benoit Cousson37018612014-04-24 14:01:45 +02001336 return dai->capture_widget;
Liam Girdwood01d75842012-04-25 12:12:49 +01001337}
1338
1339static int widget_in_list(struct snd_soc_dapm_widget_list *list,
1340 struct snd_soc_dapm_widget *widget)
1341{
1342 int i;
1343
1344 for (i = 0; i < list->num_widgets; i++) {
1345 if (widget == list->widgets[i])
1346 return 1;
1347 }
1348
1349 return 0;
1350}
1351
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001352static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget,
1353 enum snd_soc_dapm_direction dir)
1354{
1355 struct snd_soc_card *card = widget->dapm->card;
1356 struct snd_soc_pcm_runtime *rtd;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001357 struct snd_soc_dai *dai;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001358 int i;
1359
1360 if (dir == SND_SOC_DAPM_DIR_OUT) {
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00001361 for_each_card_rtds(card, rtd) {
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001362 if (!rtd->dai_link->no_pcm)
1363 continue;
1364
1365 if (rtd->cpu_dai->playback_widget == widget)
1366 return true;
1367
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001368 for_each_rtd_codec_dai(rtd, i, dai) {
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001369 if (dai->playback_widget == widget)
1370 return true;
1371 }
1372 }
1373 } else { /* SND_SOC_DAPM_DIR_IN */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00001374 for_each_card_rtds(card, rtd) {
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001375 if (!rtd->dai_link->no_pcm)
1376 continue;
1377
1378 if (rtd->cpu_dai->capture_widget == widget)
1379 return true;
1380
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001381 for_each_rtd_codec_dai(rtd, i, dai) {
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001382 if (dai->capture_widget == widget)
1383 return true;
1384 }
1385 }
1386 }
1387
1388 return false;
1389}
1390
Liam Girdwood23607022014-01-17 17:03:55 +00001391int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001392 int stream, struct snd_soc_dapm_widget_list **list)
Liam Girdwood01d75842012-04-25 12:12:49 +01001393{
1394 struct snd_soc_dai *cpu_dai = fe->cpu_dai;
Liam Girdwood01d75842012-04-25 12:12:49 +01001395 int paths;
1396
Liam Girdwood01d75842012-04-25 12:12:49 +01001397 /* get number of valid DAI paths and their widgets */
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001398 paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list,
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001399 dpcm_end_walk_at_be);
Liam Girdwood01d75842012-04-25 12:12:49 +01001400
Liam Girdwood103d84a2012-11-19 14:39:15 +00001401 dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths,
Liam Girdwood01d75842012-04-25 12:12:49 +01001402 stream ? "capture" : "playback");
1403
Liam Girdwood01d75842012-04-25 12:12:49 +01001404 return paths;
1405}
1406
Liam Girdwood01d75842012-04-25 12:12:49 +01001407static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
1408 struct snd_soc_dapm_widget_list **list_)
1409{
1410 struct snd_soc_dpcm *dpcm;
1411 struct snd_soc_dapm_widget_list *list = *list_;
1412 struct snd_soc_dapm_widget *widget;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001413 struct snd_soc_dai *dai;
Liam Girdwood01d75842012-04-25 12:12:49 +01001414 int prune = 0;
1415
1416 /* Destroy any old FE <--> BE connections */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001417 for_each_dpcm_be(fe, stream, dpcm) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001418 unsigned int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01001419
1420 /* is there a valid CPU DAI widget for this BE */
Benoit Cousson37018612014-04-24 14:01:45 +02001421 widget = dai_get_widget(dpcm->be->cpu_dai, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001422
1423 /* prune the BE if it's no longer in our active list */
1424 if (widget && widget_in_list(list, widget))
1425 continue;
1426
1427 /* is there a valid CODEC DAI widget for this BE */
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001428 for_each_rtd_codec_dai(dpcm->be, i, dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001429 widget = dai_get_widget(dai, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001430
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001431 /* prune the BE if it's no longer in our active list */
1432 if (widget && widget_in_list(list, widget))
1433 continue;
1434 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001435
Liam Girdwood103d84a2012-11-19 14:39:15 +00001436 dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001437 stream ? "capture" : "playback",
1438 dpcm->be->dai_link->name, fe->dai_link->name);
1439 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
1440 dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1441 prune++;
1442 }
1443
Liam Girdwood103d84a2012-11-19 14:39:15 +00001444 dev_dbg(fe->dev, "ASoC: found %d old BE paths for pruning\n", prune);
Liam Girdwood01d75842012-04-25 12:12:49 +01001445 return prune;
1446}
1447
1448static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
1449 struct snd_soc_dapm_widget_list **list_)
1450{
1451 struct snd_soc_card *card = fe->card;
1452 struct snd_soc_dapm_widget_list *list = *list_;
1453 struct snd_soc_pcm_runtime *be;
1454 int i, new = 0, err;
1455
1456 /* Create any new FE <--> BE connections */
1457 for (i = 0; i < list->num_widgets; i++) {
1458
Mark Brown46162742013-06-05 19:36:11 +01001459 switch (list->widgets[i]->id) {
1460 case snd_soc_dapm_dai_in:
Koro Chenc5b85402015-07-06 10:02:10 +08001461 if (stream != SNDRV_PCM_STREAM_PLAYBACK)
1462 continue;
1463 break;
Mark Brown46162742013-06-05 19:36:11 +01001464 case snd_soc_dapm_dai_out:
Koro Chenc5b85402015-07-06 10:02:10 +08001465 if (stream != SNDRV_PCM_STREAM_CAPTURE)
1466 continue;
Mark Brown46162742013-06-05 19:36:11 +01001467 break;
1468 default:
Liam Girdwood01d75842012-04-25 12:12:49 +01001469 continue;
Mark Brown46162742013-06-05 19:36:11 +01001470 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001471
1472 /* is there a valid BE rtd for this widget */
1473 be = dpcm_get_be(card, list->widgets[i], stream);
1474 if (!be) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001475 dev_err(fe->dev, "ASoC: no BE found for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001476 list->widgets[i]->name);
1477 continue;
1478 }
1479
1480 /* make sure BE is a real BE */
1481 if (!be->dai_link->no_pcm)
1482 continue;
1483
1484 /* don't connect if FE is not running */
Liam Girdwood23607022014-01-17 17:03:55 +00001485 if (!fe->dpcm[stream].runtime && !fe->fe_compr)
Liam Girdwood01d75842012-04-25 12:12:49 +01001486 continue;
1487
1488 /* newly connected FE and BE */
1489 err = dpcm_be_connect(fe, be, stream);
1490 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001491 dev_err(fe->dev, "ASoC: can't connect %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001492 list->widgets[i]->name);
1493 break;
1494 } else if (err == 0) /* already connected */
1495 continue;
1496
1497 /* new */
1498 be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1499 new++;
1500 }
1501
Liam Girdwood103d84a2012-11-19 14:39:15 +00001502 dev_dbg(fe->dev, "ASoC: found %d new BE paths\n", new);
Liam Girdwood01d75842012-04-25 12:12:49 +01001503 return new;
1504}
1505
1506/*
1507 * Find the corresponding BE DAIs that source or sink audio to this
1508 * FE substream.
1509 */
Liam Girdwood23607022014-01-17 17:03:55 +00001510int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
Liam Girdwood01d75842012-04-25 12:12:49 +01001511 int stream, struct snd_soc_dapm_widget_list **list, int new)
1512{
1513 if (new)
1514 return dpcm_add_paths(fe, stream, list);
1515 else
1516 return dpcm_prune_paths(fe, stream, list);
1517}
1518
Liam Girdwood23607022014-01-17 17:03:55 +00001519void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001520{
1521 struct snd_soc_dpcm *dpcm;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001522 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001523
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001524 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001525 for_each_dpcm_be(fe, stream, dpcm)
Liam Girdwood01d75842012-04-25 12:12:49 +01001526 dpcm->be->dpcm[stream].runtime_update =
1527 SND_SOC_DPCM_UPDATE_NO;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001528 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001529}
1530
1531static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe,
1532 int stream)
1533{
1534 struct snd_soc_dpcm *dpcm;
1535
1536 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001537 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001538
1539 struct snd_soc_pcm_runtime *be = dpcm->be;
1540 struct snd_pcm_substream *be_substream =
1541 snd_soc_dpcm_get_substream(be, stream);
1542
1543 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001544 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001545 stream ? "capture" : "playback",
1546 be->dpcm[stream].state);
1547
1548 if (--be->dpcm[stream].users != 0)
1549 continue;
1550
1551 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1552 continue;
1553
1554 soc_pcm_close(be_substream);
1555 be_substream->runtime = NULL;
1556 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1557 }
1558}
1559
Liam Girdwood23607022014-01-17 17:03:55 +00001560int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001561{
1562 struct snd_soc_dpcm *dpcm;
1563 int err, count = 0;
1564
1565 /* only startup BE DAIs that are either sinks or sources to this FE DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001566 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001567
1568 struct snd_soc_pcm_runtime *be = dpcm->be;
1569 struct snd_pcm_substream *be_substream =
1570 snd_soc_dpcm_get_substream(be, stream);
1571
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001572 if (!be_substream) {
1573 dev_err(be->dev, "ASoC: no backend %s stream\n",
1574 stream ? "capture" : "playback");
1575 continue;
1576 }
1577
Liam Girdwood01d75842012-04-25 12:12:49 +01001578 /* is this op for this BE ? */
1579 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1580 continue;
1581
1582 /* first time the dpcm is open ? */
1583 if (be->dpcm[stream].users == DPCM_MAX_BE_USERS)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001584 dev_err(be->dev, "ASoC: too many users %s at open %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001585 stream ? "capture" : "playback",
1586 be->dpcm[stream].state);
1587
1588 if (be->dpcm[stream].users++ != 0)
1589 continue;
1590
1591 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
1592 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
1593 continue;
1594
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001595 dev_dbg(be->dev, "ASoC: open %s BE %s\n",
1596 stream ? "capture" : "playback", be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001597
1598 be_substream->runtime = be->dpcm[stream].runtime;
1599 err = soc_pcm_open(be_substream);
1600 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001601 dev_err(be->dev, "ASoC: BE open failed %d\n", err);
Liam Girdwood01d75842012-04-25 12:12:49 +01001602 be->dpcm[stream].users--;
1603 if (be->dpcm[stream].users < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001604 dev_err(be->dev, "ASoC: no users %s at unwind %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001605 stream ? "capture" : "playback",
1606 be->dpcm[stream].state);
1607
1608 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1609 goto unwind;
1610 }
1611
1612 be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1613 count++;
1614 }
1615
1616 return count;
1617
1618unwind:
1619 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001620 for_each_dpcm_be_rollback(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001621 struct snd_soc_pcm_runtime *be = dpcm->be;
1622 struct snd_pcm_substream *be_substream =
1623 snd_soc_dpcm_get_substream(be, stream);
1624
1625 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1626 continue;
1627
1628 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001629 dev_err(be->dev, "ASoC: no users %s at close %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001630 stream ? "capture" : "playback",
1631 be->dpcm[stream].state);
1632
1633 if (--be->dpcm[stream].users != 0)
1634 continue;
1635
1636 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1637 continue;
1638
1639 soc_pcm_close(be_substream);
1640 be_substream->runtime = NULL;
1641 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1642 }
1643
1644 return err;
1645}
1646
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001647static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
Jerome Brunet435ffb72018-07-05 12:13:48 +02001648 struct snd_soc_pcm_stream *stream)
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001649{
1650 runtime->hw.rate_min = stream->rate_min;
Charles Keepaxe33ffbd9c2018-08-27 14:26:47 +01001651 runtime->hw.rate_max = min_not_zero(stream->rate_max, UINT_MAX);
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001652 runtime->hw.channels_min = stream->channels_min;
1653 runtime->hw.channels_max = stream->channels_max;
Lars-Peter Clausen002220a2014-01-06 14:19:07 +01001654 if (runtime->hw.formats)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001655 runtime->hw.formats &= stream->formats;
Lars-Peter Clausen002220a2014-01-06 14:19:07 +01001656 else
Jerome Brunet435ffb72018-07-05 12:13:48 +02001657 runtime->hw.formats = stream->formats;
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001658 runtime->hw.rates = stream->rates;
1659}
1660
Jerome Brunet435ffb72018-07-05 12:13:48 +02001661static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream,
1662 u64 *formats)
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001663{
1664 struct snd_soc_pcm_runtime *fe = substream->private_data;
1665 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001666 struct snd_soc_dai *dai;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001667 int stream = substream->stream;
1668
1669 if (!fe->dai_link->dpcm_merged_format)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001670 return;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001671
1672 /*
1673 * It returns merged BE codec format
1674 * if FE want to use it (= dpcm_merged_format)
1675 */
1676
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001677 for_each_dpcm_be(fe, stream, dpcm) {
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001678 struct snd_soc_pcm_runtime *be = dpcm->be;
1679 struct snd_soc_dai_driver *codec_dai_drv;
1680 struct snd_soc_pcm_stream *codec_stream;
1681 int i;
1682
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001683 for_each_rtd_codec_dai(be, i, dai) {
Jerome Brunet4febced2018-06-27 17:36:38 +02001684 /*
1685 * Skip CODECs which don't support the current stream
1686 * type. See soc_pcm_init_runtime_hw() for more details
1687 */
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001688 if (!snd_soc_dai_stream_valid(dai, stream))
Jerome Brunet4febced2018-06-27 17:36:38 +02001689 continue;
1690
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001691 codec_dai_drv = dai->driver;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001692 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1693 codec_stream = &codec_dai_drv->playback;
1694 else
1695 codec_stream = &codec_dai_drv->capture;
1696
Jerome Brunet435ffb72018-07-05 12:13:48 +02001697 *formats &= codec_stream->formats;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001698 }
1699 }
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001700}
1701
Jerome Brunet435ffb72018-07-05 12:13:48 +02001702static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream,
1703 unsigned int *channels_min,
1704 unsigned int *channels_max)
Jiada Wangf4c277b2018-06-20 18:25:20 +09001705{
1706 struct snd_soc_pcm_runtime *fe = substream->private_data;
1707 struct snd_soc_dpcm *dpcm;
1708 int stream = substream->stream;
1709
1710 if (!fe->dai_link->dpcm_merged_chan)
1711 return;
1712
Jiada Wangf4c277b2018-06-20 18:25:20 +09001713 /*
1714 * It returns merged BE codec channel;
1715 * if FE want to use it (= dpcm_merged_chan)
1716 */
1717
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001718 for_each_dpcm_be(fe, stream, dpcm) {
Jiada Wangf4c277b2018-06-20 18:25:20 +09001719 struct snd_soc_pcm_runtime *be = dpcm->be;
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001720 struct snd_soc_dai_driver *cpu_dai_drv = be->cpu_dai->driver;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001721 struct snd_soc_dai_driver *codec_dai_drv;
1722 struct snd_soc_pcm_stream *codec_stream;
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001723 struct snd_soc_pcm_stream *cpu_stream;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001724
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001725 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1726 cpu_stream = &cpu_dai_drv->playback;
1727 else
1728 cpu_stream = &cpu_dai_drv->capture;
1729
1730 *channels_min = max(*channels_min, cpu_stream->channels_min);
1731 *channels_max = min(*channels_max, cpu_stream->channels_max);
1732
1733 /*
1734 * chan min/max cannot be enforced if there are multiple CODEC
1735 * DAIs connected to a single CPU DAI, use CPU DAI's directly
1736 */
1737 if (be->num_codecs == 1) {
1738 codec_dai_drv = be->codec_dais[0]->driver;
1739
Jiada Wangf4c277b2018-06-20 18:25:20 +09001740 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1741 codec_stream = &codec_dai_drv->playback;
1742 else
1743 codec_stream = &codec_dai_drv->capture;
1744
1745 *channels_min = max(*channels_min,
1746 codec_stream->channels_min);
1747 *channels_max = min(*channels_max,
1748 codec_stream->channels_max);
1749 }
1750 }
1751}
1752
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001753static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream,
1754 unsigned int *rates,
1755 unsigned int *rate_min,
1756 unsigned int *rate_max)
1757{
1758 struct snd_soc_pcm_runtime *fe = substream->private_data;
1759 struct snd_soc_dpcm *dpcm;
1760 int stream = substream->stream;
1761
1762 if (!fe->dai_link->dpcm_merged_rate)
1763 return;
1764
1765 /*
1766 * It returns merged BE codec channel;
1767 * if FE want to use it (= dpcm_merged_chan)
1768 */
1769
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001770 for_each_dpcm_be(fe, stream, dpcm) {
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001771 struct snd_soc_pcm_runtime *be = dpcm->be;
1772 struct snd_soc_dai_driver *cpu_dai_drv = be->cpu_dai->driver;
1773 struct snd_soc_dai_driver *codec_dai_drv;
1774 struct snd_soc_pcm_stream *codec_stream;
1775 struct snd_soc_pcm_stream *cpu_stream;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001776 struct snd_soc_dai *dai;
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001777 int i;
1778
1779 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1780 cpu_stream = &cpu_dai_drv->playback;
1781 else
1782 cpu_stream = &cpu_dai_drv->capture;
1783
1784 *rate_min = max(*rate_min, cpu_stream->rate_min);
1785 *rate_max = min_not_zero(*rate_max, cpu_stream->rate_max);
1786 *rates = snd_pcm_rate_mask_intersect(*rates, cpu_stream->rates);
1787
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001788 for_each_rtd_codec_dai(be, i, dai) {
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001789 /*
1790 * Skip CODECs which don't support the current stream
1791 * type. See soc_pcm_init_runtime_hw() for more details
1792 */
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001793 if (!snd_soc_dai_stream_valid(dai, stream))
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001794 continue;
1795
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001796 codec_dai_drv = dai->driver;
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001797 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1798 codec_stream = &codec_dai_drv->playback;
1799 else
1800 codec_stream = &codec_dai_drv->capture;
1801
1802 *rate_min = max(*rate_min, codec_stream->rate_min);
1803 *rate_max = min_not_zero(*rate_max,
1804 codec_stream->rate_max);
1805 *rates = snd_pcm_rate_mask_intersect(*rates,
1806 codec_stream->rates);
1807 }
1808 }
1809}
1810
Mark Brown45c0a182012-05-09 21:46:27 +01001811static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001812{
1813 struct snd_pcm_runtime *runtime = substream->runtime;
1814 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1815 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
1816 struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
1817
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001818 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001819 dpcm_init_runtime_hw(runtime, &cpu_dai_drv->playback);
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001820 else
Jerome Brunet435ffb72018-07-05 12:13:48 +02001821 dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture);
Jiada Wangf4c277b2018-06-20 18:25:20 +09001822
Jerome Brunet435ffb72018-07-05 12:13:48 +02001823 dpcm_runtime_merge_format(substream, &runtime->hw.formats);
1824 dpcm_runtime_merge_chan(substream, &runtime->hw.channels_min,
1825 &runtime->hw.channels_max);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001826 dpcm_runtime_merge_rate(substream, &runtime->hw.rates,
1827 &runtime->hw.rate_min, &runtime->hw.rate_max);
Liam Girdwood01d75842012-04-25 12:12:49 +01001828}
1829
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001830static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
1831
1832/* Set FE's runtime_update state; the state is protected via PCM stream lock
1833 * for avoiding the race with trigger callback.
1834 * If the state is unset and a trigger is pending while the previous operation,
1835 * process the pending trigger action here.
1836 */
1837static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
1838 int stream, enum snd_soc_dpcm_update state)
1839{
1840 struct snd_pcm_substream *substream =
1841 snd_soc_dpcm_get_substream(fe, stream);
1842
1843 snd_pcm_stream_lock_irq(substream);
1844 if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) {
1845 dpcm_fe_dai_do_trigger(substream,
1846 fe->dpcm[stream].trigger_pending - 1);
1847 fe->dpcm[stream].trigger_pending = 0;
1848 }
1849 fe->dpcm[stream].runtime_update = state;
1850 snd_pcm_stream_unlock_irq(substream);
1851}
1852
PC Liao906c7d62015-12-11 11:33:51 +08001853static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
1854 int stream)
1855{
1856 struct snd_soc_dpcm *dpcm;
1857 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
1858 struct snd_soc_dai *fe_cpu_dai = fe->cpu_dai;
1859 int err;
1860
1861 /* apply symmetry for FE */
1862 if (soc_pcm_has_symmetry(fe_substream))
1863 fe_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1864
1865 /* Symmetry only applies if we've got an active stream. */
1866 if (fe_cpu_dai->active) {
1867 err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai);
1868 if (err < 0)
1869 return err;
1870 }
1871
1872 /* apply symmetry for BE */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001873 for_each_dpcm_be(fe, stream, dpcm) {
PC Liao906c7d62015-12-11 11:33:51 +08001874 struct snd_soc_pcm_runtime *be = dpcm->be;
1875 struct snd_pcm_substream *be_substream =
1876 snd_soc_dpcm_get_substream(be, stream);
Jerome Brunet6246f282019-04-01 15:03:54 +02001877 struct snd_soc_pcm_runtime *rtd;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001878 struct snd_soc_dai *codec_dai;
PC Liao906c7d62015-12-11 11:33:51 +08001879 int i;
1880
Jerome Brunet6246f282019-04-01 15:03:54 +02001881 /* A backend may not have the requested substream */
1882 if (!be_substream)
1883 continue;
1884
1885 rtd = be_substream->private_data;
Jeeja KPf1176612016-09-06 14:17:55 +05301886 if (rtd->dai_link->be_hw_params_fixup)
1887 continue;
1888
PC Liao906c7d62015-12-11 11:33:51 +08001889 if (soc_pcm_has_symmetry(be_substream))
1890 be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1891
1892 /* Symmetry only applies if we've got an active stream. */
1893 if (rtd->cpu_dai->active) {
Kai Chieh Chuang99bcedb2018-05-28 10:18:19 +08001894 err = soc_pcm_apply_symmetry(fe_substream,
1895 rtd->cpu_dai);
PC Liao906c7d62015-12-11 11:33:51 +08001896 if (err < 0)
1897 return err;
1898 }
1899
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001900 for_each_rtd_codec_dai(rtd, i, codec_dai) {
1901 if (codec_dai->active) {
Kai Chieh Chuang99bcedb2018-05-28 10:18:19 +08001902 err = soc_pcm_apply_symmetry(fe_substream,
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001903 codec_dai);
PC Liao906c7d62015-12-11 11:33:51 +08001904 if (err < 0)
1905 return err;
1906 }
1907 }
1908 }
1909
1910 return 0;
1911}
1912
Liam Girdwood01d75842012-04-25 12:12:49 +01001913static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
1914{
1915 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
1916 struct snd_pcm_runtime *runtime = fe_substream->runtime;
1917 int stream = fe_substream->stream, ret = 0;
1918
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001919 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001920
1921 ret = dpcm_be_dai_startup(fe, fe_substream->stream);
1922 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001923 dev_err(fe->dev,"ASoC: failed to start some BEs %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001924 goto be_err;
1925 }
1926
Liam Girdwood103d84a2012-11-19 14:39:15 +00001927 dev_dbg(fe->dev, "ASoC: open FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001928
1929 /* start the DAI frontend */
1930 ret = soc_pcm_open(fe_substream);
1931 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001932 dev_err(fe->dev,"ASoC: failed to start FE %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001933 goto unwind;
1934 }
1935
1936 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1937
1938 dpcm_set_fe_runtime(fe_substream);
1939 snd_pcm_limit_hw_rates(runtime);
1940
PC Liao906c7d62015-12-11 11:33:51 +08001941 ret = dpcm_apply_symmetry(fe_substream, stream);
1942 if (ret < 0) {
1943 dev_err(fe->dev, "ASoC: failed to apply dpcm symmetry %d\n",
1944 ret);
1945 goto unwind;
1946 }
1947
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001948 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001949 return 0;
1950
1951unwind:
1952 dpcm_be_dai_startup_unwind(fe, fe_substream->stream);
1953be_err:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001954 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001955 return ret;
1956}
1957
Liam Girdwood23607022014-01-17 17:03:55 +00001958int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001959{
1960 struct snd_soc_dpcm *dpcm;
1961
1962 /* only shutdown BEs that are either sinks or sources to this FE DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001963 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001964
1965 struct snd_soc_pcm_runtime *be = dpcm->be;
1966 struct snd_pcm_substream *be_substream =
1967 snd_soc_dpcm_get_substream(be, stream);
1968
1969 /* is this op for this BE ? */
1970 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1971 continue;
1972
1973 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001974 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001975 stream ? "capture" : "playback",
1976 be->dpcm[stream].state);
1977
1978 if (--be->dpcm[stream].users != 0)
1979 continue;
1980
1981 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Kai Chieh Chuang9c0ac702018-05-28 10:18:18 +08001982 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) {
1983 soc_pcm_hw_free(be_substream);
1984 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1985 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001986
Liam Girdwood103d84a2012-11-19 14:39:15 +00001987 dev_dbg(be->dev, "ASoC: close BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001988 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001989
1990 soc_pcm_close(be_substream);
1991 be_substream->runtime = NULL;
1992
1993 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1994 }
1995 return 0;
1996}
1997
1998static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
1999{
2000 struct snd_soc_pcm_runtime *fe = substream->private_data;
2001 int stream = substream->stream;
2002
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002003 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002004
2005 /* shutdown the BEs */
2006 dpcm_be_dai_shutdown(fe, substream->stream);
2007
Liam Girdwood103d84a2012-11-19 14:39:15 +00002008 dev_dbg(fe->dev, "ASoC: close FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002009
2010 /* now shutdown the frontend */
2011 soc_pcm_close(substream);
2012
2013 /* run the stream event for each BE */
2014 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
2015
2016 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002017 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002018 return 0;
2019}
2020
Liam Girdwood23607022014-01-17 17:03:55 +00002021int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002022{
2023 struct snd_soc_dpcm *dpcm;
2024
2025 /* only hw_params backends that are either sinks or sources
2026 * to this frontend DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002027 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002028
2029 struct snd_soc_pcm_runtime *be = dpcm->be;
2030 struct snd_pcm_substream *be_substream =
2031 snd_soc_dpcm_get_substream(be, stream);
2032
2033 /* is this op for this BE ? */
2034 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2035 continue;
2036
2037 /* only free hw when no longer used - check all FEs */
2038 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2039 continue;
2040
Qiao Zhou36fba622014-12-03 10:13:43 +08002041 /* do not free hw if this BE is used by other FE */
2042 if (be->dpcm[stream].users > 1)
2043 continue;
2044
Liam Girdwood01d75842012-04-25 12:12:49 +01002045 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2046 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
2047 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Patrick Lai08b27842012-12-19 19:36:02 -08002048 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
Vinod Koul5e82d2b2016-02-01 22:26:40 +05302049 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
2050 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
Liam Girdwood01d75842012-04-25 12:12:49 +01002051 continue;
2052
Liam Girdwood103d84a2012-11-19 14:39:15 +00002053 dev_dbg(be->dev, "ASoC: hw_free BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002054 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002055
2056 soc_pcm_hw_free(be_substream);
2057
2058 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
2059 }
2060
2061 return 0;
2062}
2063
Mark Brown45c0a182012-05-09 21:46:27 +01002064static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002065{
2066 struct snd_soc_pcm_runtime *fe = substream->private_data;
2067 int err, stream = substream->stream;
2068
2069 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002070 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002071
Liam Girdwood103d84a2012-11-19 14:39:15 +00002072 dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002073
2074 /* call hw_free on the frontend */
2075 err = soc_pcm_hw_free(substream);
2076 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002077 dev_err(fe->dev,"ASoC: hw_free FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002078 fe->dai_link->name);
2079
2080 /* only hw_params backends that are either sinks or sources
2081 * to this frontend DAI */
2082 err = dpcm_be_dai_hw_free(fe, stream);
2083
2084 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002085 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002086
2087 mutex_unlock(&fe->card->mutex);
2088 return 0;
2089}
2090
Liam Girdwood23607022014-01-17 17:03:55 +00002091int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002092{
2093 struct snd_soc_dpcm *dpcm;
2094 int ret;
2095
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002096 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002097
2098 struct snd_soc_pcm_runtime *be = dpcm->be;
2099 struct snd_pcm_substream *be_substream =
2100 snd_soc_dpcm_get_substream(be, stream);
2101
2102 /* is this op for this BE ? */
2103 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2104 continue;
2105
Liam Girdwood01d75842012-04-25 12:12:49 +01002106 /* copy params for each dpcm */
2107 memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params,
2108 sizeof(struct snd_pcm_hw_params));
2109
2110 /* perform any hw_params fixups */
2111 if (be->dai_link->be_hw_params_fixup) {
2112 ret = be->dai_link->be_hw_params_fixup(be,
2113 &dpcm->hw_params);
2114 if (ret < 0) {
2115 dev_err(be->dev,
Liam Girdwood103d84a2012-11-19 14:39:15 +00002116 "ASoC: hw_params BE fixup failed %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002117 ret);
2118 goto unwind;
2119 }
2120 }
2121
Libin Yangae061d22019-04-19 09:53:12 +08002122 /* copy the fixed-up hw params for BE dai */
2123 memcpy(&be->dpcm[stream].hw_params, &dpcm->hw_params,
2124 sizeof(struct snd_pcm_hw_params));
2125
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00002126 /* only allow hw_params() if no connected FEs are running */
2127 if (!snd_soc_dpcm_can_be_params(fe, be, stream))
2128 continue;
2129
2130 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
2131 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2132 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE))
2133 continue;
2134
2135 dev_dbg(be->dev, "ASoC: hw_params BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002136 be->dai_link->name);
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00002137
Liam Girdwood01d75842012-04-25 12:12:49 +01002138 ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params);
2139 if (ret < 0) {
2140 dev_err(dpcm->be->dev,
Liam Girdwood103d84a2012-11-19 14:39:15 +00002141 "ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002142 goto unwind;
2143 }
2144
2145 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2146 }
2147 return 0;
2148
2149unwind:
2150 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002151 for_each_dpcm_be_rollback(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002152 struct snd_soc_pcm_runtime *be = dpcm->be;
2153 struct snd_pcm_substream *be_substream =
2154 snd_soc_dpcm_get_substream(be, stream);
2155
2156 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2157 continue;
2158
2159 /* only allow hw_free() if no connected FEs are running */
2160 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2161 continue;
2162
2163 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
2164 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2165 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
2166 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
2167 continue;
2168
2169 soc_pcm_hw_free(be_substream);
2170 }
2171
2172 return ret;
2173}
2174
Mark Brown45c0a182012-05-09 21:46:27 +01002175static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
2176 struct snd_pcm_hw_params *params)
Liam Girdwood01d75842012-04-25 12:12:49 +01002177{
2178 struct snd_soc_pcm_runtime *fe = substream->private_data;
2179 int ret, stream = substream->stream;
2180
2181 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002182 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002183
2184 memcpy(&fe->dpcm[substream->stream].hw_params, params,
2185 sizeof(struct snd_pcm_hw_params));
2186 ret = dpcm_be_dai_hw_params(fe, substream->stream);
2187 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002188 dev_err(fe->dev,"ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002189 goto out;
2190 }
2191
Liam Girdwood103d84a2012-11-19 14:39:15 +00002192 dev_dbg(fe->dev, "ASoC: hw_params FE %s rate %d chan %x fmt %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002193 fe->dai_link->name, params_rate(params),
2194 params_channels(params), params_format(params));
2195
2196 /* call hw_params on the frontend */
2197 ret = soc_pcm_hw_params(substream, params);
2198 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002199 dev_err(fe->dev,"ASoC: hw_params FE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002200 dpcm_be_dai_hw_free(fe, stream);
2201 } else
2202 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2203
2204out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002205 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002206 mutex_unlock(&fe->card->mutex);
2207 return ret;
2208}
2209
2210static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm,
2211 struct snd_pcm_substream *substream, int cmd)
2212{
2213 int ret;
2214
Liam Girdwood103d84a2012-11-19 14:39:15 +00002215 dev_dbg(dpcm->be->dev, "ASoC: trigger BE %s cmd %d\n",
彭东林94d215c2016-09-26 08:29:31 +00002216 dpcm->be->dai_link->name, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002217
2218 ret = soc_pcm_trigger(substream, cmd);
2219 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002220 dev_err(dpcm->be->dev,"ASoC: trigger BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002221
2222 return ret;
2223}
2224
Liam Girdwood23607022014-01-17 17:03:55 +00002225int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
Mark Brown45c0a182012-05-09 21:46:27 +01002226 int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002227{
2228 struct snd_soc_dpcm *dpcm;
2229 int ret = 0;
2230
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002231 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002232
2233 struct snd_soc_pcm_runtime *be = dpcm->be;
2234 struct snd_pcm_substream *be_substream =
2235 snd_soc_dpcm_get_substream(be, stream);
2236
2237 /* is this op for this BE ? */
2238 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2239 continue;
2240
2241 switch (cmd) {
2242 case SNDRV_PCM_TRIGGER_START:
2243 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
2244 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
2245 continue;
2246
2247 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2248 if (ret)
2249 return ret;
2250
2251 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2252 break;
2253 case SNDRV_PCM_TRIGGER_RESUME:
2254 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
2255 continue;
2256
2257 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2258 if (ret)
2259 return ret;
2260
2261 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2262 break;
2263 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2264 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
2265 continue;
2266
2267 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2268 if (ret)
2269 return ret;
2270
2271 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2272 break;
2273 case SNDRV_PCM_TRIGGER_STOP:
2274 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2275 continue;
2276
2277 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2278 continue;
2279
2280 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2281 if (ret)
2282 return ret;
2283
2284 be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2285 break;
2286 case SNDRV_PCM_TRIGGER_SUSPEND:
Nicolin Chen868a6ca2014-05-12 20:12:05 +08002287 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
Liam Girdwood01d75842012-04-25 12:12:49 +01002288 continue;
2289
2290 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2291 continue;
2292
2293 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2294 if (ret)
2295 return ret;
2296
2297 be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND;
2298 break;
2299 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2300 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2301 continue;
2302
2303 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2304 continue;
2305
2306 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2307 if (ret)
2308 return ret;
2309
2310 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2311 break;
2312 }
2313 }
2314
2315 return ret;
2316}
2317EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
2318
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002319static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002320{
2321 struct snd_soc_pcm_runtime *fe = substream->private_data;
2322 int stream = substream->stream, ret;
2323 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
2324
2325 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
2326
2327 switch (trigger) {
2328 case SND_SOC_DPCM_TRIGGER_PRE:
2329 /* call trigger on the frontend before the backend. */
2330
Liam Girdwood103d84a2012-11-19 14:39:15 +00002331 dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002332 fe->dai_link->name, cmd);
2333
2334 ret = soc_pcm_trigger(substream, cmd);
2335 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002336 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002337 goto out;
2338 }
2339
2340 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2341 break;
2342 case SND_SOC_DPCM_TRIGGER_POST:
2343 /* call trigger on the frontend after the backend. */
2344
2345 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2346 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002347 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002348 goto out;
2349 }
2350
Liam Girdwood103d84a2012-11-19 14:39:15 +00002351 dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002352 fe->dai_link->name, cmd);
2353
2354 ret = soc_pcm_trigger(substream, cmd);
2355 break;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002356 case SND_SOC_DPCM_TRIGGER_BESPOKE:
2357 /* bespoke trigger() - handles both FE and BEs */
2358
Liam Girdwood103d84a2012-11-19 14:39:15 +00002359 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd %d\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002360 fe->dai_link->name, cmd);
2361
2362 ret = soc_pcm_bespoke_trigger(substream, cmd);
2363 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002364 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002365 goto out;
2366 }
2367 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002368 default:
Liam Girdwood103d84a2012-11-19 14:39:15 +00002369 dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd,
Liam Girdwood01d75842012-04-25 12:12:49 +01002370 fe->dai_link->name);
2371 ret = -EINVAL;
2372 goto out;
2373 }
2374
2375 switch (cmd) {
2376 case SNDRV_PCM_TRIGGER_START:
2377 case SNDRV_PCM_TRIGGER_RESUME:
2378 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2379 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2380 break;
2381 case SNDRV_PCM_TRIGGER_STOP:
2382 case SNDRV_PCM_TRIGGER_SUSPEND:
Liam Girdwood01d75842012-04-25 12:12:49 +01002383 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2384 break;
Patrick Lai9f169b92016-12-31 22:44:39 -08002385 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2386 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2387 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002388 }
2389
2390out:
2391 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
2392 return ret;
2393}
2394
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002395static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
2396{
2397 struct snd_soc_pcm_runtime *fe = substream->private_data;
2398 int stream = substream->stream;
2399
2400 /* if FE's runtime_update is already set, we're in race;
2401 * process this trigger later at exit
2402 */
2403 if (fe->dpcm[stream].runtime_update != SND_SOC_DPCM_UPDATE_NO) {
2404 fe->dpcm[stream].trigger_pending = cmd + 1;
2405 return 0; /* delayed, assuming it's successful */
2406 }
2407
2408 /* we're alone, let's trigger */
2409 return dpcm_fe_dai_do_trigger(substream, cmd);
2410}
2411
Liam Girdwood23607022014-01-17 17:03:55 +00002412int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002413{
2414 struct snd_soc_dpcm *dpcm;
2415 int ret = 0;
2416
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002417 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002418
2419 struct snd_soc_pcm_runtime *be = dpcm->be;
2420 struct snd_pcm_substream *be_substream =
2421 snd_soc_dpcm_get_substream(be, stream);
2422
2423 /* is this op for this BE ? */
2424 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2425 continue;
2426
2427 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
Koro Chen95f444d2015-10-28 10:15:34 +08002428 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
Libin Yang5087a8f2019-05-08 10:32:41 +08002429 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND) &&
2430 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Liam Girdwood01d75842012-04-25 12:12:49 +01002431 continue;
2432
Liam Girdwood103d84a2012-11-19 14:39:15 +00002433 dev_dbg(be->dev, "ASoC: prepare BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002434 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002435
2436 ret = soc_pcm_prepare(be_substream);
2437 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002438 dev_err(be->dev, "ASoC: backend prepare failed %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002439 ret);
2440 break;
2441 }
2442
2443 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2444 }
2445 return ret;
2446}
2447
Mark Brown45c0a182012-05-09 21:46:27 +01002448static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002449{
2450 struct snd_soc_pcm_runtime *fe = substream->private_data;
2451 int stream = substream->stream, ret = 0;
2452
2453 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2454
Liam Girdwood103d84a2012-11-19 14:39:15 +00002455 dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002456
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002457 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002458
2459 /* there is no point preparing this FE if there are no BEs */
2460 if (list_empty(&fe->dpcm[stream].be_clients)) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002461 dev_err(fe->dev, "ASoC: no backend DAIs enabled for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002462 fe->dai_link->name);
2463 ret = -EINVAL;
2464 goto out;
2465 }
2466
2467 ret = dpcm_be_dai_prepare(fe, substream->stream);
2468 if (ret < 0)
2469 goto out;
2470
2471 /* call prepare on the frontend */
2472 ret = soc_pcm_prepare(substream);
2473 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002474 dev_err(fe->dev,"ASoC: prepare FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002475 fe->dai_link->name);
2476 goto out;
2477 }
2478
2479 /* run the stream event for each BE */
2480 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
2481 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2482
2483out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002484 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002485 mutex_unlock(&fe->card->mutex);
2486
2487 return ret;
2488}
2489
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01002490static int soc_pcm_ioctl(struct snd_pcm_substream *substream,
2491 unsigned int cmd, void *arg)
2492{
2493 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +00002494 struct snd_soc_component *component;
2495 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01002496
Kuninori Morimotob8135862017-10-11 01:37:23 +00002497 for_each_rtdcom(rtd, rtdcom) {
2498 component = rtdcom->component;
2499
Kuninori Morimotob8135862017-10-11 01:37:23 +00002500 if (!component->driver->ops ||
2501 !component->driver->ops->ioctl)
2502 continue;
2503
2504 /* FIXME: use 1st ioctl */
2505 return component->driver->ops->ioctl(substream, cmd, arg);
2506 }
2507
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01002508 return snd_pcm_lib_ioctl(substream, cmd, arg);
2509}
2510
Liam Girdwood618dae12012-04-25 12:12:51 +01002511static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
2512{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002513 struct snd_pcm_substream *substream =
2514 snd_soc_dpcm_get_substream(fe, stream);
2515 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01002516 int err;
Liam Girdwood01d75842012-04-25 12:12:49 +01002517
Liam Girdwood103d84a2012-11-19 14:39:15 +00002518 dev_dbg(fe->dev, "ASoC: runtime %s close on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002519 stream ? "capture" : "playback", fe->dai_link->name);
2520
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002521 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2522 /* call bespoke trigger - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002523 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002524 fe->dai_link->name);
2525
2526 err = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
2527 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002528 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002529 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002530 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002531 fe->dai_link->name);
2532
2533 err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
2534 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002535 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002536 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002537
2538 err = dpcm_be_dai_hw_free(fe, stream);
2539 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002540 dev_err(fe->dev,"ASoC: hw_free FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002541
2542 err = dpcm_be_dai_shutdown(fe, stream);
2543 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002544 dev_err(fe->dev,"ASoC: shutdown FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002545
2546 /* run the stream event for each BE */
2547 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2548
2549 return 0;
2550}
2551
2552static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
2553{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002554 struct snd_pcm_substream *substream =
2555 snd_soc_dpcm_get_substream(fe, stream);
Liam Girdwood618dae12012-04-25 12:12:51 +01002556 struct snd_soc_dpcm *dpcm;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002557 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01002558 int ret;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002559 unsigned long flags;
Liam Girdwood618dae12012-04-25 12:12:51 +01002560
Liam Girdwood103d84a2012-11-19 14:39:15 +00002561 dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002562 stream ? "capture" : "playback", fe->dai_link->name);
2563
2564 /* Only start the BE if the FE is ready */
2565 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
2566 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE)
2567 return -EINVAL;
2568
2569 /* startup must always be called for new BEs */
2570 ret = dpcm_be_dai_startup(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002571 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002572 goto disconnect;
Liam Girdwood618dae12012-04-25 12:12:51 +01002573
2574 /* keep going if FE state is > open */
2575 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN)
2576 return 0;
2577
2578 ret = dpcm_be_dai_hw_params(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002579 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002580 goto close;
Liam Girdwood618dae12012-04-25 12:12:51 +01002581
2582 /* keep going if FE state is > hw_params */
2583 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS)
2584 return 0;
2585
2586
2587 ret = dpcm_be_dai_prepare(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002588 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002589 goto hw_free;
Liam Girdwood618dae12012-04-25 12:12:51 +01002590
2591 /* run the stream event for each BE */
2592 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2593
2594 /* keep going if FE state is > prepare */
2595 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE ||
2596 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP)
2597 return 0;
2598
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002599 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2600 /* call trigger on the frontend - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002601 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002602 fe->dai_link->name);
Liam Girdwood618dae12012-04-25 12:12:51 +01002603
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002604 ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
2605 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002606 dev_err(fe->dev,"ASoC: bespoke trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002607 goto hw_free;
2608 }
2609 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002610 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002611 fe->dai_link->name);
2612
2613 ret = dpcm_be_dai_trigger(fe, stream,
2614 SNDRV_PCM_TRIGGER_START);
2615 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002616 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002617 goto hw_free;
2618 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002619 }
2620
2621 return 0;
2622
2623hw_free:
2624 dpcm_be_dai_hw_free(fe, stream);
2625close:
2626 dpcm_be_dai_shutdown(fe, stream);
2627disconnect:
2628 /* disconnect any non started BEs */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002629 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002630 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood618dae12012-04-25 12:12:51 +01002631 struct snd_soc_pcm_runtime *be = dpcm->be;
2632 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2633 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2634 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002635 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood618dae12012-04-25 12:12:51 +01002636
2637 return ret;
2638}
2639
2640static int dpcm_run_new_update(struct snd_soc_pcm_runtime *fe, int stream)
2641{
2642 int ret;
2643
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002644 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood618dae12012-04-25 12:12:51 +01002645 ret = dpcm_run_update_startup(fe, stream);
2646 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002647 dev_err(fe->dev, "ASoC: failed to startup some BEs\n");
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002648 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood618dae12012-04-25 12:12:51 +01002649
2650 return ret;
2651}
2652
2653static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream)
2654{
2655 int ret;
2656
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002657 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood618dae12012-04-25 12:12:51 +01002658 ret = dpcm_run_update_shutdown(fe, stream);
2659 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002660 dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n");
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002661 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood618dae12012-04-25 12:12:51 +01002662
2663 return ret;
2664}
2665
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002666static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
2667{
2668 struct snd_soc_dapm_widget_list *list;
2669 int count, paths;
2670
2671 if (!fe->dai_link->dynamic)
2672 return 0;
2673
2674 /* only check active links */
2675 if (!fe->cpu_dai->active)
2676 return 0;
2677
2678 /* DAPM sync will call this to update DSP paths */
2679 dev_dbg(fe->dev, "ASoC: DPCM %s runtime update for FE %s\n",
2680 new ? "new" : "old", fe->dai_link->name);
2681
2682 /* skip if FE doesn't have playback capability */
Kuninori Morimoto467fece2019-07-22 10:36:16 +09002683 if (!snd_soc_dai_stream_valid(fe->cpu_dai, SNDRV_PCM_STREAM_PLAYBACK) ||
2684 !snd_soc_dai_stream_valid(fe->codec_dai, SNDRV_PCM_STREAM_PLAYBACK))
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002685 goto capture;
2686
2687 /* skip if FE isn't currently playing */
2688 if (!fe->cpu_dai->playback_active || !fe->codec_dai->playback_active)
2689 goto capture;
2690
2691 paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list);
2692 if (paths < 0) {
2693 dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
2694 fe->dai_link->name, "playback");
2695 return paths;
2696 }
2697
2698 /* update any playback paths */
2699 count = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, new);
2700 if (count) {
2701 if (new)
2702 dpcm_run_new_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
2703 else
2704 dpcm_run_old_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
2705
2706 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
2707 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
2708 }
2709
2710 dpcm_path_put(&list);
2711
2712capture:
2713 /* skip if FE doesn't have capture capability */
Kuninori Morimoto467fece2019-07-22 10:36:16 +09002714 if (!snd_soc_dai_stream_valid(fe->cpu_dai, SNDRV_PCM_STREAM_CAPTURE) ||
2715 !snd_soc_dai_stream_valid(fe->codec_dai, SNDRV_PCM_STREAM_CAPTURE))
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002716 return 0;
2717
2718 /* skip if FE isn't currently capturing */
2719 if (!fe->cpu_dai->capture_active || !fe->codec_dai->capture_active)
2720 return 0;
2721
2722 paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list);
2723 if (paths < 0) {
2724 dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
2725 fe->dai_link->name, "capture");
2726 return paths;
2727 }
2728
2729 /* update any old capture paths */
2730 count = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, new);
2731 if (count) {
2732 if (new)
2733 dpcm_run_new_update(fe, SNDRV_PCM_STREAM_CAPTURE);
2734 else
2735 dpcm_run_old_update(fe, SNDRV_PCM_STREAM_CAPTURE);
2736
2737 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
2738 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
2739 }
2740
2741 dpcm_path_put(&list);
2742
2743 return 0;
2744}
2745
Liam Girdwood618dae12012-04-25 12:12:51 +01002746/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
2747 * any DAI links.
2748 */
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002749int soc_dpcm_runtime_update(struct snd_soc_card *card)
Liam Girdwood618dae12012-04-25 12:12:51 +01002750{
Mengdong Lin1a497982015-11-18 02:34:11 -05002751 struct snd_soc_pcm_runtime *fe;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002752 int ret = 0;
Liam Girdwood618dae12012-04-25 12:12:51 +01002753
Liam Girdwood618dae12012-04-25 12:12:51 +01002754 mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002755 /* shutdown all old paths first */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002756 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002757 ret = soc_dpcm_fe_runtime_update(fe, 0);
2758 if (ret)
2759 goto out;
Liam Girdwood618dae12012-04-25 12:12:51 +01002760 }
2761
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002762 /* bring new paths up */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002763 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002764 ret = soc_dpcm_fe_runtime_update(fe, 1);
2765 if (ret)
2766 goto out;
2767 }
2768
2769out:
Liam Girdwood618dae12012-04-25 12:12:51 +01002770 mutex_unlock(&card->mutex);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002771 return ret;
Liam Girdwood618dae12012-04-25 12:12:51 +01002772}
Liam Girdwood01d75842012-04-25 12:12:49 +01002773int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute)
2774{
2775 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00002776 struct snd_soc_dai *dai;
Liam Girdwood01d75842012-04-25 12:12:49 +01002777
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002778 for_each_dpcm_be(fe, SNDRV_PCM_STREAM_PLAYBACK, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002779
2780 struct snd_soc_pcm_runtime *be = dpcm->be;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002781 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01002782
2783 if (be->dai_link->ignore_suspend)
2784 continue;
2785
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00002786 for_each_rtd_codec_dai(be, i, dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002787 struct snd_soc_dai_driver *drv = dai->driver;
Liam Girdwood01d75842012-04-25 12:12:49 +01002788
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002789 dev_dbg(be->dev, "ASoC: BE digital mute %s\n",
2790 be->dai_link->name);
2791
2792 if (drv->ops && drv->ops->digital_mute &&
2793 dai->playback_active)
2794 drv->ops->digital_mute(dai, mute);
2795 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002796 }
2797
2798 return 0;
2799}
2800
Mark Brown45c0a182012-05-09 21:46:27 +01002801static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002802{
2803 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
2804 struct snd_soc_dpcm *dpcm;
2805 struct snd_soc_dapm_widget_list *list;
2806 int ret;
2807 int stream = fe_substream->stream;
2808
2809 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2810 fe->dpcm[stream].runtime = fe_substream->runtime;
2811
Qiao Zhou8f70e512014-09-10 17:54:07 +08002812 ret = dpcm_path_get(fe, stream, &list);
2813 if (ret < 0) {
2814 mutex_unlock(&fe->card->mutex);
2815 return ret;
2816 } else if (ret == 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002817 dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002818 fe->dai_link->name, stream ? "capture" : "playback");
Liam Girdwood01d75842012-04-25 12:12:49 +01002819 }
2820
2821 /* calculate valid and active FE <-> BE dpcms */
2822 dpcm_process_paths(fe, stream, &list, 1);
2823
2824 ret = dpcm_fe_dai_startup(fe_substream);
2825 if (ret < 0) {
2826 /* clean up all links */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002827 for_each_dpcm_be(fe, stream, dpcm)
Liam Girdwood01d75842012-04-25 12:12:49 +01002828 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2829
2830 dpcm_be_disconnect(fe, stream);
2831 fe->dpcm[stream].runtime = NULL;
2832 }
2833
2834 dpcm_clear_pending_state(fe, stream);
2835 dpcm_path_put(&list);
2836 mutex_unlock(&fe->card->mutex);
2837 return ret;
2838}
2839
Mark Brown45c0a182012-05-09 21:46:27 +01002840static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002841{
2842 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
2843 struct snd_soc_dpcm *dpcm;
2844 int stream = fe_substream->stream, ret;
2845
2846 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2847 ret = dpcm_fe_dai_shutdown(fe_substream);
2848
2849 /* mark FE's links ready to prune */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002850 for_each_dpcm_be(fe, stream, dpcm)
Liam Girdwood01d75842012-04-25 12:12:49 +01002851 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2852
2853 dpcm_be_disconnect(fe, stream);
2854
2855 fe->dpcm[stream].runtime = NULL;
2856 mutex_unlock(&fe->card->mutex);
2857 return ret;
2858}
2859
Takashi Iwai5d61f0b2017-08-25 12:04:07 +02002860static void soc_pcm_private_free(struct snd_pcm *pcm)
2861{
2862 struct snd_soc_pcm_runtime *rtd = pcm->private_data;
Kuninori Morimotof523ace2017-09-26 01:00:53 +00002863 struct snd_soc_rtdcom_list *rtdcom;
2864 struct snd_soc_component *component;
Takashi Iwai5d61f0b2017-08-25 12:04:07 +02002865
Kuninori Morimotof30a4c32018-01-24 05:18:46 +00002866 /* need to sync the delayed work before releasing resources */
2867 flush_delayed_work(&rtd->delayed_work);
Kuninori Morimotof523ace2017-09-26 01:00:53 +00002868 for_each_rtdcom(rtd, rtdcom) {
Kuninori Morimotof523ace2017-09-26 01:00:53 +00002869 component = rtdcom->component;
2870
Kuninori Morimoto11fb14f2018-05-08 03:19:49 +00002871 if (component->driver->pcm_free)
2872 component->driver->pcm_free(pcm);
Kuninori Morimotof523ace2017-09-26 01:00:53 +00002873 }
Takashi Iwai5d61f0b2017-08-25 12:04:07 +02002874}
2875
Kuninori Morimotob8135862017-10-11 01:37:23 +00002876static int soc_rtdcom_ack(struct snd_pcm_substream *substream)
2877{
2878 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2879 struct snd_soc_rtdcom_list *rtdcom;
2880 struct snd_soc_component *component;
2881
2882 for_each_rtdcom(rtd, rtdcom) {
2883 component = rtdcom->component;
2884
2885 if (!component->driver->ops ||
2886 !component->driver->ops->ack)
2887 continue;
2888
2889 /* FIXME. it returns 1st ask now */
2890 return component->driver->ops->ack(substream);
2891 }
2892
2893 return -EINVAL;
2894}
2895
2896static int soc_rtdcom_copy_user(struct snd_pcm_substream *substream, int channel,
2897 unsigned long pos, void __user *buf,
2898 unsigned long bytes)
2899{
2900 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2901 struct snd_soc_rtdcom_list *rtdcom;
2902 struct snd_soc_component *component;
2903
2904 for_each_rtdcom(rtd, rtdcom) {
2905 component = rtdcom->component;
2906
2907 if (!component->driver->ops ||
2908 !component->driver->ops->copy_user)
2909 continue;
2910
2911 /* FIXME. it returns 1st copy now */
2912 return component->driver->ops->copy_user(substream, channel,
2913 pos, buf, bytes);
2914 }
2915
2916 return -EINVAL;
2917}
2918
2919static int soc_rtdcom_copy_kernel(struct snd_pcm_substream *substream, int channel,
2920 unsigned long pos, void *buf, unsigned long bytes)
2921{
2922 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2923 struct snd_soc_rtdcom_list *rtdcom;
2924 struct snd_soc_component *component;
2925
2926 for_each_rtdcom(rtd, rtdcom) {
2927 component = rtdcom->component;
2928
2929 if (!component->driver->ops ||
2930 !component->driver->ops->copy_kernel)
2931 continue;
2932
2933 /* FIXME. it returns 1st copy now */
2934 return component->driver->ops->copy_kernel(substream, channel,
2935 pos, buf, bytes);
2936 }
2937
2938 return -EINVAL;
2939}
2940
2941static int soc_rtdcom_fill_silence(struct snd_pcm_substream *substream, int channel,
2942 unsigned long pos, unsigned long bytes)
2943{
2944 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2945 struct snd_soc_rtdcom_list *rtdcom;
2946 struct snd_soc_component *component;
2947
2948 for_each_rtdcom(rtd, rtdcom) {
2949 component = rtdcom->component;
2950
2951 if (!component->driver->ops ||
2952 !component->driver->ops->fill_silence)
2953 continue;
2954
2955 /* FIXME. it returns 1st silence now */
2956 return component->driver->ops->fill_silence(substream, channel,
2957 pos, bytes);
2958 }
2959
2960 return -EINVAL;
2961}
2962
2963static struct page *soc_rtdcom_page(struct snd_pcm_substream *substream,
2964 unsigned long offset)
2965{
2966 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2967 struct snd_soc_rtdcom_list *rtdcom;
2968 struct snd_soc_component *component;
2969 struct page *page;
2970
2971 for_each_rtdcom(rtd, rtdcom) {
2972 component = rtdcom->component;
2973
2974 if (!component->driver->ops ||
2975 !component->driver->ops->page)
2976 continue;
2977
2978 /* FIXME. it returns 1st page now */
2979 page = component->driver->ops->page(substream, offset);
2980 if (page)
2981 return page;
2982 }
2983
2984 return NULL;
2985}
2986
2987static int soc_rtdcom_mmap(struct snd_pcm_substream *substream,
2988 struct vm_area_struct *vma)
2989{
2990 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2991 struct snd_soc_rtdcom_list *rtdcom;
2992 struct snd_soc_component *component;
2993
2994 for_each_rtdcom(rtd, rtdcom) {
2995 component = rtdcom->component;
2996
2997 if (!component->driver->ops ||
2998 !component->driver->ops->mmap)
2999 continue;
3000
3001 /* FIXME. it returns 1st mmap now */
3002 return component->driver->ops->mmap(substream, vma);
3003 }
3004
3005 return -EINVAL;
3006}
3007
Liam Girdwoodddee6272011-06-09 14:45:53 +01003008/* create a new pcm */
3009int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
3010{
Benoit Cousson2e5894d2014-07-08 23:19:35 +02003011 struct snd_soc_dai *codec_dai;
Liam Girdwoodddee6272011-06-09 14:45:53 +01003012 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimotof523ace2017-09-26 01:00:53 +00003013 struct snd_soc_component *component;
3014 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +01003015 struct snd_pcm *pcm;
3016 char new_name[64];
3017 int ret = 0, playback = 0, capture = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02003018 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01003019
Liam Girdwood01d75842012-04-25 12:12:49 +01003020 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
Liam Girdwood1e9de422014-01-07 17:51:42 +00003021 playback = rtd->dai_link->dpcm_playback;
3022 capture = rtd->dai_link->dpcm_capture;
Liam Girdwood01d75842012-04-25 12:12:49 +01003023 } else {
Jerome Bruneta3420312019-07-25 18:59:47 +02003024 /* Adapt stream for codec2codec links */
3025 struct snd_soc_pcm_stream *cpu_capture = rtd->dai_link->params ?
3026 &cpu_dai->driver->playback : &cpu_dai->driver->capture;
3027 struct snd_soc_pcm_stream *cpu_playback = rtd->dai_link->params ?
3028 &cpu_dai->driver->capture : &cpu_dai->driver->playback;
3029
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00003030 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto467fece2019-07-22 10:36:16 +09003031 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
3032 snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_PLAYBACK))
Benoit Cousson2e5894d2014-07-08 23:19:35 +02003033 playback = 1;
Kuninori Morimoto467fece2019-07-22 10:36:16 +09003034 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
3035 snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_CAPTURE))
Benoit Cousson2e5894d2014-07-08 23:19:35 +02003036 capture = 1;
3037 }
Jerome Bruneta3420312019-07-25 18:59:47 +02003038
3039 capture = capture && cpu_capture->channels_min;
3040 playback = playback && cpu_playback->channels_min;
Liam Girdwood01d75842012-04-25 12:12:49 +01003041 }
Sangsu Parka5002312012-01-02 17:15:10 +09003042
Fabio Estevamd6bead02013-08-29 10:32:13 -03003043 if (rtd->dai_link->playback_only) {
3044 playback = 1;
3045 capture = 0;
3046 }
3047
3048 if (rtd->dai_link->capture_only) {
3049 playback = 0;
3050 capture = 1;
3051 }
3052
Liam Girdwood01d75842012-04-25 12:12:49 +01003053 /* create the PCM */
Jerome Bruneta3420312019-07-25 18:59:47 +02003054 if (rtd->dai_link->params) {
3055 snprintf(new_name, sizeof(new_name), "codec2codec(%s)",
3056 rtd->dai_link->stream_name);
3057
3058 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
3059 playback, capture, &pcm);
3060 } else if (rtd->dai_link->no_pcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01003061 snprintf(new_name, sizeof(new_name), "(%s)",
3062 rtd->dai_link->stream_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003063
Liam Girdwood01d75842012-04-25 12:12:49 +01003064 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
3065 playback, capture, &pcm);
3066 } else {
3067 if (rtd->dai_link->dynamic)
3068 snprintf(new_name, sizeof(new_name), "%s (*)",
3069 rtd->dai_link->stream_name);
3070 else
3071 snprintf(new_name, sizeof(new_name), "%s %s-%d",
Benoit Cousson2e5894d2014-07-08 23:19:35 +02003072 rtd->dai_link->stream_name,
3073 (rtd->num_codecs > 1) ?
3074 "multicodec" : rtd->codec_dai->name, num);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003075
Liam Girdwood01d75842012-04-25 12:12:49 +01003076 ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
3077 capture, &pcm);
3078 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01003079 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00003080 dev_err(rtd->card->dev, "ASoC: can't create pcm for %s\n",
Liam Girdwood5cb9b742012-07-06 16:54:52 +01003081 rtd->dai_link->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003082 return ret;
3083 }
Liam Girdwood103d84a2012-11-19 14:39:15 +00003084 dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003085
3086 /* DAPM dai link stream work */
Jerome Bruneta3420312019-07-25 18:59:47 +02003087 if (rtd->dai_link->params)
3088 INIT_DELAYED_WORK(&rtd->delayed_work,
3089 codec2codec_close_delayed_work);
3090 else
3091 INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003092
Vinod Koul48c76992015-02-12 09:59:53 +05303093 pcm->nonatomic = rtd->dai_link->nonatomic;
Liam Girdwoodddee6272011-06-09 14:45:53 +01003094 rtd->pcm = pcm;
3095 pcm->private_data = rtd;
Liam Girdwood01d75842012-04-25 12:12:49 +01003096
Jerome Bruneta3420312019-07-25 18:59:47 +02003097 if (rtd->dai_link->no_pcm || rtd->dai_link->params) {
Liam Girdwood01d75842012-04-25 12:12:49 +01003098 if (playback)
3099 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
3100 if (capture)
3101 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
3102 goto out;
3103 }
3104
3105 /* ASoC PCM operations */
3106 if (rtd->dai_link->dynamic) {
3107 rtd->ops.open = dpcm_fe_dai_open;
3108 rtd->ops.hw_params = dpcm_fe_dai_hw_params;
3109 rtd->ops.prepare = dpcm_fe_dai_prepare;
3110 rtd->ops.trigger = dpcm_fe_dai_trigger;
3111 rtd->ops.hw_free = dpcm_fe_dai_hw_free;
3112 rtd->ops.close = dpcm_fe_dai_close;
3113 rtd->ops.pointer = soc_pcm_pointer;
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01003114 rtd->ops.ioctl = soc_pcm_ioctl;
Liam Girdwood01d75842012-04-25 12:12:49 +01003115 } else {
3116 rtd->ops.open = soc_pcm_open;
3117 rtd->ops.hw_params = soc_pcm_hw_params;
3118 rtd->ops.prepare = soc_pcm_prepare;
3119 rtd->ops.trigger = soc_pcm_trigger;
3120 rtd->ops.hw_free = soc_pcm_hw_free;
3121 rtd->ops.close = soc_pcm_close;
3122 rtd->ops.pointer = soc_pcm_pointer;
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01003123 rtd->ops.ioctl = soc_pcm_ioctl;
Liam Girdwood01d75842012-04-25 12:12:49 +01003124 }
3125
Kuninori Morimotob8135862017-10-11 01:37:23 +00003126 for_each_rtdcom(rtd, rtdcom) {
3127 const struct snd_pcm_ops *ops = rtdcom->component->driver->ops;
3128
3129 if (!ops)
3130 continue;
3131
3132 if (ops->ack)
3133 rtd->ops.ack = soc_rtdcom_ack;
3134 if (ops->copy_user)
3135 rtd->ops.copy_user = soc_rtdcom_copy_user;
3136 if (ops->copy_kernel)
3137 rtd->ops.copy_kernel = soc_rtdcom_copy_kernel;
3138 if (ops->fill_silence)
3139 rtd->ops.fill_silence = soc_rtdcom_fill_silence;
3140 if (ops->page)
3141 rtd->ops.page = soc_rtdcom_page;
3142 if (ops->mmap)
3143 rtd->ops.mmap = soc_rtdcom_mmap;
3144 }
3145
Liam Girdwoodddee6272011-06-09 14:45:53 +01003146 if (playback)
Liam Girdwood01d75842012-04-25 12:12:49 +01003147 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003148
3149 if (capture)
Liam Girdwood01d75842012-04-25 12:12:49 +01003150 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003151
Kuninori Morimotof523ace2017-09-26 01:00:53 +00003152 for_each_rtdcom(rtd, rtdcom) {
3153 component = rtdcom->component;
3154
Kuninori Morimoto11fb14f2018-05-08 03:19:49 +00003155 if (!component->driver->pcm_new)
Kuninori Morimotof523ace2017-09-26 01:00:53 +00003156 continue;
3157
Kuninori Morimoto11fb14f2018-05-08 03:19:49 +00003158 ret = component->driver->pcm_new(rtd);
Johan Hovoldc641e5b2017-07-12 17:55:29 +02003159 if (ret < 0) {
Kuninori Morimotof523ace2017-09-26 01:00:53 +00003160 dev_err(component->dev,
Johan Hovoldc641e5b2017-07-12 17:55:29 +02003161 "ASoC: pcm constructor failed: %d\n",
3162 ret);
3163 return ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +01003164 }
3165 }
Johan Hovoldc641e5b2017-07-12 17:55:29 +02003166
Takashi Iwai5d61f0b2017-08-25 12:04:07 +02003167 pcm->private_free = soc_pcm_private_free;
Takashi Iwai3d21ef02019-01-11 15:58:39 +01003168 pcm->no_device_suspend = true;
Liam Girdwood01d75842012-04-25 12:12:49 +01003169out:
Benoit Cousson2e5894d2014-07-08 23:19:35 +02003170 dev_info(rtd->card->dev, "%s <-> %s mapping ok\n",
3171 (rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name,
3172 cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003173 return ret;
3174}
Liam Girdwood01d75842012-04-25 12:12:49 +01003175
3176/* is the current PCM operation for this FE ? */
3177int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream)
3178{
3179 if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE)
3180 return 1;
3181 return 0;
3182}
3183EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update);
3184
3185/* is the current PCM operation for this BE ? */
3186int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
3187 struct snd_soc_pcm_runtime *be, int stream)
3188{
3189 if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) ||
3190 ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) &&
3191 be->dpcm[stream].runtime_update))
3192 return 1;
3193 return 0;
3194}
3195EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update);
3196
3197/* get the substream for this BE */
3198struct snd_pcm_substream *
3199 snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream)
3200{
3201 return be->pcm->streams[stream].substream;
3202}
3203EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream);
3204
3205/* get the BE runtime state */
3206enum snd_soc_dpcm_state
3207 snd_soc_dpcm_be_get_state(struct snd_soc_pcm_runtime *be, int stream)
3208{
3209 return be->dpcm[stream].state;
3210}
3211EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_get_state);
3212
3213/* set the BE runtime state */
3214void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be,
3215 int stream, enum snd_soc_dpcm_state state)
3216{
3217 be->dpcm[stream].state = state;
3218}
3219EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_set_state);
3220
3221/*
3222 * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE
3223 * are not running, paused or suspended for the specified stream direction.
3224 */
3225int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
3226 struct snd_soc_pcm_runtime *be, int stream)
3227{
3228 struct snd_soc_dpcm *dpcm;
3229 int state;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003230 int ret = 1;
3231 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01003232
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003233 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00003234 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01003235
3236 if (dpcm->fe == fe)
3237 continue;
3238
3239 state = dpcm->fe->dpcm[stream].state;
3240 if (state == SND_SOC_DPCM_STATE_START ||
3241 state == SND_SOC_DPCM_STATE_PAUSED ||
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003242 state == SND_SOC_DPCM_STATE_SUSPEND) {
3243 ret = 0;
3244 break;
3245 }
Liam Girdwood01d75842012-04-25 12:12:49 +01003246 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003247 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01003248
3249 /* it's safe to free/stop this BE DAI */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003250 return ret;
Liam Girdwood01d75842012-04-25 12:12:49 +01003251}
3252EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop);
3253
3254/*
3255 * We can only change hw params a BE DAI if any of it's FE are not prepared,
3256 * running, paused or suspended for the specified stream direction.
3257 */
3258int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
3259 struct snd_soc_pcm_runtime *be, int stream)
3260{
3261 struct snd_soc_dpcm *dpcm;
3262 int state;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003263 int ret = 1;
3264 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01003265
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003266 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00003267 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01003268
3269 if (dpcm->fe == fe)
3270 continue;
3271
3272 state = dpcm->fe->dpcm[stream].state;
3273 if (state == SND_SOC_DPCM_STATE_START ||
3274 state == SND_SOC_DPCM_STATE_PAUSED ||
3275 state == SND_SOC_DPCM_STATE_SUSPEND ||
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003276 state == SND_SOC_DPCM_STATE_PREPARE) {
3277 ret = 0;
3278 break;
3279 }
Liam Girdwood01d75842012-04-25 12:12:49 +01003280 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003281 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01003282
3283 /* it's safe to change hw_params */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003284 return ret;
Liam Girdwood01d75842012-04-25 12:12:49 +01003285}
3286EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003287
3288#ifdef CONFIG_DEBUG_FS
Lars-Peter Clausen852801412016-11-22 11:29:14 +01003289static const char *dpcm_state_string(enum snd_soc_dpcm_state state)
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003290{
3291 switch (state) {
3292 case SND_SOC_DPCM_STATE_NEW:
3293 return "new";
3294 case SND_SOC_DPCM_STATE_OPEN:
3295 return "open";
3296 case SND_SOC_DPCM_STATE_HW_PARAMS:
3297 return "hw_params";
3298 case SND_SOC_DPCM_STATE_PREPARE:
3299 return "prepare";
3300 case SND_SOC_DPCM_STATE_START:
3301 return "start";
3302 case SND_SOC_DPCM_STATE_STOP:
3303 return "stop";
3304 case SND_SOC_DPCM_STATE_SUSPEND:
3305 return "suspend";
3306 case SND_SOC_DPCM_STATE_PAUSED:
3307 return "paused";
3308 case SND_SOC_DPCM_STATE_HW_FREE:
3309 return "hw_free";
3310 case SND_SOC_DPCM_STATE_CLOSE:
3311 return "close";
3312 }
3313
3314 return "unknown";
3315}
3316
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003317static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
3318 int stream, char *buf, size_t size)
3319{
3320 struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params;
3321 struct snd_soc_dpcm *dpcm;
3322 ssize_t offset = 0;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003323 unsigned long flags;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003324
3325 /* FE state */
3326 offset += snprintf(buf + offset, size - offset,
3327 "[%s - %s]\n", fe->dai_link->name,
3328 stream ? "Capture" : "Playback");
3329
3330 offset += snprintf(buf + offset, size - offset, "State: %s\n",
3331 dpcm_state_string(fe->dpcm[stream].state));
3332
3333 if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
3334 (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
3335 offset += snprintf(buf + offset, size - offset,
3336 "Hardware Params: "
3337 "Format = %s, Channels = %d, Rate = %d\n",
3338 snd_pcm_format_name(params_format(params)),
3339 params_channels(params),
3340 params_rate(params));
3341
3342 /* BEs state */
3343 offset += snprintf(buf + offset, size - offset, "Backends:\n");
3344
3345 if (list_empty(&fe->dpcm[stream].be_clients)) {
3346 offset += snprintf(buf + offset, size - offset,
3347 " No active DSP links\n");
3348 goto out;
3349 }
3350
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003351 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00003352 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003353 struct snd_soc_pcm_runtime *be = dpcm->be;
3354 params = &dpcm->hw_params;
3355
3356 offset += snprintf(buf + offset, size - offset,
3357 "- %s\n", be->dai_link->name);
3358
3359 offset += snprintf(buf + offset, size - offset,
3360 " State: %s\n",
3361 dpcm_state_string(be->dpcm[stream].state));
3362
3363 if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
3364 (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
3365 offset += snprintf(buf + offset, size - offset,
3366 " Hardware Params: "
3367 "Format = %s, Channels = %d, Rate = %d\n",
3368 snd_pcm_format_name(params_format(params)),
3369 params_channels(params),
3370 params_rate(params));
3371 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003372 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003373out:
3374 return offset;
3375}
3376
3377static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf,
3378 size_t count, loff_t *ppos)
3379{
3380 struct snd_soc_pcm_runtime *fe = file->private_data;
3381 ssize_t out_count = PAGE_SIZE, offset = 0, ret = 0;
3382 char *buf;
3383
3384 buf = kmalloc(out_count, GFP_KERNEL);
3385 if (!buf)
3386 return -ENOMEM;
3387
Kuninori Morimoto467fece2019-07-22 10:36:16 +09003388 if (snd_soc_dai_stream_valid(fe->cpu_dai, SNDRV_PCM_STREAM_PLAYBACK))
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003389 offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_PLAYBACK,
3390 buf + offset, out_count - offset);
3391
Kuninori Morimoto467fece2019-07-22 10:36:16 +09003392 if (snd_soc_dai_stream_valid(fe->cpu_dai, SNDRV_PCM_STREAM_CAPTURE))
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003393 offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_CAPTURE,
3394 buf + offset, out_count - offset);
3395
Liam Girdwoodf57b8482012-04-27 11:33:46 +01003396 ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003397
Liam Girdwoodf57b8482012-04-27 11:33:46 +01003398 kfree(buf);
3399 return ret;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003400}
3401
3402static const struct file_operations dpcm_state_fops = {
Liam Girdwoodf57b8482012-04-27 11:33:46 +01003403 .open = simple_open,
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003404 .read = dpcm_state_read_file,
3405 .llseek = default_llseek,
3406};
3407
Lars-Peter Clausen2e55b902015-04-09 10:52:37 +02003408void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003409{
Mark Brownb3bba9a2012-05-08 10:33:47 +01003410 if (!rtd->dai_link)
Lars-Peter Clausen2e55b902015-04-09 10:52:37 +02003411 return;
Mark Brownb3bba9a2012-05-08 10:33:47 +01003412
Lars-Peter Clausen6553bf062015-04-09 10:52:38 +02003413 if (!rtd->card->debugfs_card_root)
3414 return;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003415
3416 rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name,
3417 rtd->card->debugfs_card_root);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003418
Fabio Estevamf1e3f402017-07-29 11:40:55 -03003419 debugfs_create_file("state", 0444, rtd->debugfs_dpcm_root,
3420 rtd, &dpcm_state_fops);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003421}
3422#endif