blob: c0018293c67b29607902623434ce7023341f864d [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>
Liam Girdwoodddee6272011-06-09 14:45:53 +010018#include <linux/slab.h>
19#include <linux/workqueue.h>
Liam Girdwood01d75842012-04-25 12:12:49 +010020#include <linux/export.h>
Liam Girdwoodf86dcef2012-04-25 12:12:50 +010021#include <linux/debugfs.h>
Liam Girdwoodddee6272011-06-09 14:45:53 +010022#include <sound/core.h>
23#include <sound/pcm.h>
24#include <sound/pcm_params.h>
25#include <sound/soc.h>
Liam Girdwood01d75842012-04-25 12:12:49 +010026#include <sound/soc-dpcm.h>
Liam Girdwoodddee6272011-06-09 14:45:53 +010027#include <sound/initval.h>
28
Liam Girdwood01d75842012-04-25 12:12:49 +010029#define DPCM_MAX_BE_USERS 8
30
Kuninori Morimotof183f922020-01-22 09:44:35 +090031static int soc_rtd_startup(struct snd_soc_pcm_runtime *rtd,
32 struct snd_pcm_substream *substream)
33{
34 if (rtd->dai_link->ops &&
35 rtd->dai_link->ops->startup)
36 return rtd->dai_link->ops->startup(substream);
37 return 0;
38}
39
Lars-Peter Clausen90996f42013-05-14 11:05:30 +020040/**
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010041 * snd_soc_runtime_activate() - Increment active count for PCM runtime components
42 * @rtd: ASoC PCM runtime that is activated
43 * @stream: Direction of the PCM stream
44 *
45 * Increments the active count for all the DAIs and components attached to a PCM
46 * runtime. Should typically be called when a stream is opened.
47 *
Peter Ujfalusi72b745e2019-08-13 13:45:32 +030048 * Must be called with the rtd->card->pcm_mutex being held
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010049 */
50void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream)
51{
52 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +000053 struct snd_soc_dai *codec_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +020054 int i;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010055
Peter Ujfalusi72b745e2019-08-13 13:45:32 +030056 lockdep_assert_held(&rtd->card->pcm_mutex);
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010057
58 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
59 cpu_dai->playback_active++;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +000060 for_each_rtd_codec_dai(rtd, i, codec_dai)
61 codec_dai->playback_active++;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010062 } else {
63 cpu_dai->capture_active++;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +000064 for_each_rtd_codec_dai(rtd, i, codec_dai)
65 codec_dai->capture_active++;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010066 }
67
68 cpu_dai->active++;
Lars-Peter Clausencdde4cc2014-03-05 13:17:47 +010069 cpu_dai->component->active++;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +000070 for_each_rtd_codec_dai(rtd, i, codec_dai) {
71 codec_dai->active++;
72 codec_dai->component->active++;
Benoit Cousson2e5894d2014-07-08 23:19:35 +020073 }
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010074}
75
76/**
77 * snd_soc_runtime_deactivate() - Decrement active count for PCM runtime components
78 * @rtd: ASoC PCM runtime that is deactivated
79 * @stream: Direction of the PCM stream
80 *
81 * Decrements the active count for all the DAIs and components attached to a PCM
82 * runtime. Should typically be called when a stream is closed.
83 *
Peter Ujfalusi72b745e2019-08-13 13:45:32 +030084 * Must be called with the rtd->card->pcm_mutex being held
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010085 */
86void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream)
87{
88 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +000089 struct snd_soc_dai *codec_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +020090 int i;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010091
Peter Ujfalusi72b745e2019-08-13 13:45:32 +030092 lockdep_assert_held(&rtd->card->pcm_mutex);
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010093
94 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
95 cpu_dai->playback_active--;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +000096 for_each_rtd_codec_dai(rtd, i, codec_dai)
97 codec_dai->playback_active--;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010098 } else {
99 cpu_dai->capture_active--;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000100 for_each_rtd_codec_dai(rtd, i, codec_dai)
101 codec_dai->capture_active--;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100102 }
103
104 cpu_dai->active--;
Lars-Peter Clausencdde4cc2014-03-05 13:17:47 +0100105 cpu_dai->component->active--;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000106 for_each_rtd_codec_dai(rtd, i, codec_dai) {
107 codec_dai->component->active--;
108 codec_dai->active--;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200109 }
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100110}
111
112/**
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100113 * snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay
114 * @rtd: The ASoC PCM runtime that should be checked.
115 *
116 * This function checks whether the power down delay should be ignored for a
117 * specific PCM runtime. Returns true if the delay is 0, if it the DAI link has
118 * been configured to ignore the delay, or if none of the components benefits
119 * from having the delay.
120 */
121bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
122{
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000123 struct snd_soc_component *component;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200124 bool ignore = true;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900125 int i;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200126
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100127 if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
128 return true;
129
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900130 for_each_rtd_components(rtd, i, component)
Kuninori Morimoto72c38182018-01-19 05:21:19 +0000131 ignore &= !component->driver->use_pmdown_time;
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000132
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000133 return ignore;
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100134}
135
136/**
Lars-Peter Clausen90996f42013-05-14 11:05:30 +0200137 * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
138 * @substream: the pcm substream
139 * @hw: the hardware parameters
140 *
141 * Sets the substream runtime hardware parameters.
142 */
143int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
144 const struct snd_pcm_hardware *hw)
145{
146 struct snd_pcm_runtime *runtime = substream->runtime;
147 runtime->hw.info = hw->info;
148 runtime->hw.formats = hw->formats;
149 runtime->hw.period_bytes_min = hw->period_bytes_min;
150 runtime->hw.period_bytes_max = hw->period_bytes_max;
151 runtime->hw.periods_min = hw->periods_min;
152 runtime->hw.periods_max = hw->periods_max;
153 runtime->hw.buffer_bytes_max = hw->buffer_bytes_max;
154 runtime->hw.fifo_size = hw->fifo_size;
155 return 0;
156}
157EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
158
Liam Girdwood01d75842012-04-25 12:12:49 +0100159/* DPCM stream event, send event to FE and all active BEs. */
Liam Girdwood23607022014-01-17 17:03:55 +0000160int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
Liam Girdwood01d75842012-04-25 12:12:49 +0100161 int event)
162{
163 struct snd_soc_dpcm *dpcm;
164
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +0000165 for_each_dpcm_be(fe, dir, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +0100166
167 struct snd_soc_pcm_runtime *be = dpcm->be;
168
Liam Girdwood103d84a2012-11-19 14:39:15 +0000169 dev_dbg(be->dev, "ASoC: BE %s event %d dir %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +0100170 be->dai_link->name, event, dir);
171
Banajit Goswamib1cd2e32017-07-14 23:15:05 -0700172 if ((event == SND_SOC_DAPM_STREAM_STOP) &&
173 (be->dpcm[dir].users >= 1))
174 continue;
175
Liam Girdwood01d75842012-04-25 12:12:49 +0100176 snd_soc_dapm_stream_event(be, dir, event);
177 }
178
179 snd_soc_dapm_stream_event(fe, dir, event);
180
181 return 0;
182}
183
Dong Aisheng17841022011-08-29 17:15:14 +0800184static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
185 struct snd_soc_dai *soc_dai)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100186{
187 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100188 int ret;
189
Nicolin Chen3635bf02013-11-13 18:56:24 +0800190 if (soc_dai->rate && (soc_dai->driver->symmetric_rates ||
191 rtd->dai_link->symmetric_rates)) {
192 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n",
193 soc_dai->rate);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100194
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200195 ret = snd_pcm_hw_constraint_single(substream->runtime,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800196 SNDRV_PCM_HW_PARAM_RATE,
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200197 soc_dai->rate);
Nicolin Chen3635bf02013-11-13 18:56:24 +0800198 if (ret < 0) {
199 dev_err(soc_dai->dev,
200 "ASoC: Unable to apply rate constraint: %d\n",
201 ret);
202 return ret;
203 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100204 }
205
Nicolin Chen3635bf02013-11-13 18:56:24 +0800206 if (soc_dai->channels && (soc_dai->driver->symmetric_channels ||
207 rtd->dai_link->symmetric_channels)) {
208 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d channel(s)\n",
209 soc_dai->channels);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100210
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200211 ret = snd_pcm_hw_constraint_single(substream->runtime,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800212 SNDRV_PCM_HW_PARAM_CHANNELS,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800213 soc_dai->channels);
214 if (ret < 0) {
215 dev_err(soc_dai->dev,
216 "ASoC: Unable to apply channel symmetry constraint: %d\n",
217 ret);
218 return ret;
219 }
220 }
221
222 if (soc_dai->sample_bits && (soc_dai->driver->symmetric_samplebits ||
223 rtd->dai_link->symmetric_samplebits)) {
224 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d sample bits\n",
225 soc_dai->sample_bits);
226
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200227 ret = snd_pcm_hw_constraint_single(substream->runtime,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800228 SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800229 soc_dai->sample_bits);
230 if (ret < 0) {
231 dev_err(soc_dai->dev,
232 "ASoC: Unable to apply sample bits symmetry constraint: %d\n",
233 ret);
234 return ret;
235 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100236 }
237
238 return 0;
239}
240
Nicolin Chen3635bf02013-11-13 18:56:24 +0800241static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
242 struct snd_pcm_hw_params *params)
243{
244 struct snd_soc_pcm_runtime *rtd = substream->private_data;
245 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000246 struct snd_soc_dai *codec_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200247 unsigned int rate, channels, sample_bits, symmetry, i;
Nicolin Chen3635bf02013-11-13 18:56:24 +0800248
249 rate = params_rate(params);
250 channels = params_channels(params);
251 sample_bits = snd_pcm_format_physical_width(params_format(params));
252
253 /* reject unmatched parameters when applying symmetry */
254 symmetry = cpu_dai->driver->symmetric_rates ||
Nicolin Chen3635bf02013-11-13 18:56:24 +0800255 rtd->dai_link->symmetric_rates;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200256
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000257 for_each_rtd_codec_dai(rtd, i, codec_dai)
258 symmetry |= codec_dai->driver->symmetric_rates;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200259
Nicolin Chen3635bf02013-11-13 18:56:24 +0800260 if (symmetry && cpu_dai->rate && cpu_dai->rate != rate) {
261 dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n",
262 cpu_dai->rate, rate);
263 return -EINVAL;
264 }
265
266 symmetry = cpu_dai->driver->symmetric_channels ||
Nicolin Chen3635bf02013-11-13 18:56:24 +0800267 rtd->dai_link->symmetric_channels;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200268
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000269 for_each_rtd_codec_dai(rtd, i, codec_dai)
270 symmetry |= codec_dai->driver->symmetric_channels;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200271
Nicolin Chen3635bf02013-11-13 18:56:24 +0800272 if (symmetry && cpu_dai->channels && cpu_dai->channels != channels) {
273 dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n",
274 cpu_dai->channels, channels);
275 return -EINVAL;
276 }
277
278 symmetry = cpu_dai->driver->symmetric_samplebits ||
Nicolin Chen3635bf02013-11-13 18:56:24 +0800279 rtd->dai_link->symmetric_samplebits;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200280
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000281 for_each_rtd_codec_dai(rtd, i, codec_dai)
282 symmetry |= codec_dai->driver->symmetric_samplebits;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200283
Nicolin Chen3635bf02013-11-13 18:56:24 +0800284 if (symmetry && cpu_dai->sample_bits && cpu_dai->sample_bits != sample_bits) {
285 dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n",
286 cpu_dai->sample_bits, sample_bits);
287 return -EINVAL;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100288 }
289
290 return 0;
291}
292
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100293static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream)
294{
295 struct snd_soc_pcm_runtime *rtd = substream->private_data;
296 struct snd_soc_dai_driver *cpu_driver = rtd->cpu_dai->driver;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100297 struct snd_soc_dai_link *link = rtd->dai_link;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000298 struct snd_soc_dai *codec_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200299 unsigned int symmetry, i;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100300
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200301 symmetry = cpu_driver->symmetric_rates || link->symmetric_rates ||
302 cpu_driver->symmetric_channels || link->symmetric_channels ||
303 cpu_driver->symmetric_samplebits || link->symmetric_samplebits;
304
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000305 for_each_rtd_codec_dai(rtd, i, codec_dai)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200306 symmetry = symmetry ||
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000307 codec_dai->driver->symmetric_rates ||
308 codec_dai->driver->symmetric_channels ||
309 codec_dai->driver->symmetric_samplebits;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200310
311 return symmetry;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100312}
313
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200314static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits)
Mark Brown58ba9b22012-01-16 18:38:51 +0000315{
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200316 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Takashi Iwaic6068d32014-12-31 17:10:34 +0100317 int ret;
Mark Brown58ba9b22012-01-16 18:38:51 +0000318
319 if (!bits)
320 return;
321
Lars-Peter Clausen0e2a3752014-12-29 18:43:38 +0100322 ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 0, bits);
323 if (ret != 0)
324 dev_warn(rtd->dev, "ASoC: Failed to set MSB %d: %d\n",
325 bits, ret);
Mark Brown58ba9b22012-01-16 18:38:51 +0000326}
327
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200328static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200329{
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200330 struct snd_soc_pcm_runtime *rtd = substream->private_data;
331 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200332 struct snd_soc_dai *codec_dai;
333 int i;
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200334 unsigned int bits = 0, cpu_bits;
335
336 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000337 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200338 if (codec_dai->driver->playback.sig_bits == 0) {
339 bits = 0;
340 break;
341 }
342 bits = max(codec_dai->driver->playback.sig_bits, bits);
343 }
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200344 cpu_bits = cpu_dai->driver->playback.sig_bits;
345 } else {
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000346 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Daniel Mack5e63dfc2014-10-07 14:33:46 +0200347 if (codec_dai->driver->capture.sig_bits == 0) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200348 bits = 0;
349 break;
350 }
351 bits = max(codec_dai->driver->capture.sig_bits, bits);
352 }
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200353 cpu_bits = cpu_dai->driver->capture.sig_bits;
354 }
355
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200356 soc_pcm_set_msb(substream, bits);
357 soc_pcm_set_msb(substream, cpu_bits);
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200358}
359
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200360static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200361{
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200362 struct snd_pcm_runtime *runtime = substream->runtime;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100363 struct snd_pcm_hardware *hw = &runtime->hw;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200364 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000365 struct snd_soc_dai *codec_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200366 struct snd_soc_dai_driver *cpu_dai_drv = rtd->cpu_dai->driver;
367 struct snd_soc_dai_driver *codec_dai_drv;
368 struct snd_soc_pcm_stream *codec_stream;
369 struct snd_soc_pcm_stream *cpu_stream;
370 unsigned int chan_min = 0, chan_max = UINT_MAX;
371 unsigned int rate_min = 0, rate_max = UINT_MAX;
372 unsigned int rates = UINT_MAX;
373 u64 formats = ULLONG_MAX;
374 int i;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100375
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200376 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
377 cpu_stream = &cpu_dai_drv->playback;
Lars-Peter Clausen16d7ea92014-01-06 14:19:16 +0100378 else
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200379 cpu_stream = &cpu_dai_drv->capture;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100380
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200381 /* first calculate min/max only for CODECs in the DAI link */
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000382 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200383
384 /*
385 * Skip CODECs which don't support the current stream type.
386 * Otherwise, since the rate, channel, and format values will
387 * zero in that case, we would have no usable settings left,
388 * causing the resulting setup to fail.
389 * At least one CODEC should match, otherwise we should have
390 * bailed out on a higher level, since there would be no
391 * CODEC to support the transfer direction in that case.
392 */
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000393 if (!snd_soc_dai_stream_valid(codec_dai,
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200394 substream->stream))
395 continue;
396
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000397 codec_dai_drv = codec_dai->driver;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200398 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
399 codec_stream = &codec_dai_drv->playback;
400 else
401 codec_stream = &codec_dai_drv->capture;
402 chan_min = max(chan_min, codec_stream->channels_min);
403 chan_max = min(chan_max, codec_stream->channels_max);
404 rate_min = max(rate_min, codec_stream->rate_min);
405 rate_max = min_not_zero(rate_max, codec_stream->rate_max);
406 formats &= codec_stream->formats;
407 rates = snd_pcm_rate_mask_intersect(codec_stream->rates, rates);
408 }
409
410 /*
411 * chan min/max cannot be enforced if there are multiple CODEC DAIs
412 * connected to a single CPU DAI, use CPU DAI's directly and let
413 * channel allocation be fixed up later
414 */
415 if (rtd->num_codecs > 1) {
416 chan_min = cpu_stream->channels_min;
417 chan_max = cpu_stream->channels_max;
418 }
419
420 hw->channels_min = max(chan_min, cpu_stream->channels_min);
421 hw->channels_max = min(chan_max, cpu_stream->channels_max);
422 if (hw->formats)
423 hw->formats &= formats & cpu_stream->formats;
424 else
425 hw->formats = formats & cpu_stream->formats;
426 hw->rates = snd_pcm_rate_mask_intersect(rates, cpu_stream->rates);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100427
428 snd_pcm_limit_hw_rates(runtime);
429
430 hw->rate_min = max(hw->rate_min, cpu_stream->rate_min);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200431 hw->rate_min = max(hw->rate_min, rate_min);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100432 hw->rate_max = min_not_zero(hw->rate_max, cpu_stream->rate_max);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200433 hw->rate_max = min_not_zero(hw->rate_max, rate_max);
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200434}
435
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900436static int soc_pcm_components_open(struct snd_pcm_substream *substream,
437 struct snd_soc_component **last)
438{
439 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900440 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900441 int i, ret = 0;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900442
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900443 for_each_rtd_components(rtd, i, component) {
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900444 *last = component;
445
Kuninori Morimoto4a81e8f2019-07-26 13:49:54 +0900446 ret = snd_soc_component_module_get_when_open(component);
447 if (ret < 0) {
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900448 dev_err(component->dev,
449 "ASoC: can't get module %s\n",
450 component->name);
Kuninori Morimoto4a81e8f2019-07-26 13:49:54 +0900451 return ret;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900452 }
453
Kuninori Morimotoae2f4842019-07-26 13:50:01 +0900454 ret = snd_soc_component_open(component, substream);
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900455 if (ret < 0) {
456 dev_err(component->dev,
457 "ASoC: can't open component %s: %d\n",
458 component->name, ret);
459 return ret;
460 }
461 }
462 *last = NULL;
463 return 0;
464}
465
Charles Keepax244e2932018-06-19 16:22:09 +0100466static int soc_pcm_components_close(struct snd_pcm_substream *substream,
467 struct snd_soc_component *last)
468{
469 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Charles Keepax244e2932018-06-19 16:22:09 +0100470 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900471 int i, ret = 0;
Charles Keepax244e2932018-06-19 16:22:09 +0100472
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900473 for_each_rtd_components(rtd, i, component) {
Charles Keepax244e2932018-06-19 16:22:09 +0100474 if (component == last)
475 break;
476
Kuninori Morimoto3672beb2019-07-26 13:50:07 +0900477 ret |= snd_soc_component_close(component, substream);
Kuninori Morimoto4a81e8f2019-07-26 13:49:54 +0900478 snd_soc_component_module_put_when_close(component);
Charles Keepax244e2932018-06-19 16:22:09 +0100479 }
480
Kuninori Morimoto3672beb2019-07-26 13:50:07 +0900481 return ret;
Charles Keepax244e2932018-06-19 16:22:09 +0100482}
483
Mark Brown58ba9b22012-01-16 18:38:51 +0000484/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100485 * Called by ALSA when a PCM substream is opened, the runtime->hw record is
486 * then initialized and any private data can be allocated. This also calls
Charles Keepaxef050be2018-04-24 16:39:02 +0100487 * startup for the cpu DAI, component, machine and codec DAI.
Liam Girdwoodddee6272011-06-09 14:45:53 +0100488 */
489static int soc_pcm_open(struct snd_pcm_substream *substream)
490{
491 struct snd_soc_pcm_runtime *rtd = substream->private_data;
492 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000493 struct snd_soc_component *component;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100494 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200495 struct snd_soc_dai *codec_dai;
496 const char *codec_dai_name = "multicodec";
Charles Keepax244e2932018-06-19 16:22:09 +0100497 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100498
Kuninori Morimoto76c39e82020-01-10 11:36:13 +0900499 for_each_rtd_components(rtd, i, component)
500 pinctrl_pm_select_default_state(component->dev);
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000501
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900502 for_each_rtd_components(rtd, i, component)
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000503 pm_runtime_get_sync(component->dev);
Mark Brownd6652ef2011-12-03 20:14:31 +0000504
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300505 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100506
507 /* startup the audio subsystem */
Kuninori Morimoto5a52a042019-07-22 10:33:32 +0900508 ret = snd_soc_dai_startup(cpu_dai, substream);
509 if (ret < 0) {
510 dev_err(cpu_dai->dev, "ASoC: can't open interface %s: %d\n",
511 cpu_dai->name, ret);
512 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100513 }
514
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900515 ret = soc_pcm_components_open(substream, &component);
516 if (ret < 0)
517 goto component_err;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000518
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000519 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto5a52a042019-07-22 10:33:32 +0900520 ret = snd_soc_dai_startup(codec_dai, substream);
521 if (ret < 0) {
522 dev_err(codec_dai->dev,
523 "ASoC: can't open codec %s: %d\n",
524 codec_dai->name, ret);
525 goto codec_dai_err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100526 }
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200527
528 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
529 codec_dai->tx_mask = 0;
530 else
531 codec_dai->rx_mask = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100532 }
533
Kuninori Morimotof183f922020-01-22 09:44:35 +0900534 ret = soc_rtd_startup(rtd, substream);
535 if (ret < 0) {
536 pr_err("ASoC: %s startup failed: %d\n",
537 rtd->dai_link->name, ret);
538 goto machine_err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100539 }
540
Liam Girdwood01d75842012-04-25 12:12:49 +0100541 /* Dynamic PCM DAI links compat checks use dynamic capabilities */
542 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm)
543 goto dynamic;
544
Liam Girdwoodddee6272011-06-09 14:45:53 +0100545 /* Check that the codec and cpu DAIs are compatible */
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200546 soc_pcm_init_runtime_hw(substream);
547
548 if (rtd->num_codecs == 1)
549 codec_dai_name = rtd->codec_dai->name;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100550
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100551 if (soc_pcm_has_symmetry(substream))
552 runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
553
Liam Girdwoodddee6272011-06-09 14:45:53 +0100554 ret = -EINVAL;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100555 if (!runtime->hw.rates) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000556 printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200557 codec_dai_name, cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100558 goto config_err;
559 }
560 if (!runtime->hw.formats) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000561 printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200562 codec_dai_name, cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100563 goto config_err;
564 }
565 if (!runtime->hw.channels_min || !runtime->hw.channels_max ||
566 runtime->hw.channels_min > runtime->hw.channels_max) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000567 printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200568 codec_dai_name, cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100569 goto config_err;
570 }
571
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200572 soc_pcm_apply_msb(substream);
Mark Brown58ba9b22012-01-16 18:38:51 +0000573
Liam Girdwoodddee6272011-06-09 14:45:53 +0100574 /* Symmetry only applies if we've already got an active stream. */
Dong Aisheng17841022011-08-29 17:15:14 +0800575 if (cpu_dai->active) {
576 ret = soc_pcm_apply_symmetry(substream, cpu_dai);
577 if (ret != 0)
578 goto config_err;
579 }
580
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000581 for_each_rtd_codec_dai(rtd, i, codec_dai) {
582 if (codec_dai->active) {
583 ret = soc_pcm_apply_symmetry(substream, codec_dai);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200584 if (ret != 0)
585 goto config_err;
586 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100587 }
588
Liam Girdwood103d84a2012-11-19 14:39:15 +0000589 pr_debug("ASoC: %s <-> %s info:\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200590 codec_dai_name, cpu_dai->name);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000591 pr_debug("ASoC: rate mask 0x%x\n", runtime->hw.rates);
592 pr_debug("ASoC: min ch %d max ch %d\n", runtime->hw.channels_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100593 runtime->hw.channels_max);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000594 pr_debug("ASoC: min rate %d max rate %d\n", runtime->hw.rate_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100595 runtime->hw.rate_max);
596
Liam Girdwood01d75842012-04-25 12:12:49 +0100597dynamic:
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100598
599 snd_soc_runtime_activate(rtd, substream->stream);
600
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300601 mutex_unlock(&rtd->card->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100602 return 0;
603
604config_err:
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000605 if (rtd->dai_link->ops->shutdown)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100606 rtd->dai_link->ops->shutdown(substream);
607
608machine_err:
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200609 i = rtd->num_codecs;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100610
611codec_dai_err:
Kuninori Morimoto330fcb52019-07-22 10:33:39 +0900612 for_each_rtd_codec_dai_rollback(rtd, i, codec_dai)
613 snd_soc_dai_shutdown(codec_dai, substream);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200614
Kuninori Morimotob8135862017-10-11 01:37:23 +0000615component_err:
Charles Keepax244e2932018-06-19 16:22:09 +0100616 soc_pcm_components_close(substream, component);
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900617
Kuninori Morimoto330fcb52019-07-22 10:33:39 +0900618 snd_soc_dai_shutdown(cpu_dai, substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100619out:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300620 mutex_unlock(&rtd->card->pcm_mutex);
Mark Brownd6652ef2011-12-03 20:14:31 +0000621
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900622 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000623 pm_runtime_mark_last_busy(component->dev);
624 pm_runtime_put_autosuspend(component->dev);
Sanyog Kale3f809782016-01-05 17:14:49 +0530625 }
626
Kuninori Morimoto76c39e82020-01-10 11:36:13 +0900627 for_each_rtd_components(rtd, i, component)
628 if (!component->active)
629 pinctrl_pm_select_sleep_state(component->dev);
Mark Brownd6652ef2011-12-03 20:14:31 +0000630
Liam Girdwoodddee6272011-06-09 14:45:53 +0100631 return ret;
632}
633
Curtis Malainey4bf2e382019-12-03 09:30:07 -0800634static void codec2codec_close_delayed_work(struct snd_soc_pcm_runtime *rtd)
Jerome Bruneta3420312019-07-25 18:59:47 +0200635{
636 /*
637 * Currently nothing to do for c2c links
638 * Since c2c links are internal nodes in the DAPM graph and
639 * don't interface with the outside world or application layer
640 * we don't have to do any special handling on close.
641 */
642}
643
Liam Girdwoodddee6272011-06-09 14:45:53 +0100644/*
645 * Called by ALSA when a PCM substream is closed. Private data can be
Charles Keepaxef050be2018-04-24 16:39:02 +0100646 * freed here. The cpu DAI, codec DAI, machine and components are also
Liam Girdwoodddee6272011-06-09 14:45:53 +0100647 * shutdown.
648 */
Liam Girdwood91d5e6b2011-06-09 17:04:59 +0100649static int soc_pcm_close(struct snd_pcm_substream *substream)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100650{
651 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000652 struct snd_soc_component *component;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100653 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200654 struct snd_soc_dai *codec_dai;
655 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100656
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300657 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100658
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100659 snd_soc_runtime_deactivate(rtd, substream->stream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100660
Dong Aisheng17841022011-08-29 17:15:14 +0800661 /* clear the corresponding DAIs rate when inactive */
662 if (!cpu_dai->active)
663 cpu_dai->rate = 0;
664
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000665 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200666 if (!codec_dai->active)
667 codec_dai->rate = 0;
668 }
Sascha Hauer25b76792011-08-17 09:20:01 +0200669
Ramesh Babuae116012014-10-15 12:34:59 +0530670 snd_soc_dai_digital_mute(cpu_dai, 1, substream->stream);
671
Kuninori Morimoto330fcb52019-07-22 10:33:39 +0900672 snd_soc_dai_shutdown(cpu_dai, substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100673
Kuninori Morimoto330fcb52019-07-22 10:33:39 +0900674 for_each_rtd_codec_dai(rtd, i, codec_dai)
675 snd_soc_dai_shutdown(codec_dai, substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100676
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000677 if (rtd->dai_link->ops->shutdown)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100678 rtd->dai_link->ops->shutdown(substream);
679
Charles Keepax244e2932018-06-19 16:22:09 +0100680 soc_pcm_components_close(substream, NULL);
Kuninori Morimotob8135862017-10-11 01:37:23 +0000681
Kuninori Morimoto3f4cf792020-01-10 11:36:23 +0900682 snd_soc_dapm_stream_stop(rtd, substream->stream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100683
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300684 mutex_unlock(&rtd->card->pcm_mutex);
Mark Brownd6652ef2011-12-03 20:14:31 +0000685
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900686 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000687 pm_runtime_mark_last_busy(component->dev);
688 pm_runtime_put_autosuspend(component->dev);
Sanyog Kale3f809782016-01-05 17:14:49 +0530689 }
690
Kuninori Morimoto76c39e82020-01-10 11:36:13 +0900691 for_each_rtd_components(rtd, i, component)
692 if (!component->active)
693 pinctrl_pm_select_sleep_state(component->dev);
Mark Brownd6652ef2011-12-03 20:14:31 +0000694
Liam Girdwoodddee6272011-06-09 14:45:53 +0100695 return 0;
696}
697
698/*
699 * Called by ALSA when the PCM substream is prepared, can set format, sample
700 * rate, etc. This function is non atomic and can be called multiple times,
701 * it can refer to the runtime info.
702 */
703static int soc_pcm_prepare(struct snd_pcm_substream *substream)
704{
705 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000706 struct snd_soc_component *component;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100707 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200708 struct snd_soc_dai *codec_dai;
709 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100710
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300711 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100712
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000713 if (rtd->dai_link->ops->prepare) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100714 ret = rtd->dai_link->ops->prepare(substream);
715 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000716 dev_err(rtd->card->dev, "ASoC: machine prepare error:"
717 " %d\n", ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100718 goto out;
719 }
720 }
721
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900722 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto6d537232019-07-26 13:50:13 +0900723 ret = snd_soc_component_prepare(component, substream);
Kuninori Morimotob8135862017-10-11 01:37:23 +0000724 if (ret < 0) {
725 dev_err(component->dev,
726 "ASoC: platform prepare error: %d\n", ret);
727 goto out;
728 }
729 }
730
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000731 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto4beb8e12019-07-22 10:33:45 +0900732 ret = snd_soc_dai_prepare(codec_dai, substream);
733 if (ret < 0) {
734 dev_err(codec_dai->dev,
735 "ASoC: codec DAI prepare error: %d\n",
736 ret);
737 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100738 }
739 }
740
Kuninori Morimoto4beb8e12019-07-22 10:33:45 +0900741 ret = snd_soc_dai_prepare(cpu_dai, substream);
742 if (ret < 0) {
743 dev_err(cpu_dai->dev,
744 "ASoC: cpu DAI prepare error: %d\n", ret);
745 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100746 }
747
748 /* cancel any delayed stream shutdown that is pending */
749 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600750 rtd->pop_wait) {
751 rtd->pop_wait = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100752 cancel_delayed_work(&rtd->delayed_work);
753 }
754
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000755 snd_soc_dapm_stream_event(rtd, substream->stream,
756 SND_SOC_DAPM_STREAM_START);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100757
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000758 for_each_rtd_codec_dai(rtd, i, codec_dai)
759 snd_soc_dai_digital_mute(codec_dai, 0,
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200760 substream->stream);
Ramesh Babuae116012014-10-15 12:34:59 +0530761 snd_soc_dai_digital_mute(cpu_dai, 0, substream->stream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100762
763out:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300764 mutex_unlock(&rtd->card->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100765 return ret;
766}
767
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200768static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params,
769 unsigned int mask)
770{
771 struct snd_interval *interval;
772 int channels = hweight_long(mask);
773
774 interval = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
775 interval->min = channels;
776 interval->max = channels;
777}
778
Charles Keepax244e2932018-06-19 16:22:09 +0100779static int soc_pcm_components_hw_free(struct snd_pcm_substream *substream,
780 struct snd_soc_component *last)
781{
782 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Charles Keepax244e2932018-06-19 16:22:09 +0100783 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900784 int i, ret = 0;
Charles Keepax244e2932018-06-19 16:22:09 +0100785
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900786 for_each_rtd_components(rtd, i, component) {
Charles Keepax244e2932018-06-19 16:22:09 +0100787 if (component == last)
788 break;
789
Kuninori Morimotoeae71362019-07-26 13:50:24 +0900790 ret |= snd_soc_component_hw_free(component, substream);
Charles Keepax244e2932018-06-19 16:22:09 +0100791 }
792
Kuninori Morimotoeae71362019-07-26 13:50:24 +0900793 return ret;
Charles Keepax244e2932018-06-19 16:22:09 +0100794}
795
Liam Girdwoodddee6272011-06-09 14:45:53 +0100796/*
797 * Called by ALSA when the hardware params are set by application. This
798 * function can also be called multiple times and can allocate buffers
799 * (using snd_pcm_lib_* ). It's non-atomic.
800 */
801static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
802 struct snd_pcm_hw_params *params)
803{
804 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000805 struct snd_soc_component *component;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100806 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000807 struct snd_soc_dai *codec_dai;
Charles Keepax244e2932018-06-19 16:22:09 +0100808 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100809
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300810 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Shengjiu Wang5cca5952019-11-12 18:46:42 +0800811
812 ret = soc_pcm_params_symmetry(substream, params);
813 if (ret)
814 goto out;
815
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000816 if (rtd->dai_link->ops->hw_params) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100817 ret = rtd->dai_link->ops->hw_params(substream, params);
818 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000819 dev_err(rtd->card->dev, "ASoC: machine hw_params"
820 " failed: %d\n", ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100821 goto out;
822 }
823 }
824
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000825 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200826 struct snd_pcm_hw_params codec_params;
827
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200828 /*
829 * Skip CODECs which don't support the current stream type,
830 * the idea being that if a CODEC is not used for the currently
831 * set up transfer direction, it should not need to be
832 * configured, especially since the configuration used might
833 * not even be supported by that CODEC. There may be cases
834 * however where a CODEC needs to be set up although it is
835 * actually not being used for the transfer, e.g. if a
836 * capture-only CODEC is acting as an LRCLK and/or BCLK master
837 * for the DAI link including a playback-only CODEC.
838 * If this becomes necessary, we will have to augment the
839 * machine driver setup with information on how to act, so
840 * we can do the right thing here.
841 */
842 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
843 continue;
844
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200845 /* copy params for each codec */
846 codec_params = *params;
847
848 /* fixup params based on TDM slot masks */
Rander Wang570f18b2019-03-08 16:38:57 +0800849 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
850 codec_dai->tx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200851 soc_pcm_codec_params_fixup(&codec_params,
852 codec_dai->tx_mask);
Rander Wang570f18b2019-03-08 16:38:57 +0800853
854 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
855 codec_dai->rx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200856 soc_pcm_codec_params_fixup(&codec_params,
857 codec_dai->rx_mask);
858
Kuninori Morimotoaa6166c2019-07-22 10:33:04 +0900859 ret = snd_soc_dai_hw_params(codec_dai, substream,
860 &codec_params);
Benoit Cousson93e69582014-07-08 23:19:38 +0200861 if(ret < 0)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100862 goto codec_err;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200863
864 codec_dai->rate = params_rate(&codec_params);
865 codec_dai->channels = params_channels(&codec_params);
866 codec_dai->sample_bits = snd_pcm_format_physical_width(
867 params_format(&codec_params));
Charles Keepax078a85f2019-01-31 13:30:18 +0000868
869 snd_soc_dapm_update_dai(substream, &codec_params, codec_dai);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100870 }
871
Kuninori Morimotoaa6166c2019-07-22 10:33:04 +0900872 ret = snd_soc_dai_hw_params(cpu_dai, substream, params);
Benoit Cousson93e69582014-07-08 23:19:38 +0200873 if (ret < 0)
874 goto interface_err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100875
Kuninori Morimotoca58221d2019-05-13 16:07:43 +0900876 /* store the parameters for each DAIs */
877 cpu_dai->rate = params_rate(params);
878 cpu_dai->channels = params_channels(params);
879 cpu_dai->sample_bits =
880 snd_pcm_format_physical_width(params_format(params));
881
882 snd_soc_dapm_update_dai(substream, params, cpu_dai);
883
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900884 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto245c5392019-07-26 13:50:19 +0900885 ret = snd_soc_component_hw_params(component, substream, params);
Charles Keepax244e2932018-06-19 16:22:09 +0100886 if (ret < 0) {
Kuninori Morimotob8135862017-10-11 01:37:23 +0000887 dev_err(component->dev,
888 "ASoC: %s hw params failed: %d\n",
Charles Keepax244e2932018-06-19 16:22:09 +0100889 component->name, ret);
890 goto component_err;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000891 }
892 }
Charles Keepax244e2932018-06-19 16:22:09 +0100893 component = NULL;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000894
Liam Girdwoodddee6272011-06-09 14:45:53 +0100895out:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300896 mutex_unlock(&rtd->card->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100897 return ret;
898
Kuninori Morimotob8135862017-10-11 01:37:23 +0000899component_err:
Charles Keepax244e2932018-06-19 16:22:09 +0100900 soc_pcm_components_hw_free(substream, component);
Kuninori Morimotob8135862017-10-11 01:37:23 +0000901
Kuninori Morimoto846faae2019-07-22 10:33:19 +0900902 snd_soc_dai_hw_free(cpu_dai, substream);
Kuninori Morimoto2371abd2019-05-13 16:07:52 +0900903 cpu_dai->rate = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100904
905interface_err:
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200906 i = rtd->num_codecs;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100907
908codec_err:
Kuninori Morimoto6d11b122018-09-18 01:28:30 +0000909 for_each_rtd_codec_dai_rollback(rtd, i, codec_dai) {
Jerome Brunetf47b9ad2019-04-29 11:47:50 +0200910 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
911 continue;
912
Kuninori Morimoto846faae2019-07-22 10:33:19 +0900913 snd_soc_dai_hw_free(codec_dai, substream);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200914 codec_dai->rate = 0;
915 }
916
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000917 if (rtd->dai_link->ops->hw_free)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100918 rtd->dai_link->ops->hw_free(substream);
919
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300920 mutex_unlock(&rtd->card->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100921 return ret;
922}
923
924/*
925 * Frees resources allocated by hw_params, can be called multiple times
926 */
927static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
928{
929 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100930 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200931 struct snd_soc_dai *codec_dai;
Nicolin Chen7f62b6e2013-12-04 11:18:36 +0800932 bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200933 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100934
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300935 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100936
Nicolin Chend3383422013-11-20 18:37:09 +0800937 /* clear the corresponding DAIs parameters when going to be inactive */
938 if (cpu_dai->active == 1) {
939 cpu_dai->rate = 0;
940 cpu_dai->channels = 0;
941 cpu_dai->sample_bits = 0;
942 }
943
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000944 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200945 if (codec_dai->active == 1) {
946 codec_dai->rate = 0;
947 codec_dai->channels = 0;
948 codec_dai->sample_bits = 0;
949 }
Nicolin Chend3383422013-11-20 18:37:09 +0800950 }
951
Liam Girdwoodddee6272011-06-09 14:45:53 +0100952 /* apply codec digital mute */
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000953 for_each_rtd_codec_dai(rtd, i, codec_dai) {
954 if ((playback && codec_dai->playback_active == 1) ||
955 (!playback && codec_dai->capture_active == 1))
956 snd_soc_dai_digital_mute(codec_dai, 1,
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200957 substream->stream);
958 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100959
960 /* free any machine hw params */
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000961 if (rtd->dai_link->ops->hw_free)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100962 rtd->dai_link->ops->hw_free(substream);
963
Kuninori Morimotob8135862017-10-11 01:37:23 +0000964 /* free any component resources */
Charles Keepax244e2932018-06-19 16:22:09 +0100965 soc_pcm_components_hw_free(substream, NULL);
Kuninori Morimotob8135862017-10-11 01:37:23 +0000966
Liam Girdwoodddee6272011-06-09 14:45:53 +0100967 /* now free hw params for the DAIs */
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000968 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Jerome Brunetf47b9ad2019-04-29 11:47:50 +0200969 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
970 continue;
971
Kuninori Morimoto846faae2019-07-22 10:33:19 +0900972 snd_soc_dai_hw_free(codec_dai, substream);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200973 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100974
Kuninori Morimoto846faae2019-07-22 10:33:19 +0900975 snd_soc_dai_hw_free(cpu_dai, substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100976
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300977 mutex_unlock(&rtd->card->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100978 return 0;
979}
980
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +0300981static int soc_pcm_trigger_start(struct snd_pcm_substream *substream, int cmd)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100982{
983 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000984 struct snd_soc_component *component;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100985 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200986 struct snd_soc_dai *codec_dai;
987 int i, ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100988
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +0300989 if (rtd->dai_link->ops->trigger) {
990 ret = rtd->dai_link->ops->trigger(substream, cmd);
Kuninori Morimoto95aef352019-07-22 10:33:51 +0900991 if (ret < 0)
992 return ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100993 }
994
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900995 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto5693d502019-07-26 13:50:29 +0900996 ret = snd_soc_component_trigger(component, substream, cmd);
Kuninori Morimotob8135862017-10-11 01:37:23 +0000997 if (ret < 0)
998 return ret;
999 }
1000
Dan Carpenter901e8222019-09-23 17:22:57 +03001001 ret = snd_soc_dai_trigger(cpu_dai, substream, cmd);
Kuninori Morimoto95aef352019-07-22 10:33:51 +09001002 if (ret < 0)
1003 return ret;
Jarkko Nikula4792b0d2014-04-28 14:17:52 +02001004
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001005 for_each_rtd_codec_dai(rtd, i, codec_dai) {
1006 ret = snd_soc_dai_trigger(codec_dai, substream, cmd);
1007 if (ret < 0)
1008 return ret;
1009 }
1010
1011 return 0;
1012}
1013
1014static int soc_pcm_trigger_stop(struct snd_pcm_substream *substream, int cmd)
1015{
1016 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1017 struct snd_soc_component *component;
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001018 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
1019 struct snd_soc_dai *codec_dai;
1020 int i, ret;
1021
1022 for_each_rtd_codec_dai(rtd, i, codec_dai) {
1023 ret = snd_soc_dai_trigger(codec_dai, substream, cmd);
1024 if (ret < 0)
1025 return ret;
1026 }
1027
1028 ret = snd_soc_dai_trigger(cpu_dai, substream, cmd);
1029 if (ret < 0)
1030 return ret;
1031
Kuninori Morimoto613fb502020-01-10 11:35:21 +09001032 for_each_rtd_components(rtd, i, component) {
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001033 ret = snd_soc_component_trigger(component, substream, cmd);
1034 if (ret < 0)
1035 return ret;
1036 }
1037
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +00001038 if (rtd->dai_link->ops->trigger) {
Jarkko Nikula4792b0d2014-04-28 14:17:52 +02001039 ret = rtd->dai_link->ops->trigger(substream, cmd);
1040 if (ret < 0)
1041 return ret;
1042 }
1043
Liam Girdwoodddee6272011-06-09 14:45:53 +01001044 return 0;
1045}
1046
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001047static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1048{
1049 int ret;
1050
1051 switch (cmd) {
1052 case SNDRV_PCM_TRIGGER_START:
1053 case SNDRV_PCM_TRIGGER_RESUME:
1054 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1055 ret = soc_pcm_trigger_start(substream, cmd);
1056 break;
1057 case SNDRV_PCM_TRIGGER_STOP:
1058 case SNDRV_PCM_TRIGGER_SUSPEND:
1059 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
1060 ret = soc_pcm_trigger_stop(substream, cmd);
1061 break;
1062 default:
1063 return -EINVAL;
1064 }
1065
1066 return ret;
1067}
1068
Mark Brown45c0a182012-05-09 21:46:27 +01001069static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
1070 int cmd)
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001071{
1072 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001073 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001074 struct snd_soc_dai *codec_dai;
1075 int i, ret;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001076
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001077 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto5c0769af2019-07-22 10:33:56 +09001078 ret = snd_soc_dai_bespoke_trigger(codec_dai, substream, cmd);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001079 if (ret < 0)
1080 return ret;
1081 }
Kuninori Morimoto5c0769af2019-07-22 10:33:56 +09001082
Dan Carpenter901e8222019-09-23 17:22:57 +03001083 ret = snd_soc_dai_bespoke_trigger(cpu_dai, substream, cmd);
Kuninori Morimoto5c0769af2019-07-22 10:33:56 +09001084 if (ret < 0)
1085 return ret;
1086
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001087 return 0;
1088}
Liam Girdwoodddee6272011-06-09 14:45:53 +01001089/*
1090 * soc level wrapper for pointer callback
Charles Keepaxef050be2018-04-24 16:39:02 +01001091 * If cpu_dai, codec_dai, component driver has the delay callback, then
Liam Girdwoodddee6272011-06-09 14:45:53 +01001092 * the runtime->delay will be updated accordingly.
1093 */
1094static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
1095{
1096 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001097 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001098 struct snd_soc_dai *codec_dai;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001099 struct snd_pcm_runtime *runtime = substream->runtime;
1100 snd_pcm_uframes_t offset = 0;
1101 snd_pcm_sframes_t delay = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001102 snd_pcm_sframes_t codec_delay = 0;
1103 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001104
Akshu Agrawal9fb4c2bf2018-08-01 15:37:33 +05301105 /* clearing the previous total delay */
1106 runtime->delay = 0;
1107
Kuninori Morimoto0035e252019-07-26 13:51:47 +09001108 offset = snd_soc_pcm_component_pointer(substream);
Kuninori Morimotob8135862017-10-11 01:37:23 +00001109
Akshu Agrawal9fb4c2bf2018-08-01 15:37:33 +05301110 /* base delay if assigned in pointer callback */
1111 delay = runtime->delay;
Kuninori Morimotob8135862017-10-11 01:37:23 +00001112
Kuninori Morimoto1dea80d2019-07-22 10:34:09 +09001113 delay += snd_soc_dai_delay(cpu_dai, substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001114
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001115 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto1dea80d2019-07-22 10:34:09 +09001116 codec_delay = max(codec_delay,
1117 snd_soc_dai_delay(codec_dai, substream));
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001118 }
1119 delay += codec_delay;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001120
Liam Girdwoodddee6272011-06-09 14:45:53 +01001121 runtime->delay = delay;
1122
1123 return offset;
1124}
1125
Liam Girdwood01d75842012-04-25 12:12:49 +01001126/* connect a FE and BE */
1127static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
1128 struct snd_soc_pcm_runtime *be, int stream)
1129{
1130 struct snd_soc_dpcm *dpcm;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001131 unsigned long flags;
Takashi Iwaibd0b6092019-11-07 14:48:33 +01001132#ifdef CONFIG_DEBUG_FS
Hans de Goede0632fa02019-10-05 23:22:02 +02001133 char *name;
Takashi Iwaibd0b6092019-11-07 14:48:33 +01001134#endif
Liam Girdwood01d75842012-04-25 12:12:49 +01001135
1136 /* only add new dpcms */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001137 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001138 if (dpcm->be == be && dpcm->fe == fe)
1139 return 0;
1140 }
1141
1142 dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_KERNEL);
1143 if (!dpcm)
1144 return -ENOMEM;
1145
1146 dpcm->be = be;
1147 dpcm->fe = fe;
1148 be->dpcm[stream].runtime = fe->dpcm[stream].runtime;
1149 dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001150 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001151 list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients);
1152 list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001153 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001154
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001155 dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001156 stream ? "capture" : "playback", fe->dai_link->name,
1157 stream ? "<-" : "->", be->dai_link->name);
1158
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001159#ifdef CONFIG_DEBUG_FS
Hans de Goede0632fa02019-10-05 23:22:02 +02001160 name = kasprintf(GFP_KERNEL, "%s:%s", be->dai_link->name,
1161 stream ? "capture" : "playback");
1162 if (name) {
1163 dpcm->debugfs_state = debugfs_create_dir(name,
1164 fe->debugfs_dpcm_root);
1165 debugfs_create_u32("state", 0644, dpcm->debugfs_state,
1166 &dpcm->state);
1167 kfree(name);
1168 }
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001169#endif
Liam Girdwood01d75842012-04-25 12:12:49 +01001170 return 1;
1171}
1172
1173/* reparent a BE onto another FE */
1174static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
1175 struct snd_soc_pcm_runtime *be, int stream)
1176{
1177 struct snd_soc_dpcm *dpcm;
1178 struct snd_pcm_substream *fe_substream, *be_substream;
1179
1180 /* reparent if BE is connected to other FEs */
1181 if (!be->dpcm[stream].users)
1182 return;
1183
1184 be_substream = snd_soc_dpcm_get_substream(be, stream);
1185
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00001186 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001187 if (dpcm->fe == fe)
1188 continue;
1189
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001190 dev_dbg(fe->dev, "reparent %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001191 stream ? "capture" : "playback",
1192 dpcm->fe->dai_link->name,
1193 stream ? "<-" : "->", dpcm->be->dai_link->name);
1194
1195 fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, stream);
1196 be_substream->runtime = fe_substream->runtime;
1197 break;
1198 }
1199}
1200
1201/* disconnect a BE and FE */
Liam Girdwood23607022014-01-17 17:03:55 +00001202void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001203{
1204 struct snd_soc_dpcm *dpcm, *d;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001205 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001206
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001207 for_each_dpcm_be_safe(fe, stream, dpcm, d) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001208 dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001209 stream ? "capture" : "playback",
1210 dpcm->be->dai_link->name);
1211
1212 if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE)
1213 continue;
1214
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001215 dev_dbg(fe->dev, "freed DSP %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001216 stream ? "capture" : "playback", fe->dai_link->name,
1217 stream ? "<-" : "->", dpcm->be->dai_link->name);
1218
1219 /* BEs still alive need new FE */
1220 dpcm_be_reparent(fe, dpcm->be, stream);
1221
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001222#ifdef CONFIG_DEBUG_FS
Greg Kroah-Hartmanfee531d2019-07-31 15:17:15 +02001223 debugfs_remove_recursive(dpcm->debugfs_state);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001224#endif
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001225 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001226 list_del(&dpcm->list_be);
1227 list_del(&dpcm->list_fe);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001228 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001229 kfree(dpcm);
1230 }
1231}
1232
1233/* get BE for DAI widget and stream */
1234static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
1235 struct snd_soc_dapm_widget *widget, int stream)
1236{
1237 struct snd_soc_pcm_runtime *be;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001238 struct snd_soc_dai *dai;
Mengdong Lin1a497982015-11-18 02:34:11 -05001239 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01001240
Liam Girdwood3c146462018-03-14 20:43:51 +00001241 dev_dbg(card->dev, "ASoC: find BE for widget %s\n", widget->name);
1242
Liam Girdwood01d75842012-04-25 12:12:49 +01001243 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00001244 for_each_card_rtds(card, be) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001245
Liam Girdwood35ea0652012-06-05 19:26:59 +01001246 if (!be->dai_link->no_pcm)
1247 continue;
1248
Liam Girdwood3c146462018-03-14 20:43:51 +00001249 dev_dbg(card->dev, "ASoC: try BE : %s\n",
1250 be->cpu_dai->playback_widget ?
1251 be->cpu_dai->playback_widget->name : "(not set)");
1252
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001253 if (be->cpu_dai->playback_widget == widget)
Liam Girdwood01d75842012-04-25 12:12:49 +01001254 return be;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001255
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001256 for_each_rtd_codec_dai(be, i, dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001257 if (dai->playback_widget == widget)
1258 return be;
1259 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001260 }
1261 } else {
1262
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00001263 for_each_card_rtds(card, be) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001264
Liam Girdwood35ea0652012-06-05 19:26:59 +01001265 if (!be->dai_link->no_pcm)
1266 continue;
1267
Liam Girdwood3c146462018-03-14 20:43:51 +00001268 dev_dbg(card->dev, "ASoC: try BE %s\n",
1269 be->cpu_dai->capture_widget ?
1270 be->cpu_dai->capture_widget->name : "(not set)");
1271
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001272 if (be->cpu_dai->capture_widget == widget)
Liam Girdwood01d75842012-04-25 12:12:49 +01001273 return be;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001274
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001275 for_each_rtd_codec_dai(be, i, dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001276 if (dai->capture_widget == widget)
1277 return be;
1278 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001279 }
1280 }
1281
Liam Girdwood3c146462018-03-14 20:43:51 +00001282 /* dai link name and stream name set correctly ? */
Liam Girdwood103d84a2012-11-19 14:39:15 +00001283 dev_err(card->dev, "ASoC: can't get %s BE for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001284 stream ? "capture" : "playback", widget->name);
1285 return NULL;
1286}
1287
1288static inline struct snd_soc_dapm_widget *
Benoit Cousson37018612014-04-24 14:01:45 +02001289 dai_get_widget(struct snd_soc_dai *dai, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001290{
1291 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
Benoit Cousson37018612014-04-24 14:01:45 +02001292 return dai->playback_widget;
Liam Girdwood01d75842012-04-25 12:12:49 +01001293 else
Benoit Cousson37018612014-04-24 14:01:45 +02001294 return dai->capture_widget;
Liam Girdwood01d75842012-04-25 12:12:49 +01001295}
1296
1297static int widget_in_list(struct snd_soc_dapm_widget_list *list,
1298 struct snd_soc_dapm_widget *widget)
1299{
1300 int i;
1301
1302 for (i = 0; i < list->num_widgets; i++) {
1303 if (widget == list->widgets[i])
1304 return 1;
1305 }
1306
1307 return 0;
1308}
1309
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001310static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget,
1311 enum snd_soc_dapm_direction dir)
1312{
1313 struct snd_soc_card *card = widget->dapm->card;
1314 struct snd_soc_pcm_runtime *rtd;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001315 struct snd_soc_dai *dai;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001316 int i;
1317
1318 if (dir == SND_SOC_DAPM_DIR_OUT) {
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00001319 for_each_card_rtds(card, rtd) {
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001320 if (!rtd->dai_link->no_pcm)
1321 continue;
1322
1323 if (rtd->cpu_dai->playback_widget == widget)
1324 return true;
1325
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001326 for_each_rtd_codec_dai(rtd, i, dai) {
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001327 if (dai->playback_widget == widget)
1328 return true;
1329 }
1330 }
1331 } else { /* SND_SOC_DAPM_DIR_IN */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00001332 for_each_card_rtds(card, rtd) {
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001333 if (!rtd->dai_link->no_pcm)
1334 continue;
1335
1336 if (rtd->cpu_dai->capture_widget == widget)
1337 return true;
1338
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001339 for_each_rtd_codec_dai(rtd, i, dai) {
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001340 if (dai->capture_widget == widget)
1341 return true;
1342 }
1343 }
1344 }
1345
1346 return false;
1347}
1348
Liam Girdwood23607022014-01-17 17:03:55 +00001349int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001350 int stream, struct snd_soc_dapm_widget_list **list)
Liam Girdwood01d75842012-04-25 12:12:49 +01001351{
1352 struct snd_soc_dai *cpu_dai = fe->cpu_dai;
Liam Girdwood01d75842012-04-25 12:12:49 +01001353 int paths;
1354
Liam Girdwood01d75842012-04-25 12:12:49 +01001355 /* get number of valid DAI paths and their widgets */
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001356 paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list,
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001357 dpcm_end_walk_at_be);
Liam Girdwood01d75842012-04-25 12:12:49 +01001358
Liam Girdwood103d84a2012-11-19 14:39:15 +00001359 dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths,
Liam Girdwood01d75842012-04-25 12:12:49 +01001360 stream ? "capture" : "playback");
1361
Liam Girdwood01d75842012-04-25 12:12:49 +01001362 return paths;
1363}
1364
Liam Girdwood01d75842012-04-25 12:12:49 +01001365static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
1366 struct snd_soc_dapm_widget_list **list_)
1367{
1368 struct snd_soc_dpcm *dpcm;
1369 struct snd_soc_dapm_widget_list *list = *list_;
1370 struct snd_soc_dapm_widget *widget;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001371 struct snd_soc_dai *dai;
Liam Girdwood01d75842012-04-25 12:12:49 +01001372 int prune = 0;
Kuninori Morimotobed646d2019-10-15 12:59:38 +09001373 int do_prune;
Liam Girdwood01d75842012-04-25 12:12:49 +01001374
1375 /* Destroy any old FE <--> BE connections */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001376 for_each_dpcm_be(fe, stream, dpcm) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001377 unsigned int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01001378
1379 /* is there a valid CPU DAI widget for this BE */
Benoit Cousson37018612014-04-24 14:01:45 +02001380 widget = dai_get_widget(dpcm->be->cpu_dai, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001381
1382 /* prune the BE if it's no longer in our active list */
1383 if (widget && widget_in_list(list, widget))
1384 continue;
1385
1386 /* is there a valid CODEC DAI widget for this BE */
Kuninori Morimotobed646d2019-10-15 12:59:38 +09001387 do_prune = 1;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001388 for_each_rtd_codec_dai(dpcm->be, i, dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001389 widget = dai_get_widget(dai, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001390
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001391 /* prune the BE if it's no longer in our active list */
1392 if (widget && widget_in_list(list, widget))
Kuninori Morimotobed646d2019-10-15 12:59:38 +09001393 do_prune = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001394 }
Kuninori Morimotobed646d2019-10-15 12:59:38 +09001395 if (!do_prune)
1396 continue;
Liam Girdwood01d75842012-04-25 12:12:49 +01001397
Liam Girdwood103d84a2012-11-19 14:39:15 +00001398 dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001399 stream ? "capture" : "playback",
1400 dpcm->be->dai_link->name, fe->dai_link->name);
1401 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
1402 dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1403 prune++;
1404 }
1405
Liam Girdwood103d84a2012-11-19 14:39:15 +00001406 dev_dbg(fe->dev, "ASoC: found %d old BE paths for pruning\n", prune);
Liam Girdwood01d75842012-04-25 12:12:49 +01001407 return prune;
1408}
1409
1410static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
1411 struct snd_soc_dapm_widget_list **list_)
1412{
1413 struct snd_soc_card *card = fe->card;
1414 struct snd_soc_dapm_widget_list *list = *list_;
1415 struct snd_soc_pcm_runtime *be;
1416 int i, new = 0, err;
1417
1418 /* Create any new FE <--> BE connections */
1419 for (i = 0; i < list->num_widgets; i++) {
1420
Mark Brown46162742013-06-05 19:36:11 +01001421 switch (list->widgets[i]->id) {
1422 case snd_soc_dapm_dai_in:
Koro Chenc5b85402015-07-06 10:02:10 +08001423 if (stream != SNDRV_PCM_STREAM_PLAYBACK)
1424 continue;
1425 break;
Mark Brown46162742013-06-05 19:36:11 +01001426 case snd_soc_dapm_dai_out:
Koro Chenc5b85402015-07-06 10:02:10 +08001427 if (stream != SNDRV_PCM_STREAM_CAPTURE)
1428 continue;
Mark Brown46162742013-06-05 19:36:11 +01001429 break;
1430 default:
Liam Girdwood01d75842012-04-25 12:12:49 +01001431 continue;
Mark Brown46162742013-06-05 19:36:11 +01001432 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001433
1434 /* is there a valid BE rtd for this widget */
1435 be = dpcm_get_be(card, list->widgets[i], stream);
1436 if (!be) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001437 dev_err(fe->dev, "ASoC: no BE found for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001438 list->widgets[i]->name);
1439 continue;
1440 }
1441
1442 /* make sure BE is a real BE */
1443 if (!be->dai_link->no_pcm)
1444 continue;
1445
1446 /* don't connect if FE is not running */
Liam Girdwood23607022014-01-17 17:03:55 +00001447 if (!fe->dpcm[stream].runtime && !fe->fe_compr)
Liam Girdwood01d75842012-04-25 12:12:49 +01001448 continue;
1449
1450 /* newly connected FE and BE */
1451 err = dpcm_be_connect(fe, be, stream);
1452 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001453 dev_err(fe->dev, "ASoC: can't connect %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001454 list->widgets[i]->name);
1455 break;
1456 } else if (err == 0) /* already connected */
1457 continue;
1458
1459 /* new */
1460 be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1461 new++;
1462 }
1463
Liam Girdwood103d84a2012-11-19 14:39:15 +00001464 dev_dbg(fe->dev, "ASoC: found %d new BE paths\n", new);
Liam Girdwood01d75842012-04-25 12:12:49 +01001465 return new;
1466}
1467
1468/*
1469 * Find the corresponding BE DAIs that source or sink audio to this
1470 * FE substream.
1471 */
Liam Girdwood23607022014-01-17 17:03:55 +00001472int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
Liam Girdwood01d75842012-04-25 12:12:49 +01001473 int stream, struct snd_soc_dapm_widget_list **list, int new)
1474{
1475 if (new)
1476 return dpcm_add_paths(fe, stream, list);
1477 else
1478 return dpcm_prune_paths(fe, stream, list);
1479}
1480
Liam Girdwood23607022014-01-17 17:03:55 +00001481void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001482{
1483 struct snd_soc_dpcm *dpcm;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001484 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001485
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001486 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001487 for_each_dpcm_be(fe, stream, dpcm)
Liam Girdwood01d75842012-04-25 12:12:49 +01001488 dpcm->be->dpcm[stream].runtime_update =
1489 SND_SOC_DPCM_UPDATE_NO;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001490 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001491}
1492
1493static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe,
1494 int stream)
1495{
1496 struct snd_soc_dpcm *dpcm;
1497
1498 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001499 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001500
1501 struct snd_soc_pcm_runtime *be = dpcm->be;
1502 struct snd_pcm_substream *be_substream =
1503 snd_soc_dpcm_get_substream(be, stream);
1504
1505 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001506 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001507 stream ? "capture" : "playback",
1508 be->dpcm[stream].state);
1509
1510 if (--be->dpcm[stream].users != 0)
1511 continue;
1512
1513 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1514 continue;
1515
1516 soc_pcm_close(be_substream);
1517 be_substream->runtime = NULL;
1518 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1519 }
1520}
1521
Liam Girdwood23607022014-01-17 17:03:55 +00001522int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001523{
1524 struct snd_soc_dpcm *dpcm;
1525 int err, count = 0;
1526
1527 /* only startup BE DAIs that are either sinks or sources to this FE DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001528 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001529
1530 struct snd_soc_pcm_runtime *be = dpcm->be;
1531 struct snd_pcm_substream *be_substream =
1532 snd_soc_dpcm_get_substream(be, stream);
1533
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001534 if (!be_substream) {
1535 dev_err(be->dev, "ASoC: no backend %s stream\n",
1536 stream ? "capture" : "playback");
1537 continue;
1538 }
1539
Liam Girdwood01d75842012-04-25 12:12:49 +01001540 /* is this op for this BE ? */
1541 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1542 continue;
1543
1544 /* first time the dpcm is open ? */
1545 if (be->dpcm[stream].users == DPCM_MAX_BE_USERS)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001546 dev_err(be->dev, "ASoC: too many users %s at open %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001547 stream ? "capture" : "playback",
1548 be->dpcm[stream].state);
1549
1550 if (be->dpcm[stream].users++ != 0)
1551 continue;
1552
1553 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
1554 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
1555 continue;
1556
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001557 dev_dbg(be->dev, "ASoC: open %s BE %s\n",
1558 stream ? "capture" : "playback", be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001559
1560 be_substream->runtime = be->dpcm[stream].runtime;
1561 err = soc_pcm_open(be_substream);
1562 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001563 dev_err(be->dev, "ASoC: BE open failed %d\n", err);
Liam Girdwood01d75842012-04-25 12:12:49 +01001564 be->dpcm[stream].users--;
1565 if (be->dpcm[stream].users < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001566 dev_err(be->dev, "ASoC: no users %s at unwind %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001567 stream ? "capture" : "playback",
1568 be->dpcm[stream].state);
1569
1570 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1571 goto unwind;
1572 }
1573
1574 be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1575 count++;
1576 }
1577
1578 return count;
1579
1580unwind:
1581 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001582 for_each_dpcm_be_rollback(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001583 struct snd_soc_pcm_runtime *be = dpcm->be;
1584 struct snd_pcm_substream *be_substream =
1585 snd_soc_dpcm_get_substream(be, stream);
1586
1587 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1588 continue;
1589
1590 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001591 dev_err(be->dev, "ASoC: no users %s at close %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001592 stream ? "capture" : "playback",
1593 be->dpcm[stream].state);
1594
1595 if (--be->dpcm[stream].users != 0)
1596 continue;
1597
1598 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1599 continue;
1600
1601 soc_pcm_close(be_substream);
1602 be_substream->runtime = NULL;
1603 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1604 }
1605
1606 return err;
1607}
1608
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001609static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
Jerome Brunet435ffb72018-07-05 12:13:48 +02001610 struct snd_soc_pcm_stream *stream)
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001611{
1612 runtime->hw.rate_min = stream->rate_min;
Charles Keepaxe33ffbd9c2018-08-27 14:26:47 +01001613 runtime->hw.rate_max = min_not_zero(stream->rate_max, UINT_MAX);
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001614 runtime->hw.channels_min = stream->channels_min;
1615 runtime->hw.channels_max = stream->channels_max;
Lars-Peter Clausen002220a2014-01-06 14:19:07 +01001616 if (runtime->hw.formats)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001617 runtime->hw.formats &= stream->formats;
Lars-Peter Clausen002220a2014-01-06 14:19:07 +01001618 else
Jerome Brunet435ffb72018-07-05 12:13:48 +02001619 runtime->hw.formats = stream->formats;
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001620 runtime->hw.rates = stream->rates;
1621}
1622
Jerome Brunet435ffb72018-07-05 12:13:48 +02001623static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream,
1624 u64 *formats)
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001625{
1626 struct snd_soc_pcm_runtime *fe = substream->private_data;
1627 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001628 struct snd_soc_dai *dai;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001629 int stream = substream->stream;
1630
1631 if (!fe->dai_link->dpcm_merged_format)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001632 return;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001633
1634 /*
1635 * It returns merged BE codec format
1636 * if FE want to use it (= dpcm_merged_format)
1637 */
1638
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001639 for_each_dpcm_be(fe, stream, dpcm) {
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001640 struct snd_soc_pcm_runtime *be = dpcm->be;
1641 struct snd_soc_dai_driver *codec_dai_drv;
1642 struct snd_soc_pcm_stream *codec_stream;
1643 int i;
1644
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001645 for_each_rtd_codec_dai(be, i, dai) {
Jerome Brunet4febced2018-06-27 17:36:38 +02001646 /*
1647 * Skip CODECs which don't support the current stream
1648 * type. See soc_pcm_init_runtime_hw() for more details
1649 */
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001650 if (!snd_soc_dai_stream_valid(dai, stream))
Jerome Brunet4febced2018-06-27 17:36:38 +02001651 continue;
1652
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001653 codec_dai_drv = dai->driver;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001654 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1655 codec_stream = &codec_dai_drv->playback;
1656 else
1657 codec_stream = &codec_dai_drv->capture;
1658
Jerome Brunet435ffb72018-07-05 12:13:48 +02001659 *formats &= codec_stream->formats;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001660 }
1661 }
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001662}
1663
Jerome Brunet435ffb72018-07-05 12:13:48 +02001664static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream,
1665 unsigned int *channels_min,
1666 unsigned int *channels_max)
Jiada Wangf4c277b2018-06-20 18:25:20 +09001667{
1668 struct snd_soc_pcm_runtime *fe = substream->private_data;
1669 struct snd_soc_dpcm *dpcm;
1670 int stream = substream->stream;
1671
1672 if (!fe->dai_link->dpcm_merged_chan)
1673 return;
1674
Jiada Wangf4c277b2018-06-20 18:25:20 +09001675 /*
1676 * It returns merged BE codec channel;
1677 * if FE want to use it (= dpcm_merged_chan)
1678 */
1679
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001680 for_each_dpcm_be(fe, stream, dpcm) {
Jiada Wangf4c277b2018-06-20 18:25:20 +09001681 struct snd_soc_pcm_runtime *be = dpcm->be;
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001682 struct snd_soc_dai_driver *cpu_dai_drv = be->cpu_dai->driver;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001683 struct snd_soc_dai_driver *codec_dai_drv;
1684 struct snd_soc_pcm_stream *codec_stream;
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001685 struct snd_soc_pcm_stream *cpu_stream;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001686
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001687 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1688 cpu_stream = &cpu_dai_drv->playback;
1689 else
1690 cpu_stream = &cpu_dai_drv->capture;
1691
1692 *channels_min = max(*channels_min, cpu_stream->channels_min);
1693 *channels_max = min(*channels_max, cpu_stream->channels_max);
1694
1695 /*
1696 * chan min/max cannot be enforced if there are multiple CODEC
1697 * DAIs connected to a single CPU DAI, use CPU DAI's directly
1698 */
1699 if (be->num_codecs == 1) {
1700 codec_dai_drv = be->codec_dais[0]->driver;
1701
Jiada Wangf4c277b2018-06-20 18:25:20 +09001702 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1703 codec_stream = &codec_dai_drv->playback;
1704 else
1705 codec_stream = &codec_dai_drv->capture;
1706
1707 *channels_min = max(*channels_min,
1708 codec_stream->channels_min);
1709 *channels_max = min(*channels_max,
1710 codec_stream->channels_max);
1711 }
1712 }
1713}
1714
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001715static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream,
1716 unsigned int *rates,
1717 unsigned int *rate_min,
1718 unsigned int *rate_max)
1719{
1720 struct snd_soc_pcm_runtime *fe = substream->private_data;
1721 struct snd_soc_dpcm *dpcm;
1722 int stream = substream->stream;
1723
1724 if (!fe->dai_link->dpcm_merged_rate)
1725 return;
1726
1727 /*
1728 * It returns merged BE codec channel;
1729 * if FE want to use it (= dpcm_merged_chan)
1730 */
1731
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001732 for_each_dpcm_be(fe, stream, dpcm) {
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001733 struct snd_soc_pcm_runtime *be = dpcm->be;
1734 struct snd_soc_dai_driver *cpu_dai_drv = be->cpu_dai->driver;
1735 struct snd_soc_dai_driver *codec_dai_drv;
1736 struct snd_soc_pcm_stream *codec_stream;
1737 struct snd_soc_pcm_stream *cpu_stream;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001738 struct snd_soc_dai *dai;
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001739 int i;
1740
1741 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1742 cpu_stream = &cpu_dai_drv->playback;
1743 else
1744 cpu_stream = &cpu_dai_drv->capture;
1745
1746 *rate_min = max(*rate_min, cpu_stream->rate_min);
1747 *rate_max = min_not_zero(*rate_max, cpu_stream->rate_max);
1748 *rates = snd_pcm_rate_mask_intersect(*rates, cpu_stream->rates);
1749
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001750 for_each_rtd_codec_dai(be, i, dai) {
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001751 /*
1752 * Skip CODECs which don't support the current stream
1753 * type. See soc_pcm_init_runtime_hw() for more details
1754 */
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001755 if (!snd_soc_dai_stream_valid(dai, stream))
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001756 continue;
1757
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001758 codec_dai_drv = dai->driver;
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001759 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1760 codec_stream = &codec_dai_drv->playback;
1761 else
1762 codec_stream = &codec_dai_drv->capture;
1763
1764 *rate_min = max(*rate_min, codec_stream->rate_min);
1765 *rate_max = min_not_zero(*rate_max,
1766 codec_stream->rate_max);
1767 *rates = snd_pcm_rate_mask_intersect(*rates,
1768 codec_stream->rates);
1769 }
1770 }
1771}
1772
Mark Brown45c0a182012-05-09 21:46:27 +01001773static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001774{
1775 struct snd_pcm_runtime *runtime = substream->runtime;
1776 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1777 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
1778 struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
1779
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001780 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001781 dpcm_init_runtime_hw(runtime, &cpu_dai_drv->playback);
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001782 else
Jerome Brunet435ffb72018-07-05 12:13:48 +02001783 dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture);
Jiada Wangf4c277b2018-06-20 18:25:20 +09001784
Jerome Brunet435ffb72018-07-05 12:13:48 +02001785 dpcm_runtime_merge_format(substream, &runtime->hw.formats);
1786 dpcm_runtime_merge_chan(substream, &runtime->hw.channels_min,
1787 &runtime->hw.channels_max);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001788 dpcm_runtime_merge_rate(substream, &runtime->hw.rates,
1789 &runtime->hw.rate_min, &runtime->hw.rate_max);
Liam Girdwood01d75842012-04-25 12:12:49 +01001790}
1791
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001792static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
1793
1794/* Set FE's runtime_update state; the state is protected via PCM stream lock
1795 * for avoiding the race with trigger callback.
1796 * If the state is unset and a trigger is pending while the previous operation,
1797 * process the pending trigger action here.
1798 */
1799static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
1800 int stream, enum snd_soc_dpcm_update state)
1801{
1802 struct snd_pcm_substream *substream =
1803 snd_soc_dpcm_get_substream(fe, stream);
1804
1805 snd_pcm_stream_lock_irq(substream);
1806 if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) {
1807 dpcm_fe_dai_do_trigger(substream,
1808 fe->dpcm[stream].trigger_pending - 1);
1809 fe->dpcm[stream].trigger_pending = 0;
1810 }
1811 fe->dpcm[stream].runtime_update = state;
1812 snd_pcm_stream_unlock_irq(substream);
1813}
1814
PC Liao906c7d62015-12-11 11:33:51 +08001815static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
1816 int stream)
1817{
1818 struct snd_soc_dpcm *dpcm;
1819 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
1820 struct snd_soc_dai *fe_cpu_dai = fe->cpu_dai;
1821 int err;
1822
1823 /* apply symmetry for FE */
1824 if (soc_pcm_has_symmetry(fe_substream))
1825 fe_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1826
1827 /* Symmetry only applies if we've got an active stream. */
1828 if (fe_cpu_dai->active) {
1829 err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai);
1830 if (err < 0)
1831 return err;
1832 }
1833
1834 /* apply symmetry for BE */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001835 for_each_dpcm_be(fe, stream, dpcm) {
PC Liao906c7d62015-12-11 11:33:51 +08001836 struct snd_soc_pcm_runtime *be = dpcm->be;
1837 struct snd_pcm_substream *be_substream =
1838 snd_soc_dpcm_get_substream(be, stream);
Jerome Brunet6246f282019-04-01 15:03:54 +02001839 struct snd_soc_pcm_runtime *rtd;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001840 struct snd_soc_dai *codec_dai;
PC Liao906c7d62015-12-11 11:33:51 +08001841 int i;
1842
Jerome Brunet6246f282019-04-01 15:03:54 +02001843 /* A backend may not have the requested substream */
1844 if (!be_substream)
1845 continue;
1846
1847 rtd = be_substream->private_data;
Jeeja KPf1176612016-09-06 14:17:55 +05301848 if (rtd->dai_link->be_hw_params_fixup)
1849 continue;
1850
PC Liao906c7d62015-12-11 11:33:51 +08001851 if (soc_pcm_has_symmetry(be_substream))
1852 be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1853
1854 /* Symmetry only applies if we've got an active stream. */
1855 if (rtd->cpu_dai->active) {
Kai Chieh Chuang99bcedb2018-05-28 10:18:19 +08001856 err = soc_pcm_apply_symmetry(fe_substream,
1857 rtd->cpu_dai);
PC Liao906c7d62015-12-11 11:33:51 +08001858 if (err < 0)
1859 return err;
1860 }
1861
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001862 for_each_rtd_codec_dai(rtd, i, codec_dai) {
1863 if (codec_dai->active) {
Kai Chieh Chuang99bcedb2018-05-28 10:18:19 +08001864 err = soc_pcm_apply_symmetry(fe_substream,
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001865 codec_dai);
PC Liao906c7d62015-12-11 11:33:51 +08001866 if (err < 0)
1867 return err;
1868 }
1869 }
1870 }
1871
1872 return 0;
1873}
1874
Liam Girdwood01d75842012-04-25 12:12:49 +01001875static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
1876{
1877 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
1878 struct snd_pcm_runtime *runtime = fe_substream->runtime;
1879 int stream = fe_substream->stream, ret = 0;
1880
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001881 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001882
1883 ret = dpcm_be_dai_startup(fe, fe_substream->stream);
1884 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001885 dev_err(fe->dev,"ASoC: failed to start some BEs %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001886 goto be_err;
1887 }
1888
Liam Girdwood103d84a2012-11-19 14:39:15 +00001889 dev_dbg(fe->dev, "ASoC: open FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001890
1891 /* start the DAI frontend */
1892 ret = soc_pcm_open(fe_substream);
1893 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001894 dev_err(fe->dev,"ASoC: failed to start FE %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001895 goto unwind;
1896 }
1897
1898 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1899
1900 dpcm_set_fe_runtime(fe_substream);
1901 snd_pcm_limit_hw_rates(runtime);
1902
PC Liao906c7d62015-12-11 11:33:51 +08001903 ret = dpcm_apply_symmetry(fe_substream, stream);
1904 if (ret < 0) {
1905 dev_err(fe->dev, "ASoC: failed to apply dpcm symmetry %d\n",
1906 ret);
1907 goto unwind;
1908 }
1909
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001910 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001911 return 0;
1912
1913unwind:
1914 dpcm_be_dai_startup_unwind(fe, fe_substream->stream);
1915be_err:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001916 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001917 return ret;
1918}
1919
Liam Girdwood23607022014-01-17 17:03:55 +00001920int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001921{
1922 struct snd_soc_dpcm *dpcm;
1923
1924 /* only shutdown BEs that are either sinks or sources to this FE DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001925 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001926
1927 struct snd_soc_pcm_runtime *be = dpcm->be;
1928 struct snd_pcm_substream *be_substream =
1929 snd_soc_dpcm_get_substream(be, stream);
1930
1931 /* is this op for this BE ? */
1932 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1933 continue;
1934
1935 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001936 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001937 stream ? "capture" : "playback",
1938 be->dpcm[stream].state);
1939
1940 if (--be->dpcm[stream].users != 0)
1941 continue;
1942
1943 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Kai Chieh Chuang9c0ac702018-05-28 10:18:18 +08001944 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) {
1945 soc_pcm_hw_free(be_substream);
1946 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1947 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001948
Liam Girdwood103d84a2012-11-19 14:39:15 +00001949 dev_dbg(be->dev, "ASoC: close BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001950 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001951
1952 soc_pcm_close(be_substream);
1953 be_substream->runtime = NULL;
1954
1955 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1956 }
1957 return 0;
1958}
1959
1960static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
1961{
1962 struct snd_soc_pcm_runtime *fe = substream->private_data;
1963 int stream = substream->stream;
1964
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001965 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001966
1967 /* shutdown the BEs */
1968 dpcm_be_dai_shutdown(fe, substream->stream);
1969
Liam Girdwood103d84a2012-11-19 14:39:15 +00001970 dev_dbg(fe->dev, "ASoC: close FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001971
1972 /* now shutdown the frontend */
1973 soc_pcm_close(substream);
1974
1975 /* run the stream event for each BE */
Kuninori Morimotob0edff42020-01-10 11:36:56 +09001976 snd_soc_dapm_stream_stop(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001977
1978 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001979 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001980 return 0;
1981}
1982
Liam Girdwood23607022014-01-17 17:03:55 +00001983int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001984{
1985 struct snd_soc_dpcm *dpcm;
1986
1987 /* only hw_params backends that are either sinks or sources
1988 * to this frontend DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001989 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001990
1991 struct snd_soc_pcm_runtime *be = dpcm->be;
1992 struct snd_pcm_substream *be_substream =
1993 snd_soc_dpcm_get_substream(be, stream);
1994
1995 /* is this op for this BE ? */
1996 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1997 continue;
1998
1999 /* only free hw when no longer used - check all FEs */
2000 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2001 continue;
2002
Qiao Zhou36fba622014-12-03 10:13:43 +08002003 /* do not free hw if this BE is used by other FE */
2004 if (be->dpcm[stream].users > 1)
2005 continue;
2006
Liam Girdwood01d75842012-04-25 12:12:49 +01002007 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2008 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
2009 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Patrick Lai08b27842012-12-19 19:36:02 -08002010 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
Vinod Koul5e82d2b2016-02-01 22:26:40 +05302011 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
2012 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
Liam Girdwood01d75842012-04-25 12:12:49 +01002013 continue;
2014
Liam Girdwood103d84a2012-11-19 14:39:15 +00002015 dev_dbg(be->dev, "ASoC: hw_free BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002016 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002017
2018 soc_pcm_hw_free(be_substream);
2019
2020 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
2021 }
2022
2023 return 0;
2024}
2025
Mark Brown45c0a182012-05-09 21:46:27 +01002026static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002027{
2028 struct snd_soc_pcm_runtime *fe = substream->private_data;
2029 int err, stream = substream->stream;
2030
2031 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002032 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002033
Liam Girdwood103d84a2012-11-19 14:39:15 +00002034 dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002035
2036 /* call hw_free on the frontend */
2037 err = soc_pcm_hw_free(substream);
2038 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002039 dev_err(fe->dev,"ASoC: hw_free FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002040 fe->dai_link->name);
2041
2042 /* only hw_params backends that are either sinks or sources
2043 * to this frontend DAI */
2044 err = dpcm_be_dai_hw_free(fe, stream);
2045
2046 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002047 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002048
2049 mutex_unlock(&fe->card->mutex);
2050 return 0;
2051}
2052
Liam Girdwood23607022014-01-17 17:03:55 +00002053int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002054{
2055 struct snd_soc_dpcm *dpcm;
2056 int ret;
2057
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002058 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002059
2060 struct snd_soc_pcm_runtime *be = dpcm->be;
2061 struct snd_pcm_substream *be_substream =
2062 snd_soc_dpcm_get_substream(be, stream);
2063
2064 /* is this op for this BE ? */
2065 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2066 continue;
2067
Liam Girdwood01d75842012-04-25 12:12:49 +01002068 /* copy params for each dpcm */
2069 memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params,
2070 sizeof(struct snd_pcm_hw_params));
2071
2072 /* perform any hw_params fixups */
2073 if (be->dai_link->be_hw_params_fixup) {
2074 ret = be->dai_link->be_hw_params_fixup(be,
2075 &dpcm->hw_params);
2076 if (ret < 0) {
2077 dev_err(be->dev,
Liam Girdwood103d84a2012-11-19 14:39:15 +00002078 "ASoC: hw_params BE fixup failed %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002079 ret);
2080 goto unwind;
2081 }
2082 }
2083
Libin Yangae061d22019-04-19 09:53:12 +08002084 /* copy the fixed-up hw params for BE dai */
2085 memcpy(&be->dpcm[stream].hw_params, &dpcm->hw_params,
2086 sizeof(struct snd_pcm_hw_params));
2087
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00002088 /* only allow hw_params() if no connected FEs are running */
2089 if (!snd_soc_dpcm_can_be_params(fe, be, stream))
2090 continue;
2091
2092 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
2093 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2094 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE))
2095 continue;
2096
2097 dev_dbg(be->dev, "ASoC: hw_params BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002098 be->dai_link->name);
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00002099
Liam Girdwood01d75842012-04-25 12:12:49 +01002100 ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params);
2101 if (ret < 0) {
2102 dev_err(dpcm->be->dev,
Liam Girdwood103d84a2012-11-19 14:39:15 +00002103 "ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002104 goto unwind;
2105 }
2106
2107 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2108 }
2109 return 0;
2110
2111unwind:
2112 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002113 for_each_dpcm_be_rollback(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002114 struct snd_soc_pcm_runtime *be = dpcm->be;
2115 struct snd_pcm_substream *be_substream =
2116 snd_soc_dpcm_get_substream(be, stream);
2117
2118 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2119 continue;
2120
2121 /* only allow hw_free() if no connected FEs are running */
2122 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2123 continue;
2124
2125 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
2126 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2127 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
2128 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
2129 continue;
2130
2131 soc_pcm_hw_free(be_substream);
2132 }
2133
2134 return ret;
2135}
2136
Mark Brown45c0a182012-05-09 21:46:27 +01002137static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
2138 struct snd_pcm_hw_params *params)
Liam Girdwood01d75842012-04-25 12:12:49 +01002139{
2140 struct snd_soc_pcm_runtime *fe = substream->private_data;
2141 int ret, stream = substream->stream;
2142
2143 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002144 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002145
2146 memcpy(&fe->dpcm[substream->stream].hw_params, params,
2147 sizeof(struct snd_pcm_hw_params));
2148 ret = dpcm_be_dai_hw_params(fe, substream->stream);
2149 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002150 dev_err(fe->dev,"ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002151 goto out;
2152 }
2153
Liam Girdwood103d84a2012-11-19 14:39:15 +00002154 dev_dbg(fe->dev, "ASoC: hw_params FE %s rate %d chan %x fmt %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002155 fe->dai_link->name, params_rate(params),
2156 params_channels(params), params_format(params));
2157
2158 /* call hw_params on the frontend */
2159 ret = soc_pcm_hw_params(substream, params);
2160 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002161 dev_err(fe->dev,"ASoC: hw_params FE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002162 dpcm_be_dai_hw_free(fe, stream);
2163 } else
2164 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2165
2166out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002167 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002168 mutex_unlock(&fe->card->mutex);
2169 return ret;
2170}
2171
2172static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm,
2173 struct snd_pcm_substream *substream, int cmd)
2174{
2175 int ret;
2176
Liam Girdwood103d84a2012-11-19 14:39:15 +00002177 dev_dbg(dpcm->be->dev, "ASoC: trigger BE %s cmd %d\n",
彭东林94d215c2016-09-26 08:29:31 +00002178 dpcm->be->dai_link->name, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002179
2180 ret = soc_pcm_trigger(substream, cmd);
2181 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002182 dev_err(dpcm->be->dev,"ASoC: trigger BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002183
2184 return ret;
2185}
2186
Liam Girdwood23607022014-01-17 17:03:55 +00002187int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
Mark Brown45c0a182012-05-09 21:46:27 +01002188 int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002189{
2190 struct snd_soc_dpcm *dpcm;
2191 int ret = 0;
2192
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002193 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002194
2195 struct snd_soc_pcm_runtime *be = dpcm->be;
2196 struct snd_pcm_substream *be_substream =
2197 snd_soc_dpcm_get_substream(be, stream);
2198
2199 /* is this op for this BE ? */
2200 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2201 continue;
2202
2203 switch (cmd) {
2204 case SNDRV_PCM_TRIGGER_START:
2205 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
2206 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
2207 continue;
2208
2209 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2210 if (ret)
2211 return ret;
2212
2213 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2214 break;
2215 case SNDRV_PCM_TRIGGER_RESUME:
2216 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
2217 continue;
2218
2219 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2220 if (ret)
2221 return ret;
2222
2223 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2224 break;
2225 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2226 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
2227 continue;
2228
2229 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2230 if (ret)
2231 return ret;
2232
2233 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2234 break;
2235 case SNDRV_PCM_TRIGGER_STOP:
2236 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2237 continue;
2238
2239 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2240 continue;
2241
2242 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2243 if (ret)
2244 return ret;
2245
2246 be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2247 break;
2248 case SNDRV_PCM_TRIGGER_SUSPEND:
Nicolin Chen868a6ca2014-05-12 20:12:05 +08002249 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
Liam Girdwood01d75842012-04-25 12:12:49 +01002250 continue;
2251
2252 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2253 continue;
2254
2255 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2256 if (ret)
2257 return ret;
2258
2259 be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND;
2260 break;
2261 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2262 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2263 continue;
2264
2265 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2266 continue;
2267
2268 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2269 if (ret)
2270 return ret;
2271
2272 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2273 break;
2274 }
2275 }
2276
2277 return ret;
2278}
2279EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
2280
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002281static int dpcm_dai_trigger_fe_be(struct snd_pcm_substream *substream,
2282 int cmd, bool fe_first)
2283{
2284 struct snd_soc_pcm_runtime *fe = substream->private_data;
2285 int ret;
2286
2287 /* call trigger on the frontend before the backend. */
2288 if (fe_first) {
2289 dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n",
2290 fe->dai_link->name, cmd);
2291
2292 ret = soc_pcm_trigger(substream, cmd);
2293 if (ret < 0)
2294 return ret;
2295
2296 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2297 return ret;
2298 }
2299
2300 /* call trigger on the frontend after the backend. */
2301 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2302 if (ret < 0)
2303 return ret;
2304
2305 dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n",
2306 fe->dai_link->name, cmd);
2307
2308 ret = soc_pcm_trigger(substream, cmd);
2309
2310 return ret;
2311}
2312
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002313static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002314{
2315 struct snd_soc_pcm_runtime *fe = substream->private_data;
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002316 int stream = substream->stream;
2317 int ret = 0;
Liam Girdwood01d75842012-04-25 12:12:49 +01002318 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
2319
2320 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
2321
2322 switch (trigger) {
2323 case SND_SOC_DPCM_TRIGGER_PRE:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002324 switch (cmd) {
2325 case SNDRV_PCM_TRIGGER_START:
2326 case SNDRV_PCM_TRIGGER_RESUME:
2327 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2328 ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
2329 break;
2330 case SNDRV_PCM_TRIGGER_STOP:
2331 case SNDRV_PCM_TRIGGER_SUSPEND:
2332 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2333 ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
2334 break;
2335 default:
2336 ret = -EINVAL;
2337 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002338 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002339 break;
2340 case SND_SOC_DPCM_TRIGGER_POST:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002341 switch (cmd) {
2342 case SNDRV_PCM_TRIGGER_START:
2343 case SNDRV_PCM_TRIGGER_RESUME:
2344 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2345 ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
2346 break;
2347 case SNDRV_PCM_TRIGGER_STOP:
2348 case SNDRV_PCM_TRIGGER_SUSPEND:
2349 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2350 ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
2351 break;
2352 default:
2353 ret = -EINVAL;
2354 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002355 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002356 break;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002357 case SND_SOC_DPCM_TRIGGER_BESPOKE:
2358 /* bespoke trigger() - handles both FE and BEs */
2359
Liam Girdwood103d84a2012-11-19 14:39:15 +00002360 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd %d\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002361 fe->dai_link->name, cmd);
2362
2363 ret = soc_pcm_bespoke_trigger(substream, cmd);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002364 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002365 default:
Liam Girdwood103d84a2012-11-19 14:39:15 +00002366 dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd,
Liam Girdwood01d75842012-04-25 12:12:49 +01002367 fe->dai_link->name);
2368 ret = -EINVAL;
2369 goto out;
2370 }
2371
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002372 if (ret < 0) {
2373 dev_err(fe->dev, "ASoC: trigger FE cmd: %d failed: %d\n",
2374 cmd, ret);
2375 goto out;
2376 }
2377
Liam Girdwood01d75842012-04-25 12:12:49 +01002378 switch (cmd) {
2379 case SNDRV_PCM_TRIGGER_START:
2380 case SNDRV_PCM_TRIGGER_RESUME:
2381 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2382 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2383 break;
2384 case SNDRV_PCM_TRIGGER_STOP:
2385 case SNDRV_PCM_TRIGGER_SUSPEND:
Liam Girdwood01d75842012-04-25 12:12:49 +01002386 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2387 break;
Patrick Lai9f169b92016-12-31 22:44:39 -08002388 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2389 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2390 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002391 }
2392
2393out:
2394 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
2395 return ret;
2396}
2397
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002398static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
2399{
2400 struct snd_soc_pcm_runtime *fe = substream->private_data;
2401 int stream = substream->stream;
2402
2403 /* if FE's runtime_update is already set, we're in race;
2404 * process this trigger later at exit
2405 */
2406 if (fe->dpcm[stream].runtime_update != SND_SOC_DPCM_UPDATE_NO) {
2407 fe->dpcm[stream].trigger_pending = cmd + 1;
2408 return 0; /* delayed, assuming it's successful */
2409 }
2410
2411 /* we're alone, let's trigger */
2412 return dpcm_fe_dai_do_trigger(substream, cmd);
2413}
2414
Liam Girdwood23607022014-01-17 17:03:55 +00002415int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002416{
2417 struct snd_soc_dpcm *dpcm;
2418 int ret = 0;
2419
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002420 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002421
2422 struct snd_soc_pcm_runtime *be = dpcm->be;
2423 struct snd_pcm_substream *be_substream =
2424 snd_soc_dpcm_get_substream(be, stream);
2425
2426 /* is this op for this BE ? */
2427 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2428 continue;
2429
2430 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
Koro Chen95f444d2015-10-28 10:15:34 +08002431 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
Libin Yang5087a8f2019-05-08 10:32:41 +08002432 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND) &&
2433 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Liam Girdwood01d75842012-04-25 12:12:49 +01002434 continue;
2435
Liam Girdwood103d84a2012-11-19 14:39:15 +00002436 dev_dbg(be->dev, "ASoC: prepare BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002437 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002438
2439 ret = soc_pcm_prepare(be_substream);
2440 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002441 dev_err(be->dev, "ASoC: backend prepare failed %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002442 ret);
2443 break;
2444 }
2445
2446 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2447 }
2448 return ret;
2449}
2450
Mark Brown45c0a182012-05-09 21:46:27 +01002451static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002452{
2453 struct snd_soc_pcm_runtime *fe = substream->private_data;
2454 int stream = substream->stream, ret = 0;
2455
2456 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2457
Liam Girdwood103d84a2012-11-19 14:39:15 +00002458 dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002459
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002460 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002461
2462 /* there is no point preparing this FE if there are no BEs */
2463 if (list_empty(&fe->dpcm[stream].be_clients)) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002464 dev_err(fe->dev, "ASoC: no backend DAIs enabled for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002465 fe->dai_link->name);
2466 ret = -EINVAL;
2467 goto out;
2468 }
2469
2470 ret = dpcm_be_dai_prepare(fe, substream->stream);
2471 if (ret < 0)
2472 goto out;
2473
2474 /* call prepare on the frontend */
2475 ret = soc_pcm_prepare(substream);
2476 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002477 dev_err(fe->dev,"ASoC: prepare FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002478 fe->dai_link->name);
2479 goto out;
2480 }
2481
2482 /* run the stream event for each BE */
2483 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
2484 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2485
2486out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002487 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002488 mutex_unlock(&fe->card->mutex);
2489
2490 return ret;
2491}
2492
Liam Girdwood618dae12012-04-25 12:12:51 +01002493static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
2494{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002495 struct snd_pcm_substream *substream =
2496 snd_soc_dpcm_get_substream(fe, stream);
2497 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01002498 int err;
Liam Girdwood01d75842012-04-25 12:12:49 +01002499
Liam Girdwood103d84a2012-11-19 14:39:15 +00002500 dev_dbg(fe->dev, "ASoC: runtime %s close on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002501 stream ? "capture" : "playback", fe->dai_link->name);
2502
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002503 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2504 /* call bespoke trigger - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002505 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002506 fe->dai_link->name);
2507
2508 err = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
2509 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002510 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002511 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002512 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002513 fe->dai_link->name);
2514
2515 err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
2516 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002517 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002518 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002519
2520 err = dpcm_be_dai_hw_free(fe, stream);
2521 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002522 dev_err(fe->dev,"ASoC: hw_free FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002523
2524 err = dpcm_be_dai_shutdown(fe, stream);
2525 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002526 dev_err(fe->dev,"ASoC: shutdown FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002527
2528 /* run the stream event for each BE */
2529 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2530
2531 return 0;
2532}
2533
2534static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
2535{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002536 struct snd_pcm_substream *substream =
2537 snd_soc_dpcm_get_substream(fe, stream);
Liam Girdwood618dae12012-04-25 12:12:51 +01002538 struct snd_soc_dpcm *dpcm;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002539 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01002540 int ret;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002541 unsigned long flags;
Liam Girdwood618dae12012-04-25 12:12:51 +01002542
Liam Girdwood103d84a2012-11-19 14:39:15 +00002543 dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002544 stream ? "capture" : "playback", fe->dai_link->name);
2545
2546 /* Only start the BE if the FE is ready */
2547 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
2548 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE)
2549 return -EINVAL;
2550
2551 /* startup must always be called for new BEs */
2552 ret = dpcm_be_dai_startup(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002553 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002554 goto disconnect;
Liam Girdwood618dae12012-04-25 12:12:51 +01002555
2556 /* keep going if FE state is > open */
2557 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN)
2558 return 0;
2559
2560 ret = dpcm_be_dai_hw_params(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002561 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002562 goto close;
Liam Girdwood618dae12012-04-25 12:12:51 +01002563
2564 /* keep going if FE state is > hw_params */
2565 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS)
2566 return 0;
2567
2568
2569 ret = dpcm_be_dai_prepare(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002570 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002571 goto hw_free;
Liam Girdwood618dae12012-04-25 12:12:51 +01002572
2573 /* run the stream event for each BE */
2574 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2575
2576 /* keep going if FE state is > prepare */
2577 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE ||
2578 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP)
2579 return 0;
2580
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002581 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2582 /* call trigger on the frontend - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002583 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002584 fe->dai_link->name);
Liam Girdwood618dae12012-04-25 12:12:51 +01002585
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002586 ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
2587 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002588 dev_err(fe->dev,"ASoC: bespoke trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002589 goto hw_free;
2590 }
2591 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002592 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002593 fe->dai_link->name);
2594
2595 ret = dpcm_be_dai_trigger(fe, stream,
2596 SNDRV_PCM_TRIGGER_START);
2597 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002598 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002599 goto hw_free;
2600 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002601 }
2602
2603 return 0;
2604
2605hw_free:
2606 dpcm_be_dai_hw_free(fe, stream);
2607close:
2608 dpcm_be_dai_shutdown(fe, stream);
2609disconnect:
2610 /* disconnect any non started BEs */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002611 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002612 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood618dae12012-04-25 12:12:51 +01002613 struct snd_soc_pcm_runtime *be = dpcm->be;
2614 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2615 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2616 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002617 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood618dae12012-04-25 12:12:51 +01002618
2619 return ret;
2620}
2621
2622static int dpcm_run_new_update(struct snd_soc_pcm_runtime *fe, int stream)
2623{
2624 int ret;
2625
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002626 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood618dae12012-04-25 12:12:51 +01002627 ret = dpcm_run_update_startup(fe, stream);
2628 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002629 dev_err(fe->dev, "ASoC: failed to startup some BEs\n");
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002630 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood618dae12012-04-25 12:12:51 +01002631
2632 return ret;
2633}
2634
2635static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream)
2636{
2637 int ret;
2638
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002639 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood618dae12012-04-25 12:12:51 +01002640 ret = dpcm_run_update_shutdown(fe, stream);
2641 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002642 dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n");
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002643 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood618dae12012-04-25 12:12:51 +01002644
2645 return ret;
2646}
2647
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002648static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
2649{
2650 struct snd_soc_dapm_widget_list *list;
2651 int count, paths;
2652
2653 if (!fe->dai_link->dynamic)
2654 return 0;
2655
2656 /* only check active links */
2657 if (!fe->cpu_dai->active)
2658 return 0;
2659
2660 /* DAPM sync will call this to update DSP paths */
2661 dev_dbg(fe->dev, "ASoC: DPCM %s runtime update for FE %s\n",
2662 new ? "new" : "old", fe->dai_link->name);
2663
2664 /* skip if FE doesn't have playback capability */
Kuninori Morimoto467fece2019-07-22 10:36:16 +09002665 if (!snd_soc_dai_stream_valid(fe->cpu_dai, SNDRV_PCM_STREAM_PLAYBACK) ||
2666 !snd_soc_dai_stream_valid(fe->codec_dai, SNDRV_PCM_STREAM_PLAYBACK))
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002667 goto capture;
2668
2669 /* skip if FE isn't currently playing */
2670 if (!fe->cpu_dai->playback_active || !fe->codec_dai->playback_active)
2671 goto capture;
2672
2673 paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list);
2674 if (paths < 0) {
2675 dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
2676 fe->dai_link->name, "playback");
2677 return paths;
2678 }
2679
2680 /* update any playback paths */
2681 count = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, new);
2682 if (count) {
2683 if (new)
2684 dpcm_run_new_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
2685 else
2686 dpcm_run_old_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
2687
2688 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
2689 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
2690 }
2691
2692 dpcm_path_put(&list);
2693
2694capture:
2695 /* skip if FE doesn't have capture capability */
Kuninori Morimoto467fece2019-07-22 10:36:16 +09002696 if (!snd_soc_dai_stream_valid(fe->cpu_dai, SNDRV_PCM_STREAM_CAPTURE) ||
2697 !snd_soc_dai_stream_valid(fe->codec_dai, SNDRV_PCM_STREAM_CAPTURE))
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002698 return 0;
2699
2700 /* skip if FE isn't currently capturing */
2701 if (!fe->cpu_dai->capture_active || !fe->codec_dai->capture_active)
2702 return 0;
2703
2704 paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list);
2705 if (paths < 0) {
2706 dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
2707 fe->dai_link->name, "capture");
2708 return paths;
2709 }
2710
2711 /* update any old capture paths */
2712 count = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, new);
2713 if (count) {
2714 if (new)
2715 dpcm_run_new_update(fe, SNDRV_PCM_STREAM_CAPTURE);
2716 else
2717 dpcm_run_old_update(fe, SNDRV_PCM_STREAM_CAPTURE);
2718
2719 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
2720 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
2721 }
2722
2723 dpcm_path_put(&list);
2724
2725 return 0;
2726}
2727
Liam Girdwood618dae12012-04-25 12:12:51 +01002728/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
2729 * any DAI links.
2730 */
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002731int soc_dpcm_runtime_update(struct snd_soc_card *card)
Liam Girdwood618dae12012-04-25 12:12:51 +01002732{
Mengdong Lin1a497982015-11-18 02:34:11 -05002733 struct snd_soc_pcm_runtime *fe;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002734 int ret = 0;
Liam Girdwood618dae12012-04-25 12:12:51 +01002735
Liam Girdwood618dae12012-04-25 12:12:51 +01002736 mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002737 /* shutdown all old paths first */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002738 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002739 ret = soc_dpcm_fe_runtime_update(fe, 0);
2740 if (ret)
2741 goto out;
Liam Girdwood618dae12012-04-25 12:12:51 +01002742 }
2743
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002744 /* bring new paths up */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002745 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002746 ret = soc_dpcm_fe_runtime_update(fe, 1);
2747 if (ret)
2748 goto out;
2749 }
2750
2751out:
Liam Girdwood618dae12012-04-25 12:12:51 +01002752 mutex_unlock(&card->mutex);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002753 return ret;
Liam Girdwood618dae12012-04-25 12:12:51 +01002754}
Liam Girdwood01d75842012-04-25 12:12:49 +01002755int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute)
2756{
2757 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00002758 struct snd_soc_dai *dai;
Liam Girdwood01d75842012-04-25 12:12:49 +01002759
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002760 for_each_dpcm_be(fe, SNDRV_PCM_STREAM_PLAYBACK, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002761
2762 struct snd_soc_pcm_runtime *be = dpcm->be;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002763 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01002764
2765 if (be->dai_link->ignore_suspend)
2766 continue;
2767
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00002768 for_each_rtd_codec_dai(be, i, dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002769 struct snd_soc_dai_driver *drv = dai->driver;
Liam Girdwood01d75842012-04-25 12:12:49 +01002770
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002771 dev_dbg(be->dev, "ASoC: BE digital mute %s\n",
2772 be->dai_link->name);
2773
2774 if (drv->ops && drv->ops->digital_mute &&
2775 dai->playback_active)
2776 drv->ops->digital_mute(dai, mute);
2777 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002778 }
2779
2780 return 0;
2781}
2782
Mark Brown45c0a182012-05-09 21:46:27 +01002783static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002784{
2785 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
2786 struct snd_soc_dpcm *dpcm;
2787 struct snd_soc_dapm_widget_list *list;
2788 int ret;
2789 int stream = fe_substream->stream;
2790
2791 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2792 fe->dpcm[stream].runtime = fe_substream->runtime;
2793
Qiao Zhou8f70e512014-09-10 17:54:07 +08002794 ret = dpcm_path_get(fe, stream, &list);
2795 if (ret < 0) {
2796 mutex_unlock(&fe->card->mutex);
2797 return ret;
2798 } else if (ret == 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002799 dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002800 fe->dai_link->name, stream ? "capture" : "playback");
Liam Girdwood01d75842012-04-25 12:12:49 +01002801 }
2802
2803 /* calculate valid and active FE <-> BE dpcms */
2804 dpcm_process_paths(fe, stream, &list, 1);
2805
2806 ret = dpcm_fe_dai_startup(fe_substream);
2807 if (ret < 0) {
2808 /* clean up all links */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002809 for_each_dpcm_be(fe, stream, dpcm)
Liam Girdwood01d75842012-04-25 12:12:49 +01002810 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2811
2812 dpcm_be_disconnect(fe, stream);
2813 fe->dpcm[stream].runtime = NULL;
2814 }
2815
2816 dpcm_clear_pending_state(fe, stream);
2817 dpcm_path_put(&list);
2818 mutex_unlock(&fe->card->mutex);
2819 return ret;
2820}
2821
Mark Brown45c0a182012-05-09 21:46:27 +01002822static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002823{
2824 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
2825 struct snd_soc_dpcm *dpcm;
2826 int stream = fe_substream->stream, ret;
2827
2828 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2829 ret = dpcm_fe_dai_shutdown(fe_substream);
2830
2831 /* mark FE's links ready to prune */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002832 for_each_dpcm_be(fe, stream, dpcm)
Liam Girdwood01d75842012-04-25 12:12:49 +01002833 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2834
2835 dpcm_be_disconnect(fe, stream);
2836
2837 fe->dpcm[stream].runtime = NULL;
2838 mutex_unlock(&fe->card->mutex);
2839 return ret;
2840}
2841
Liam Girdwoodddee6272011-06-09 14:45:53 +01002842/* create a new pcm */
2843int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
2844{
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002845 struct snd_soc_dai *codec_dai;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002846 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto2b544dd2019-10-15 12:59:31 +09002847 struct snd_soc_component *component;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002848 struct snd_pcm *pcm;
2849 char new_name[64];
2850 int ret = 0, playback = 0, capture = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002851 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002852
Liam Girdwood01d75842012-04-25 12:12:49 +01002853 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
Liam Girdwood1e9de422014-01-07 17:51:42 +00002854 playback = rtd->dai_link->dpcm_playback;
2855 capture = rtd->dai_link->dpcm_capture;
Liam Girdwood01d75842012-04-25 12:12:49 +01002856 } else {
Jerome Bruneta3420312019-07-25 18:59:47 +02002857 /* Adapt stream for codec2codec links */
2858 struct snd_soc_pcm_stream *cpu_capture = rtd->dai_link->params ?
2859 &cpu_dai->driver->playback : &cpu_dai->driver->capture;
2860 struct snd_soc_pcm_stream *cpu_playback = rtd->dai_link->params ?
2861 &cpu_dai->driver->capture : &cpu_dai->driver->playback;
2862
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00002863 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto467fece2019-07-22 10:36:16 +09002864 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
2865 snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_PLAYBACK))
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002866 playback = 1;
Kuninori Morimoto467fece2019-07-22 10:36:16 +09002867 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
2868 snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_CAPTURE))
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002869 capture = 1;
2870 }
Jerome Bruneta3420312019-07-25 18:59:47 +02002871
2872 capture = capture && cpu_capture->channels_min;
2873 playback = playback && cpu_playback->channels_min;
Liam Girdwood01d75842012-04-25 12:12:49 +01002874 }
Sangsu Parka5002312012-01-02 17:15:10 +09002875
Fabio Estevamd6bead02013-08-29 10:32:13 -03002876 if (rtd->dai_link->playback_only) {
2877 playback = 1;
2878 capture = 0;
2879 }
2880
2881 if (rtd->dai_link->capture_only) {
2882 playback = 0;
2883 capture = 1;
2884 }
2885
Liam Girdwood01d75842012-04-25 12:12:49 +01002886 /* create the PCM */
Jerome Bruneta3420312019-07-25 18:59:47 +02002887 if (rtd->dai_link->params) {
2888 snprintf(new_name, sizeof(new_name), "codec2codec(%s)",
2889 rtd->dai_link->stream_name);
2890
2891 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
2892 playback, capture, &pcm);
2893 } else if (rtd->dai_link->no_pcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002894 snprintf(new_name, sizeof(new_name), "(%s)",
2895 rtd->dai_link->stream_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002896
Liam Girdwood01d75842012-04-25 12:12:49 +01002897 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
2898 playback, capture, &pcm);
2899 } else {
2900 if (rtd->dai_link->dynamic)
2901 snprintf(new_name, sizeof(new_name), "%s (*)",
2902 rtd->dai_link->stream_name);
2903 else
2904 snprintf(new_name, sizeof(new_name), "%s %s-%d",
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002905 rtd->dai_link->stream_name,
2906 (rtd->num_codecs > 1) ?
2907 "multicodec" : rtd->codec_dai->name, num);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002908
Liam Girdwood01d75842012-04-25 12:12:49 +01002909 ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
2910 capture, &pcm);
2911 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01002912 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002913 dev_err(rtd->card->dev, "ASoC: can't create pcm for %s\n",
Liam Girdwood5cb9b742012-07-06 16:54:52 +01002914 rtd->dai_link->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002915 return ret;
2916 }
Liam Girdwood103d84a2012-11-19 14:39:15 +00002917 dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002918
2919 /* DAPM dai link stream work */
Jerome Bruneta3420312019-07-25 18:59:47 +02002920 if (rtd->dai_link->params)
Curtis Malainey4bf2e382019-12-03 09:30:07 -08002921 rtd->close_delayed_work_func = codec2codec_close_delayed_work;
Jerome Bruneta3420312019-07-25 18:59:47 +02002922 else
Kuninori Morimoto83f94a22020-01-10 11:36:17 +09002923 rtd->close_delayed_work_func = snd_soc_close_delayed_work;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002924
Vinod Koul48c76992015-02-12 09:59:53 +05302925 pcm->nonatomic = rtd->dai_link->nonatomic;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002926 rtd->pcm = pcm;
2927 pcm->private_data = rtd;
Liam Girdwood01d75842012-04-25 12:12:49 +01002928
Jerome Bruneta3420312019-07-25 18:59:47 +02002929 if (rtd->dai_link->no_pcm || rtd->dai_link->params) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002930 if (playback)
2931 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
2932 if (capture)
2933 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
2934 goto out;
2935 }
2936
2937 /* ASoC PCM operations */
2938 if (rtd->dai_link->dynamic) {
2939 rtd->ops.open = dpcm_fe_dai_open;
2940 rtd->ops.hw_params = dpcm_fe_dai_hw_params;
2941 rtd->ops.prepare = dpcm_fe_dai_prepare;
2942 rtd->ops.trigger = dpcm_fe_dai_trigger;
2943 rtd->ops.hw_free = dpcm_fe_dai_hw_free;
2944 rtd->ops.close = dpcm_fe_dai_close;
2945 rtd->ops.pointer = soc_pcm_pointer;
2946 } else {
2947 rtd->ops.open = soc_pcm_open;
2948 rtd->ops.hw_params = soc_pcm_hw_params;
2949 rtd->ops.prepare = soc_pcm_prepare;
2950 rtd->ops.trigger = soc_pcm_trigger;
2951 rtd->ops.hw_free = soc_pcm_hw_free;
2952 rtd->ops.close = soc_pcm_close;
2953 rtd->ops.pointer = soc_pcm_pointer;
2954 }
2955
Kuninori Morimoto613fb502020-01-10 11:35:21 +09002956 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto2b544dd2019-10-15 12:59:31 +09002957 const struct snd_soc_component_driver *drv = component->driver;
Kuninori Morimotob8135862017-10-11 01:37:23 +00002958
Takashi Iwai3b1c9522019-11-21 20:07:08 +01002959 if (drv->ioctl)
2960 rtd->ops.ioctl = snd_soc_pcm_component_ioctl;
Takashi Iwai1e5ddb62019-11-21 20:07:09 +01002961 if (drv->sync_stop)
2962 rtd->ops.sync_stop = snd_soc_pcm_component_sync_stop;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002963 if (drv->copy_user)
Kuninori Morimoto82d81f52019-07-26 13:51:56 +09002964 rtd->ops.copy_user = snd_soc_pcm_component_copy_user;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002965 if (drv->page)
Kuninori Morimoto9c712e42019-07-26 13:52:00 +09002966 rtd->ops.page = snd_soc_pcm_component_page;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002967 if (drv->mmap)
Kuninori Morimoto205875e2019-07-26 13:52:04 +09002968 rtd->ops.mmap = snd_soc_pcm_component_mmap;
Kuninori Morimotob8135862017-10-11 01:37:23 +00002969 }
2970
Liam Girdwoodddee6272011-06-09 14:45:53 +01002971 if (playback)
Liam Girdwood01d75842012-04-25 12:12:49 +01002972 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002973
2974 if (capture)
Liam Girdwood01d75842012-04-25 12:12:49 +01002975 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002976
Kuninori Morimotob2b2afb2019-11-18 10:50:32 +09002977 ret = snd_soc_pcm_component_new(rtd);
Kuninori Morimoto74842912019-07-26 13:52:08 +09002978 if (ret < 0) {
2979 dev_err(rtd->dev, "ASoC: pcm constructor failed: %d\n", ret);
2980 return ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002981 }
Johan Hovoldc641e5b2017-07-12 17:55:29 +02002982
Takashi Iwai3d21ef02019-01-11 15:58:39 +01002983 pcm->no_device_suspend = true;
Liam Girdwood01d75842012-04-25 12:12:49 +01002984out:
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002985 dev_info(rtd->card->dev, "%s <-> %s mapping ok\n",
2986 (rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name,
2987 cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002988 return ret;
2989}
Liam Girdwood01d75842012-04-25 12:12:49 +01002990
2991/* is the current PCM operation for this FE ? */
2992int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream)
2993{
2994 if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE)
2995 return 1;
2996 return 0;
2997}
2998EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update);
2999
3000/* is the current PCM operation for this BE ? */
3001int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
3002 struct snd_soc_pcm_runtime *be, int stream)
3003{
3004 if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) ||
3005 ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) &&
3006 be->dpcm[stream].runtime_update))
3007 return 1;
3008 return 0;
3009}
3010EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update);
3011
3012/* get the substream for this BE */
3013struct snd_pcm_substream *
3014 snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream)
3015{
3016 return be->pcm->streams[stream].substream;
3017}
3018EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream);
3019
3020/* get the BE runtime state */
3021enum snd_soc_dpcm_state
3022 snd_soc_dpcm_be_get_state(struct snd_soc_pcm_runtime *be, int stream)
3023{
3024 return be->dpcm[stream].state;
3025}
3026EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_get_state);
3027
3028/* set the BE runtime state */
3029void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be,
3030 int stream, enum snd_soc_dpcm_state state)
3031{
3032 be->dpcm[stream].state = state;
3033}
3034EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_set_state);
3035
3036/*
3037 * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE
3038 * are not running, paused or suspended for the specified stream direction.
3039 */
3040int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
3041 struct snd_soc_pcm_runtime *be, int stream)
3042{
3043 struct snd_soc_dpcm *dpcm;
3044 int state;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003045 int ret = 1;
3046 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01003047
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003048 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00003049 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01003050
3051 if (dpcm->fe == fe)
3052 continue;
3053
3054 state = dpcm->fe->dpcm[stream].state;
3055 if (state == SND_SOC_DPCM_STATE_START ||
3056 state == SND_SOC_DPCM_STATE_PAUSED ||
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003057 state == SND_SOC_DPCM_STATE_SUSPEND) {
3058 ret = 0;
3059 break;
3060 }
Liam Girdwood01d75842012-04-25 12:12:49 +01003061 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003062 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01003063
3064 /* it's safe to free/stop this BE DAI */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003065 return ret;
Liam Girdwood01d75842012-04-25 12:12:49 +01003066}
3067EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop);
3068
3069/*
3070 * We can only change hw params a BE DAI if any of it's FE are not prepared,
3071 * running, paused or suspended for the specified stream direction.
3072 */
3073int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
3074 struct snd_soc_pcm_runtime *be, int stream)
3075{
3076 struct snd_soc_dpcm *dpcm;
3077 int state;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003078 int ret = 1;
3079 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01003080
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003081 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00003082 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01003083
3084 if (dpcm->fe == fe)
3085 continue;
3086
3087 state = dpcm->fe->dpcm[stream].state;
3088 if (state == SND_SOC_DPCM_STATE_START ||
3089 state == SND_SOC_DPCM_STATE_PAUSED ||
3090 state == SND_SOC_DPCM_STATE_SUSPEND ||
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003091 state == SND_SOC_DPCM_STATE_PREPARE) {
3092 ret = 0;
3093 break;
3094 }
Liam Girdwood01d75842012-04-25 12:12:49 +01003095 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003096 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01003097
3098 /* it's safe to change hw_params */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003099 return ret;
Liam Girdwood01d75842012-04-25 12:12:49 +01003100}
3101EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003102
3103#ifdef CONFIG_DEBUG_FS
Lars-Peter Clausen852801412016-11-22 11:29:14 +01003104static const char *dpcm_state_string(enum snd_soc_dpcm_state state)
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003105{
3106 switch (state) {
3107 case SND_SOC_DPCM_STATE_NEW:
3108 return "new";
3109 case SND_SOC_DPCM_STATE_OPEN:
3110 return "open";
3111 case SND_SOC_DPCM_STATE_HW_PARAMS:
3112 return "hw_params";
3113 case SND_SOC_DPCM_STATE_PREPARE:
3114 return "prepare";
3115 case SND_SOC_DPCM_STATE_START:
3116 return "start";
3117 case SND_SOC_DPCM_STATE_STOP:
3118 return "stop";
3119 case SND_SOC_DPCM_STATE_SUSPEND:
3120 return "suspend";
3121 case SND_SOC_DPCM_STATE_PAUSED:
3122 return "paused";
3123 case SND_SOC_DPCM_STATE_HW_FREE:
3124 return "hw_free";
3125 case SND_SOC_DPCM_STATE_CLOSE:
3126 return "close";
3127 }
3128
3129 return "unknown";
3130}
3131
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003132static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
3133 int stream, char *buf, size_t size)
3134{
3135 struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params;
3136 struct snd_soc_dpcm *dpcm;
3137 ssize_t offset = 0;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003138 unsigned long flags;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003139
3140 /* FE state */
3141 offset += snprintf(buf + offset, size - offset,
3142 "[%s - %s]\n", fe->dai_link->name,
3143 stream ? "Capture" : "Playback");
3144
3145 offset += snprintf(buf + offset, size - offset, "State: %s\n",
3146 dpcm_state_string(fe->dpcm[stream].state));
3147
3148 if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
3149 (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
3150 offset += snprintf(buf + offset, size - offset,
3151 "Hardware Params: "
3152 "Format = %s, Channels = %d, Rate = %d\n",
3153 snd_pcm_format_name(params_format(params)),
3154 params_channels(params),
3155 params_rate(params));
3156
3157 /* BEs state */
3158 offset += snprintf(buf + offset, size - offset, "Backends:\n");
3159
3160 if (list_empty(&fe->dpcm[stream].be_clients)) {
3161 offset += snprintf(buf + offset, size - offset,
3162 " No active DSP links\n");
3163 goto out;
3164 }
3165
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003166 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00003167 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003168 struct snd_soc_pcm_runtime *be = dpcm->be;
3169 params = &dpcm->hw_params;
3170
3171 offset += snprintf(buf + offset, size - offset,
3172 "- %s\n", be->dai_link->name);
3173
3174 offset += snprintf(buf + offset, size - offset,
3175 " State: %s\n",
3176 dpcm_state_string(be->dpcm[stream].state));
3177
3178 if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
3179 (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
3180 offset += snprintf(buf + offset, size - offset,
3181 " Hardware Params: "
3182 "Format = %s, Channels = %d, Rate = %d\n",
3183 snd_pcm_format_name(params_format(params)),
3184 params_channels(params),
3185 params_rate(params));
3186 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003187 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003188out:
3189 return offset;
3190}
3191
3192static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf,
3193 size_t count, loff_t *ppos)
3194{
3195 struct snd_soc_pcm_runtime *fe = file->private_data;
3196 ssize_t out_count = PAGE_SIZE, offset = 0, ret = 0;
3197 char *buf;
3198
3199 buf = kmalloc(out_count, GFP_KERNEL);
3200 if (!buf)
3201 return -ENOMEM;
3202
Kuninori Morimoto467fece2019-07-22 10:36:16 +09003203 if (snd_soc_dai_stream_valid(fe->cpu_dai, SNDRV_PCM_STREAM_PLAYBACK))
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003204 offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_PLAYBACK,
3205 buf + offset, out_count - offset);
3206
Kuninori Morimoto467fece2019-07-22 10:36:16 +09003207 if (snd_soc_dai_stream_valid(fe->cpu_dai, SNDRV_PCM_STREAM_CAPTURE))
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003208 offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_CAPTURE,
3209 buf + offset, out_count - offset);
3210
Liam Girdwoodf57b8482012-04-27 11:33:46 +01003211 ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003212
Liam Girdwoodf57b8482012-04-27 11:33:46 +01003213 kfree(buf);
3214 return ret;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003215}
3216
3217static const struct file_operations dpcm_state_fops = {
Liam Girdwoodf57b8482012-04-27 11:33:46 +01003218 .open = simple_open,
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003219 .read = dpcm_state_read_file,
3220 .llseek = default_llseek,
3221};
3222
Lars-Peter Clausen2e55b902015-04-09 10:52:37 +02003223void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003224{
Mark Brownb3bba9a2012-05-08 10:33:47 +01003225 if (!rtd->dai_link)
Lars-Peter Clausen2e55b902015-04-09 10:52:37 +02003226 return;
Mark Brownb3bba9a2012-05-08 10:33:47 +01003227
Kuninori Morimoto596becd2019-08-07 10:31:36 +09003228 if (!rtd->dai_link->dynamic)
3229 return;
3230
Lars-Peter Clausen6553bf062015-04-09 10:52:38 +02003231 if (!rtd->card->debugfs_card_root)
3232 return;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003233
3234 rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name,
3235 rtd->card->debugfs_card_root);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003236
Fabio Estevamf1e3f402017-07-29 11:40:55 -03003237 debugfs_create_file("state", 0444, rtd->debugfs_dpcm_root,
3238 rtd, &dpcm_state_fops);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003239}
3240#endif