blob: 7cb445bb1b541be203b012bef85da354cf84e075 [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
Kuninori Morimoto0be429f2020-01-22 09:44:40 +090040static void soc_rtd_shutdown(struct snd_soc_pcm_runtime *rtd,
41 struct snd_pcm_substream *substream)
42{
43 if (rtd->dai_link->ops &&
44 rtd->dai_link->ops->shutdown)
45 rtd->dai_link->ops->shutdown(substream);
46}
47
Kuninori Morimoto44c1a752020-01-22 09:44:44 +090048static int soc_rtd_prepare(struct snd_soc_pcm_runtime *rtd,
49 struct snd_pcm_substream *substream)
50{
51 if (rtd->dai_link->ops &&
52 rtd->dai_link->ops->prepare)
53 return rtd->dai_link->ops->prepare(substream);
54 return 0;
55}
56
Kuninori Morimotode9ad992020-01-22 09:44:48 +090057static int soc_rtd_hw_params(struct snd_soc_pcm_runtime *rtd,
58 struct snd_pcm_substream *substream,
59 struct snd_pcm_hw_params *params)
60{
61 if (rtd->dai_link->ops &&
62 rtd->dai_link->ops->hw_params)
63 return rtd->dai_link->ops->hw_params(substream, params);
64 return 0;
65}
66
Kuninori Morimoto49f020e2020-01-22 09:44:52 +090067static void soc_rtd_hw_free(struct snd_soc_pcm_runtime *rtd,
68 struct snd_pcm_substream *substream)
69{
70 if (rtd->dai_link->ops &&
71 rtd->dai_link->ops->hw_free)
72 rtd->dai_link->ops->hw_free(substream);
73}
74
Kuninori Morimotoad2bf9f2020-01-22 09:44:56 +090075static int soc_rtd_trigger(struct snd_soc_pcm_runtime *rtd,
76 struct snd_pcm_substream *substream,
77 int cmd)
78{
79 if (rtd->dai_link->ops &&
80 rtd->dai_link->ops->trigger)
81 return rtd->dai_link->ops->trigger(substream, cmd);
82 return 0;
83}
84
Kuninori Morimotod9303692020-02-17 17:27:39 +090085static inline
86struct snd_soc_dapm_widget *dai_get_widget(struct snd_soc_dai *dai, int stream)
87{
88 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
89 return dai->playback_widget;
90 else
91 return dai->capture_widget;
92}
93
Kuninori Morimoto7a5aaba2020-02-10 12:14:12 +090094static void snd_soc_runtime_action(struct snd_soc_pcm_runtime *rtd,
95 int stream, int action)
96{
97 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
98 struct snd_soc_dai *codec_dai;
99 int i;
100
101 lockdep_assert_held(&rtd->card->pcm_mutex);
102
Kuninori Morimoto0f6011f2020-02-17 17:28:15 +0900103 cpu_dai->stream_active[stream] += action;
104 for_each_rtd_codec_dai(rtd, i, codec_dai)
105 codec_dai->stream_active[stream] += action;
Kuninori Morimoto7a5aaba2020-02-10 12:14:12 +0900106
107 cpu_dai->active += action;
108 cpu_dai->component->active += action;
109 for_each_rtd_codec_dai(rtd, i, codec_dai) {
110 codec_dai->active += action;
111 codec_dai->component->active += action;
112 }
113}
114
Lars-Peter Clausen90996f42013-05-14 11:05:30 +0200115/**
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100116 * snd_soc_runtime_activate() - Increment active count for PCM runtime components
117 * @rtd: ASoC PCM runtime that is activated
118 * @stream: Direction of the PCM stream
119 *
120 * Increments the active count for all the DAIs and components attached to a PCM
121 * runtime. Should typically be called when a stream is opened.
122 *
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300123 * Must be called with the rtd->card->pcm_mutex being held
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100124 */
125void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream)
126{
Kuninori Morimoto7a5aaba2020-02-10 12:14:12 +0900127 snd_soc_runtime_action(rtd, stream, 1);
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100128}
129
130/**
131 * snd_soc_runtime_deactivate() - Decrement active count for PCM runtime components
132 * @rtd: ASoC PCM runtime that is deactivated
133 * @stream: Direction of the PCM stream
134 *
135 * Decrements the active count for all the DAIs and components attached to a PCM
136 * runtime. Should typically be called when a stream is closed.
137 *
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300138 * Must be called with the rtd->card->pcm_mutex being held
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100139 */
140void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream)
141{
Kuninori Morimoto7a5aaba2020-02-10 12:14:12 +0900142 snd_soc_runtime_action(rtd, stream, -1);
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100143}
144
145/**
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100146 * snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay
147 * @rtd: The ASoC PCM runtime that should be checked.
148 *
149 * This function checks whether the power down delay should be ignored for a
150 * specific PCM runtime. Returns true if the delay is 0, if it the DAI link has
151 * been configured to ignore the delay, or if none of the components benefits
152 * from having the delay.
153 */
154bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
155{
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000156 struct snd_soc_component *component;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200157 bool ignore = true;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900158 int i;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200159
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100160 if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
161 return true;
162
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900163 for_each_rtd_components(rtd, i, component)
Kuninori Morimoto72c38182018-01-19 05:21:19 +0000164 ignore &= !component->driver->use_pmdown_time;
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000165
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000166 return ignore;
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100167}
168
169/**
Lars-Peter Clausen90996f42013-05-14 11:05:30 +0200170 * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
171 * @substream: the pcm substream
172 * @hw: the hardware parameters
173 *
174 * Sets the substream runtime hardware parameters.
175 */
176int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
177 const struct snd_pcm_hardware *hw)
178{
179 struct snd_pcm_runtime *runtime = substream->runtime;
180 runtime->hw.info = hw->info;
181 runtime->hw.formats = hw->formats;
182 runtime->hw.period_bytes_min = hw->period_bytes_min;
183 runtime->hw.period_bytes_max = hw->period_bytes_max;
184 runtime->hw.periods_min = hw->periods_min;
185 runtime->hw.periods_max = hw->periods_max;
186 runtime->hw.buffer_bytes_max = hw->buffer_bytes_max;
187 runtime->hw.fifo_size = hw->fifo_size;
188 return 0;
189}
190EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
191
Liam Girdwood01d75842012-04-25 12:12:49 +0100192/* DPCM stream event, send event to FE and all active BEs. */
Liam Girdwood23607022014-01-17 17:03:55 +0000193int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
Liam Girdwood01d75842012-04-25 12:12:49 +0100194 int event)
195{
196 struct snd_soc_dpcm *dpcm;
197
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +0000198 for_each_dpcm_be(fe, dir, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +0100199
200 struct snd_soc_pcm_runtime *be = dpcm->be;
201
Liam Girdwood103d84a2012-11-19 14:39:15 +0000202 dev_dbg(be->dev, "ASoC: BE %s event %d dir %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +0100203 be->dai_link->name, event, dir);
204
Banajit Goswamib1cd2e32017-07-14 23:15:05 -0700205 if ((event == SND_SOC_DAPM_STREAM_STOP) &&
206 (be->dpcm[dir].users >= 1))
207 continue;
208
Liam Girdwood01d75842012-04-25 12:12:49 +0100209 snd_soc_dapm_stream_event(be, dir, event);
210 }
211
212 snd_soc_dapm_stream_event(fe, dir, event);
213
214 return 0;
215}
216
Dong Aisheng17841022011-08-29 17:15:14 +0800217static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
218 struct snd_soc_dai *soc_dai)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100219{
220 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100221 int ret;
222
Nicolin Chen3635bf02013-11-13 18:56:24 +0800223 if (soc_dai->rate && (soc_dai->driver->symmetric_rates ||
224 rtd->dai_link->symmetric_rates)) {
225 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n",
226 soc_dai->rate);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100227
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200228 ret = snd_pcm_hw_constraint_single(substream->runtime,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800229 SNDRV_PCM_HW_PARAM_RATE,
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200230 soc_dai->rate);
Nicolin Chen3635bf02013-11-13 18:56:24 +0800231 if (ret < 0) {
232 dev_err(soc_dai->dev,
233 "ASoC: Unable to apply rate constraint: %d\n",
234 ret);
235 return ret;
236 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100237 }
238
Nicolin Chen3635bf02013-11-13 18:56:24 +0800239 if (soc_dai->channels && (soc_dai->driver->symmetric_channels ||
240 rtd->dai_link->symmetric_channels)) {
241 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d channel(s)\n",
242 soc_dai->channels);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100243
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200244 ret = snd_pcm_hw_constraint_single(substream->runtime,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800245 SNDRV_PCM_HW_PARAM_CHANNELS,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800246 soc_dai->channels);
247 if (ret < 0) {
248 dev_err(soc_dai->dev,
249 "ASoC: Unable to apply channel symmetry constraint: %d\n",
250 ret);
251 return ret;
252 }
253 }
254
255 if (soc_dai->sample_bits && (soc_dai->driver->symmetric_samplebits ||
256 rtd->dai_link->symmetric_samplebits)) {
257 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d sample bits\n",
258 soc_dai->sample_bits);
259
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200260 ret = snd_pcm_hw_constraint_single(substream->runtime,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800261 SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800262 soc_dai->sample_bits);
263 if (ret < 0) {
264 dev_err(soc_dai->dev,
265 "ASoC: Unable to apply sample bits symmetry constraint: %d\n",
266 ret);
267 return ret;
268 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100269 }
270
271 return 0;
272}
273
Nicolin Chen3635bf02013-11-13 18:56:24 +0800274static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
275 struct snd_pcm_hw_params *params)
276{
277 struct snd_soc_pcm_runtime *rtd = substream->private_data;
278 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000279 struct snd_soc_dai *codec_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200280 unsigned int rate, channels, sample_bits, symmetry, i;
Nicolin Chen3635bf02013-11-13 18:56:24 +0800281
282 rate = params_rate(params);
283 channels = params_channels(params);
284 sample_bits = snd_pcm_format_physical_width(params_format(params));
285
286 /* reject unmatched parameters when applying symmetry */
287 symmetry = cpu_dai->driver->symmetric_rates ||
Nicolin Chen3635bf02013-11-13 18:56:24 +0800288 rtd->dai_link->symmetric_rates;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200289
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000290 for_each_rtd_codec_dai(rtd, i, codec_dai)
291 symmetry |= codec_dai->driver->symmetric_rates;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200292
Nicolin Chen3635bf02013-11-13 18:56:24 +0800293 if (symmetry && cpu_dai->rate && cpu_dai->rate != rate) {
294 dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n",
295 cpu_dai->rate, rate);
296 return -EINVAL;
297 }
298
299 symmetry = cpu_dai->driver->symmetric_channels ||
Nicolin Chen3635bf02013-11-13 18:56:24 +0800300 rtd->dai_link->symmetric_channels;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200301
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000302 for_each_rtd_codec_dai(rtd, i, codec_dai)
303 symmetry |= codec_dai->driver->symmetric_channels;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200304
Nicolin Chen3635bf02013-11-13 18:56:24 +0800305 if (symmetry && cpu_dai->channels && cpu_dai->channels != channels) {
306 dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n",
307 cpu_dai->channels, channels);
308 return -EINVAL;
309 }
310
311 symmetry = cpu_dai->driver->symmetric_samplebits ||
Nicolin Chen3635bf02013-11-13 18:56:24 +0800312 rtd->dai_link->symmetric_samplebits;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200313
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000314 for_each_rtd_codec_dai(rtd, i, codec_dai)
315 symmetry |= codec_dai->driver->symmetric_samplebits;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200316
Nicolin Chen3635bf02013-11-13 18:56:24 +0800317 if (symmetry && cpu_dai->sample_bits && cpu_dai->sample_bits != sample_bits) {
318 dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n",
319 cpu_dai->sample_bits, sample_bits);
320 return -EINVAL;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100321 }
322
323 return 0;
324}
325
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100326static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream)
327{
328 struct snd_soc_pcm_runtime *rtd = substream->private_data;
329 struct snd_soc_dai_driver *cpu_driver = rtd->cpu_dai->driver;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100330 struct snd_soc_dai_link *link = rtd->dai_link;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000331 struct snd_soc_dai *codec_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200332 unsigned int symmetry, i;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100333
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200334 symmetry = cpu_driver->symmetric_rates || link->symmetric_rates ||
335 cpu_driver->symmetric_channels || link->symmetric_channels ||
336 cpu_driver->symmetric_samplebits || link->symmetric_samplebits;
337
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000338 for_each_rtd_codec_dai(rtd, i, codec_dai)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200339 symmetry = symmetry ||
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000340 codec_dai->driver->symmetric_rates ||
341 codec_dai->driver->symmetric_channels ||
342 codec_dai->driver->symmetric_samplebits;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200343
344 return symmetry;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100345}
346
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200347static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits)
Mark Brown58ba9b22012-01-16 18:38:51 +0000348{
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200349 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Takashi Iwaic6068d32014-12-31 17:10:34 +0100350 int ret;
Mark Brown58ba9b22012-01-16 18:38:51 +0000351
352 if (!bits)
353 return;
354
Lars-Peter Clausen0e2a3752014-12-29 18:43:38 +0100355 ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 0, bits);
356 if (ret != 0)
357 dev_warn(rtd->dev, "ASoC: Failed to set MSB %d: %d\n",
358 bits, ret);
Mark Brown58ba9b22012-01-16 18:38:51 +0000359}
360
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200361static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200362{
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200363 struct snd_soc_pcm_runtime *rtd = substream->private_data;
364 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200365 struct snd_soc_dai *codec_dai;
366 int i;
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200367 unsigned int bits = 0, cpu_bits;
368
369 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000370 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200371 if (codec_dai->driver->playback.sig_bits == 0) {
372 bits = 0;
373 break;
374 }
375 bits = max(codec_dai->driver->playback.sig_bits, bits);
376 }
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200377 cpu_bits = cpu_dai->driver->playback.sig_bits;
378 } else {
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000379 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Daniel Mack5e63dfc2014-10-07 14:33:46 +0200380 if (codec_dai->driver->capture.sig_bits == 0) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200381 bits = 0;
382 break;
383 }
384 bits = max(codec_dai->driver->capture.sig_bits, bits);
385 }
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200386 cpu_bits = cpu_dai->driver->capture.sig_bits;
387 }
388
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200389 soc_pcm_set_msb(substream, bits);
390 soc_pcm_set_msb(substream, cpu_bits);
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200391}
392
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200393static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200394{
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200395 struct snd_pcm_runtime *runtime = substream->runtime;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100396 struct snd_pcm_hardware *hw = &runtime->hw;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200397 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000398 struct snd_soc_dai *codec_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200399 struct snd_soc_pcm_stream *codec_stream;
400 struct snd_soc_pcm_stream *cpu_stream;
401 unsigned int chan_min = 0, chan_max = UINT_MAX;
402 unsigned int rate_min = 0, rate_max = UINT_MAX;
403 unsigned int rates = UINT_MAX;
404 u64 formats = ULLONG_MAX;
Kuninori Morimotoacf253c2020-02-19 15:56:30 +0900405 int stream = substream->stream;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200406 int i;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100407
Kuninori Morimotoacf253c2020-02-19 15:56:30 +0900408 cpu_stream = snd_soc_dai_get_pcm_stream(rtd->cpu_dai, stream);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100409
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200410 /* first calculate min/max only for CODECs in the DAI link */
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000411 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200412
413 /*
414 * Skip CODECs which don't support the current stream type.
415 * Otherwise, since the rate, channel, and format values will
416 * zero in that case, we would have no usable settings left,
417 * causing the resulting setup to fail.
418 * At least one CODEC should match, otherwise we should have
419 * bailed out on a higher level, since there would be no
420 * CODEC to support the transfer direction in that case.
421 */
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000422 if (!snd_soc_dai_stream_valid(codec_dai,
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200423 substream->stream))
424 continue;
425
Kuninori Morimotoacf253c2020-02-19 15:56:30 +0900426 codec_stream = snd_soc_dai_get_pcm_stream(codec_dai, stream);
427
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200428 chan_min = max(chan_min, codec_stream->channels_min);
429 chan_max = min(chan_max, codec_stream->channels_max);
430 rate_min = max(rate_min, codec_stream->rate_min);
431 rate_max = min_not_zero(rate_max, codec_stream->rate_max);
432 formats &= codec_stream->formats;
433 rates = snd_pcm_rate_mask_intersect(codec_stream->rates, rates);
434 }
435
436 /*
437 * chan min/max cannot be enforced if there are multiple CODEC DAIs
438 * connected to a single CPU DAI, use CPU DAI's directly and let
439 * channel allocation be fixed up later
440 */
441 if (rtd->num_codecs > 1) {
442 chan_min = cpu_stream->channels_min;
443 chan_max = cpu_stream->channels_max;
444 }
445
446 hw->channels_min = max(chan_min, cpu_stream->channels_min);
447 hw->channels_max = min(chan_max, cpu_stream->channels_max);
448 if (hw->formats)
449 hw->formats &= formats & cpu_stream->formats;
450 else
451 hw->formats = formats & cpu_stream->formats;
452 hw->rates = snd_pcm_rate_mask_intersect(rates, cpu_stream->rates);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100453
454 snd_pcm_limit_hw_rates(runtime);
455
456 hw->rate_min = max(hw->rate_min, cpu_stream->rate_min);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200457 hw->rate_min = max(hw->rate_min, rate_min);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100458 hw->rate_max = min_not_zero(hw->rate_max, cpu_stream->rate_max);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200459 hw->rate_max = min_not_zero(hw->rate_max, rate_max);
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200460}
461
Kuninori Morimotodd039072020-02-10 12:14:37 +0900462static int soc_pcm_components_open(struct snd_pcm_substream *substream)
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900463{
464 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900465 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900466 int i, ret = 0;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900467
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900468 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto4a81e8f2019-07-26 13:49:54 +0900469 ret = snd_soc_component_module_get_when_open(component);
470 if (ret < 0) {
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900471 dev_err(component->dev,
472 "ASoC: can't get module %s\n",
473 component->name);
Kuninori Morimoto4a81e8f2019-07-26 13:49:54 +0900474 return ret;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900475 }
476
Kuninori Morimotoae2f4842019-07-26 13:50:01 +0900477 ret = snd_soc_component_open(component, substream);
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900478 if (ret < 0) {
479 dev_err(component->dev,
480 "ASoC: can't open component %s: %d\n",
481 component->name, ret);
482 return ret;
483 }
484 }
Kuninori Morimotodd039072020-02-10 12:14:37 +0900485
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900486 return 0;
487}
488
Kuninori Morimotodd039072020-02-10 12:14:37 +0900489static int soc_pcm_components_close(struct snd_pcm_substream *substream)
Charles Keepax244e2932018-06-19 16:22:09 +0100490{
491 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Charles Keepax244e2932018-06-19 16:22:09 +0100492 struct snd_soc_component *component;
Kuninori Morimotoe82ebff2020-02-10 12:14:26 +0900493 int i, r, ret = 0;
Charles Keepax244e2932018-06-19 16:22:09 +0100494
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900495 for_each_rtd_components(rtd, i, component) {
Kuninori Morimotoe82ebff2020-02-10 12:14:26 +0900496 r = snd_soc_component_close(component, substream);
497 if (r < 0)
498 ret = r; /* use last ret */
499
Kuninori Morimoto4a81e8f2019-07-26 13:49:54 +0900500 snd_soc_component_module_put_when_close(component);
Charles Keepax244e2932018-06-19 16:22:09 +0100501 }
502
Kuninori Morimoto3672beb2019-07-26 13:50:07 +0900503 return ret;
Charles Keepax244e2932018-06-19 16:22:09 +0100504}
505
Mark Brown58ba9b22012-01-16 18:38:51 +0000506/*
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900507 * Called by ALSA when a PCM substream is closed. Private data can be
508 * freed here. The cpu DAI, codec DAI, machine and components are also
509 * shutdown.
510 */
511static int soc_pcm_close(struct snd_pcm_substream *substream)
512{
513 struct snd_soc_pcm_runtime *rtd = substream->private_data;
514 struct snd_soc_component *component;
515 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
516 struct snd_soc_dai *codec_dai;
517 int i;
518
519 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
520
521 snd_soc_runtime_deactivate(rtd, substream->stream);
522
523 snd_soc_dai_digital_mute(cpu_dai, 1, substream->stream);
524
525 snd_soc_dai_shutdown(cpu_dai, substream);
526
527 for_each_rtd_codec_dai(rtd, i, codec_dai)
528 snd_soc_dai_shutdown(codec_dai, substream);
529
530 soc_rtd_shutdown(rtd, substream);
531
532 soc_pcm_components_close(substream);
533
534 snd_soc_dapm_stream_stop(rtd, substream->stream);
535
536 mutex_unlock(&rtd->card->pcm_mutex);
537
538 for_each_rtd_components(rtd, i, component) {
539 pm_runtime_mark_last_busy(component->dev);
540 pm_runtime_put_autosuspend(component->dev);
541 }
542
543 for_each_rtd_components(rtd, i, component)
544 if (!component->active)
545 pinctrl_pm_select_sleep_state(component->dev);
546
547 return 0;
548}
549
550/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100551 * Called by ALSA when a PCM substream is opened, the runtime->hw record is
552 * then initialized and any private data can be allocated. This also calls
Charles Keepaxef050be2018-04-24 16:39:02 +0100553 * startup for the cpu DAI, component, machine and codec DAI.
Liam Girdwoodddee6272011-06-09 14:45:53 +0100554 */
555static int soc_pcm_open(struct snd_pcm_substream *substream)
556{
557 struct snd_soc_pcm_runtime *rtd = substream->private_data;
558 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000559 struct snd_soc_component *component;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100560 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200561 struct snd_soc_dai *codec_dai;
562 const char *codec_dai_name = "multicodec";
Charles Keepax244e2932018-06-19 16:22:09 +0100563 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100564
Kuninori Morimoto76c39e82020-01-10 11:36:13 +0900565 for_each_rtd_components(rtd, i, component)
566 pinctrl_pm_select_default_state(component->dev);
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000567
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900568 for_each_rtd_components(rtd, i, component)
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000569 pm_runtime_get_sync(component->dev);
Mark Brownd6652ef2011-12-03 20:14:31 +0000570
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300571 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100572
Kuninori Morimoto5d9fa032020-02-10 12:14:45 +0900573 ret = soc_pcm_components_open(substream);
574 if (ret < 0)
575 goto component_err;
576
577 ret = soc_rtd_startup(rtd, substream);
578 if (ret < 0) {
579 pr_err("ASoC: %s startup failed: %d\n",
580 rtd->dai_link->name, ret);
581 goto component_err;
582 }
583
Liam Girdwoodddee6272011-06-09 14:45:53 +0100584 /* startup the audio subsystem */
Kuninori Morimoto5a52a042019-07-22 10:33:32 +0900585 ret = snd_soc_dai_startup(cpu_dai, substream);
586 if (ret < 0) {
587 dev_err(cpu_dai->dev, "ASoC: can't open interface %s: %d\n",
588 cpu_dai->name, ret);
Kuninori Morimoto5d9fa032020-02-10 12:14:45 +0900589 goto cpu_dai_err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100590 }
591
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000592 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto5a52a042019-07-22 10:33:32 +0900593 ret = snd_soc_dai_startup(codec_dai, substream);
594 if (ret < 0) {
595 dev_err(codec_dai->dev,
596 "ASoC: can't open codec %s: %d\n",
597 codec_dai->name, ret);
Kuninori Morimoto5d9fa032020-02-10 12:14:45 +0900598 goto config_err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100599 }
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200600
601 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
602 codec_dai->tx_mask = 0;
603 else
604 codec_dai->rx_mask = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100605 }
606
Liam Girdwood01d75842012-04-25 12:12:49 +0100607 /* Dynamic PCM DAI links compat checks use dynamic capabilities */
608 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm)
609 goto dynamic;
610
Liam Girdwoodddee6272011-06-09 14:45:53 +0100611 /* Check that the codec and cpu DAIs are compatible */
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200612 soc_pcm_init_runtime_hw(substream);
613
614 if (rtd->num_codecs == 1)
615 codec_dai_name = rtd->codec_dai->name;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100616
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100617 if (soc_pcm_has_symmetry(substream))
618 runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
619
Liam Girdwoodddee6272011-06-09 14:45:53 +0100620 ret = -EINVAL;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100621 if (!runtime->hw.rates) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000622 printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200623 codec_dai_name, cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100624 goto config_err;
625 }
626 if (!runtime->hw.formats) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000627 printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200628 codec_dai_name, cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100629 goto config_err;
630 }
631 if (!runtime->hw.channels_min || !runtime->hw.channels_max ||
632 runtime->hw.channels_min > runtime->hw.channels_max) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000633 printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200634 codec_dai_name, cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100635 goto config_err;
636 }
637
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200638 soc_pcm_apply_msb(substream);
Mark Brown58ba9b22012-01-16 18:38:51 +0000639
Liam Girdwoodddee6272011-06-09 14:45:53 +0100640 /* Symmetry only applies if we've already got an active stream. */
Dong Aisheng17841022011-08-29 17:15:14 +0800641 if (cpu_dai->active) {
642 ret = soc_pcm_apply_symmetry(substream, cpu_dai);
643 if (ret != 0)
644 goto config_err;
645 }
646
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000647 for_each_rtd_codec_dai(rtd, i, codec_dai) {
648 if (codec_dai->active) {
649 ret = soc_pcm_apply_symmetry(substream, codec_dai);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200650 if (ret != 0)
651 goto config_err;
652 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100653 }
654
Liam Girdwood103d84a2012-11-19 14:39:15 +0000655 pr_debug("ASoC: %s <-> %s info:\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200656 codec_dai_name, cpu_dai->name);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000657 pr_debug("ASoC: rate mask 0x%x\n", runtime->hw.rates);
658 pr_debug("ASoC: min ch %d max ch %d\n", runtime->hw.channels_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100659 runtime->hw.channels_max);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000660 pr_debug("ASoC: min rate %d max rate %d\n", runtime->hw.rate_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100661 runtime->hw.rate_max);
662
Liam Girdwood01d75842012-04-25 12:12:49 +0100663dynamic:
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100664
665 snd_soc_runtime_activate(rtd, substream->stream);
666
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300667 mutex_unlock(&rtd->card->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100668 return 0;
669
670config_err:
Kuninori Morimotob56be802020-02-10 12:14:33 +0900671 for_each_rtd_codec_dai(rtd, i, codec_dai)
Kuninori Morimoto330fcb52019-07-22 10:33:39 +0900672 snd_soc_dai_shutdown(codec_dai, substream);
Kuninori Morimoto5d9fa032020-02-10 12:14:45 +0900673cpu_dai_err:
674 snd_soc_dai_shutdown(cpu_dai, substream);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200675
Kuninori Morimoto5d9fa032020-02-10 12:14:45 +0900676 soc_rtd_shutdown(rtd, substream);
Kuninori Morimotob8135862017-10-11 01:37:23 +0000677component_err:
Kuninori Morimotodd039072020-02-10 12:14:37 +0900678 soc_pcm_components_close(substream);
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900679
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300680 mutex_unlock(&rtd->card->pcm_mutex);
Mark Brownd6652ef2011-12-03 20:14:31 +0000681
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900682 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000683 pm_runtime_mark_last_busy(component->dev);
684 pm_runtime_put_autosuspend(component->dev);
Sanyog Kale3f809782016-01-05 17:14:49 +0530685 }
686
Kuninori Morimoto76c39e82020-01-10 11:36:13 +0900687 for_each_rtd_components(rtd, i, component)
688 if (!component->active)
689 pinctrl_pm_select_sleep_state(component->dev);
Mark Brownd6652ef2011-12-03 20:14:31 +0000690
Liam Girdwoodddee6272011-06-09 14:45:53 +0100691 return ret;
692}
693
Curtis Malainey4bf2e382019-12-03 09:30:07 -0800694static void codec2codec_close_delayed_work(struct snd_soc_pcm_runtime *rtd)
Jerome Bruneta3420312019-07-25 18:59:47 +0200695{
696 /*
697 * Currently nothing to do for c2c links
698 * Since c2c links are internal nodes in the DAPM graph and
699 * don't interface with the outside world or application layer
700 * we don't have to do any special handling on close.
701 */
702}
703
Liam Girdwoodddee6272011-06-09 14:45:53 +0100704/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100705 * Called by ALSA when the PCM substream is prepared, can set format, sample
706 * rate, etc. This function is non atomic and can be called multiple times,
707 * it can refer to the runtime info.
708 */
709static int soc_pcm_prepare(struct snd_pcm_substream *substream)
710{
711 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000712 struct snd_soc_component *component;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100713 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200714 struct snd_soc_dai *codec_dai;
715 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100716
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300717 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100718
Kuninori Morimoto44c1a752020-01-22 09:44:44 +0900719 ret = soc_rtd_prepare(rtd, substream);
720 if (ret < 0) {
721 dev_err(rtd->card->dev,
722 "ASoC: machine prepare error: %d\n", ret);
723 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100724 }
725
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900726 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto6d537232019-07-26 13:50:13 +0900727 ret = snd_soc_component_prepare(component, substream);
Kuninori Morimotob8135862017-10-11 01:37:23 +0000728 if (ret < 0) {
729 dev_err(component->dev,
730 "ASoC: platform prepare error: %d\n", ret);
731 goto out;
732 }
733 }
734
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000735 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto4beb8e12019-07-22 10:33:45 +0900736 ret = snd_soc_dai_prepare(codec_dai, substream);
737 if (ret < 0) {
738 dev_err(codec_dai->dev,
739 "ASoC: codec DAI prepare error: %d\n",
740 ret);
741 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100742 }
743 }
744
Kuninori Morimoto4beb8e12019-07-22 10:33:45 +0900745 ret = snd_soc_dai_prepare(cpu_dai, substream);
746 if (ret < 0) {
747 dev_err(cpu_dai->dev,
748 "ASoC: cpu DAI prepare error: %d\n", ret);
749 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100750 }
751
752 /* cancel any delayed stream shutdown that is pending */
753 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600754 rtd->pop_wait) {
755 rtd->pop_wait = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100756 cancel_delayed_work(&rtd->delayed_work);
757 }
758
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000759 snd_soc_dapm_stream_event(rtd, substream->stream,
760 SND_SOC_DAPM_STREAM_START);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100761
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000762 for_each_rtd_codec_dai(rtd, i, codec_dai)
763 snd_soc_dai_digital_mute(codec_dai, 0,
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200764 substream->stream);
Ramesh Babuae116012014-10-15 12:34:59 +0530765 snd_soc_dai_digital_mute(cpu_dai, 0, substream->stream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100766
767out:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300768 mutex_unlock(&rtd->card->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100769 return ret;
770}
771
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200772static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params,
773 unsigned int mask)
774{
775 struct snd_interval *interval;
776 int channels = hweight_long(mask);
777
778 interval = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
779 interval->min = channels;
780 interval->max = channels;
781}
782
Charles Keepax244e2932018-06-19 16:22:09 +0100783static int soc_pcm_components_hw_free(struct snd_pcm_substream *substream,
784 struct snd_soc_component *last)
785{
786 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Charles Keepax244e2932018-06-19 16:22:09 +0100787 struct snd_soc_component *component;
Kuninori Morimotoe82ebff2020-02-10 12:14:26 +0900788 int i, r, ret = 0;
Charles Keepax244e2932018-06-19 16:22:09 +0100789
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900790 for_each_rtd_components(rtd, i, component) {
Charles Keepax244e2932018-06-19 16:22:09 +0100791 if (component == last)
792 break;
793
Kuninori Morimotoe82ebff2020-02-10 12:14:26 +0900794 r = snd_soc_component_hw_free(component, substream);
795 if (r < 0)
796 ret = r; /* use last ret */
Charles Keepax244e2932018-06-19 16:22:09 +0100797 }
798
Kuninori Morimotoeae71362019-07-26 13:50:24 +0900799 return ret;
Charles Keepax244e2932018-06-19 16:22:09 +0100800}
801
Liam Girdwoodddee6272011-06-09 14:45:53 +0100802/*
803 * Called by ALSA when the hardware params are set by application. This
804 * function can also be called multiple times and can allocate buffers
805 * (using snd_pcm_lib_* ). It's non-atomic.
806 */
807static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
808 struct snd_pcm_hw_params *params)
809{
810 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000811 struct snd_soc_component *component;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100812 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000813 struct snd_soc_dai *codec_dai;
Charles Keepax244e2932018-06-19 16:22:09 +0100814 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100815
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300816 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Shengjiu Wang5cca5952019-11-12 18:46:42 +0800817
818 ret = soc_pcm_params_symmetry(substream, params);
819 if (ret)
820 goto out;
821
Kuninori Morimotode9ad992020-01-22 09:44:48 +0900822 ret = soc_rtd_hw_params(rtd, substream, params);
823 if (ret < 0) {
824 dev_err(rtd->card->dev,
825 "ASoC: machine hw_params failed: %d\n", ret);
826 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100827 }
828
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000829 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200830 struct snd_pcm_hw_params codec_params;
831
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200832 /*
833 * Skip CODECs which don't support the current stream type,
834 * the idea being that if a CODEC is not used for the currently
835 * set up transfer direction, it should not need to be
836 * configured, especially since the configuration used might
837 * not even be supported by that CODEC. There may be cases
838 * however where a CODEC needs to be set up although it is
839 * actually not being used for the transfer, e.g. if a
840 * capture-only CODEC is acting as an LRCLK and/or BCLK master
841 * for the DAI link including a playback-only CODEC.
842 * If this becomes necessary, we will have to augment the
843 * machine driver setup with information on how to act, so
844 * we can do the right thing here.
845 */
846 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
847 continue;
848
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200849 /* copy params for each codec */
850 codec_params = *params;
851
852 /* fixup params based on TDM slot masks */
Rander Wang570f18b2019-03-08 16:38:57 +0800853 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
854 codec_dai->tx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200855 soc_pcm_codec_params_fixup(&codec_params,
856 codec_dai->tx_mask);
Rander Wang570f18b2019-03-08 16:38:57 +0800857
858 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
859 codec_dai->rx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200860 soc_pcm_codec_params_fixup(&codec_params,
861 codec_dai->rx_mask);
862
Kuninori Morimotoaa6166c2019-07-22 10:33:04 +0900863 ret = snd_soc_dai_hw_params(codec_dai, substream,
864 &codec_params);
Benoit Cousson93e69582014-07-08 23:19:38 +0200865 if(ret < 0)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100866 goto codec_err;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200867
868 codec_dai->rate = params_rate(&codec_params);
869 codec_dai->channels = params_channels(&codec_params);
870 codec_dai->sample_bits = snd_pcm_format_physical_width(
871 params_format(&codec_params));
Charles Keepax078a85f2019-01-31 13:30:18 +0000872
873 snd_soc_dapm_update_dai(substream, &codec_params, codec_dai);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100874 }
875
Kuninori Morimotoaa6166c2019-07-22 10:33:04 +0900876 ret = snd_soc_dai_hw_params(cpu_dai, substream, params);
Benoit Cousson93e69582014-07-08 23:19:38 +0200877 if (ret < 0)
878 goto interface_err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100879
Kuninori Morimotoca58221d2019-05-13 16:07:43 +0900880 /* store the parameters for each DAIs */
881 cpu_dai->rate = params_rate(params);
882 cpu_dai->channels = params_channels(params);
883 cpu_dai->sample_bits =
884 snd_pcm_format_physical_width(params_format(params));
885
886 snd_soc_dapm_update_dai(substream, params, cpu_dai);
887
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900888 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto245c5392019-07-26 13:50:19 +0900889 ret = snd_soc_component_hw_params(component, substream, params);
Charles Keepax244e2932018-06-19 16:22:09 +0100890 if (ret < 0) {
Kuninori Morimotob8135862017-10-11 01:37:23 +0000891 dev_err(component->dev,
892 "ASoC: %s hw params failed: %d\n",
Charles Keepax244e2932018-06-19 16:22:09 +0100893 component->name, ret);
894 goto component_err;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000895 }
896 }
Charles Keepax244e2932018-06-19 16:22:09 +0100897 component = NULL;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000898
Liam Girdwoodddee6272011-06-09 14:45:53 +0100899out:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300900 mutex_unlock(&rtd->card->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100901 return ret;
902
Kuninori Morimotob8135862017-10-11 01:37:23 +0000903component_err:
Charles Keepax244e2932018-06-19 16:22:09 +0100904 soc_pcm_components_hw_free(substream, component);
Kuninori Morimotob8135862017-10-11 01:37:23 +0000905
Kuninori Morimoto846faae2019-07-22 10:33:19 +0900906 snd_soc_dai_hw_free(cpu_dai, substream);
Kuninori Morimoto2371abd2019-05-13 16:07:52 +0900907 cpu_dai->rate = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100908
909interface_err:
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200910 i = rtd->num_codecs;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100911
912codec_err:
Kuninori Morimoto6d11b122018-09-18 01:28:30 +0000913 for_each_rtd_codec_dai_rollback(rtd, i, codec_dai) {
Jerome Brunetf47b9ad2019-04-29 11:47:50 +0200914 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
915 continue;
916
Kuninori Morimoto846faae2019-07-22 10:33:19 +0900917 snd_soc_dai_hw_free(codec_dai, substream);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200918 codec_dai->rate = 0;
919 }
920
Kuninori Morimoto49f020e2020-01-22 09:44:52 +0900921 soc_rtd_hw_free(rtd, substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100922
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300923 mutex_unlock(&rtd->card->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100924 return ret;
925}
926
927/*
928 * Frees resources allocated by hw_params, can be called multiple times
929 */
930static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
931{
932 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100933 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200934 struct snd_soc_dai *codec_dai;
Nicolin Chen7f62b6e2013-12-04 11:18:36 +0800935 bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200936 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100937
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300938 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100939
Nicolin Chend3383422013-11-20 18:37:09 +0800940 /* clear the corresponding DAIs parameters when going to be inactive */
941 if (cpu_dai->active == 1) {
942 cpu_dai->rate = 0;
943 cpu_dai->channels = 0;
944 cpu_dai->sample_bits = 0;
945 }
946
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000947 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200948 if (codec_dai->active == 1) {
949 codec_dai->rate = 0;
950 codec_dai->channels = 0;
951 codec_dai->sample_bits = 0;
952 }
Nicolin Chend3383422013-11-20 18:37:09 +0800953 }
954
Liam Girdwoodddee6272011-06-09 14:45:53 +0100955 /* apply codec digital mute */
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000956 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto0f6011f2020-02-17 17:28:15 +0900957 int playback_active = codec_dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK];
958 int capture_active = codec_dai->stream_active[SNDRV_PCM_STREAM_CAPTURE];
959
960 if ((playback && playback_active == 1) ||
961 (!playback && capture_active == 1))
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000962 snd_soc_dai_digital_mute(codec_dai, 1,
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200963 substream->stream);
964 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100965
966 /* free any machine hw params */
Kuninori Morimoto49f020e2020-01-22 09:44:52 +0900967 soc_rtd_hw_free(rtd, substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100968
Kuninori Morimotob8135862017-10-11 01:37:23 +0000969 /* free any component resources */
Charles Keepax244e2932018-06-19 16:22:09 +0100970 soc_pcm_components_hw_free(substream, NULL);
Kuninori Morimotob8135862017-10-11 01:37:23 +0000971
Liam Girdwoodddee6272011-06-09 14:45:53 +0100972 /* now free hw params for the DAIs */
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000973 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Jerome Brunetf47b9ad2019-04-29 11:47:50 +0200974 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
975 continue;
976
Kuninori Morimoto846faae2019-07-22 10:33:19 +0900977 snd_soc_dai_hw_free(codec_dai, substream);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200978 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100979
Kuninori Morimoto846faae2019-07-22 10:33:19 +0900980 snd_soc_dai_hw_free(cpu_dai, substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100981
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300982 mutex_unlock(&rtd->card->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100983 return 0;
984}
985
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +0300986static int soc_pcm_trigger_start(struct snd_pcm_substream *substream, int cmd)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100987{
988 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000989 struct snd_soc_component *component;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100990 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200991 struct snd_soc_dai *codec_dai;
992 int i, ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100993
Kuninori Morimotoad2bf9f2020-01-22 09:44:56 +0900994 ret = soc_rtd_trigger(rtd, substream, cmd);
995 if (ret < 0)
996 return ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100997
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900998 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto5693d502019-07-26 13:50:29 +0900999 ret = snd_soc_component_trigger(component, substream, cmd);
Kuninori Morimotob8135862017-10-11 01:37:23 +00001000 if (ret < 0)
1001 return ret;
1002 }
1003
Dan Carpenter901e8222019-09-23 17:22:57 +03001004 ret = snd_soc_dai_trigger(cpu_dai, substream, cmd);
Kuninori Morimoto95aef352019-07-22 10:33:51 +09001005 if (ret < 0)
1006 return ret;
Jarkko Nikula4792b0d2014-04-28 14:17:52 +02001007
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001008 for_each_rtd_codec_dai(rtd, i, codec_dai) {
1009 ret = snd_soc_dai_trigger(codec_dai, substream, cmd);
1010 if (ret < 0)
1011 return ret;
1012 }
1013
1014 return 0;
1015}
1016
1017static int soc_pcm_trigger_stop(struct snd_pcm_substream *substream, int cmd)
1018{
1019 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1020 struct snd_soc_component *component;
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001021 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
1022 struct snd_soc_dai *codec_dai;
1023 int i, ret;
1024
1025 for_each_rtd_codec_dai(rtd, i, codec_dai) {
1026 ret = snd_soc_dai_trigger(codec_dai, substream, cmd);
1027 if (ret < 0)
1028 return ret;
1029 }
1030
1031 ret = snd_soc_dai_trigger(cpu_dai, substream, cmd);
1032 if (ret < 0)
1033 return ret;
1034
Kuninori Morimoto613fb502020-01-10 11:35:21 +09001035 for_each_rtd_components(rtd, i, component) {
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001036 ret = snd_soc_component_trigger(component, substream, cmd);
1037 if (ret < 0)
1038 return ret;
1039 }
1040
Kuninori Morimotoad2bf9f2020-01-22 09:44:56 +09001041 ret = soc_rtd_trigger(rtd, substream, cmd);
1042 if (ret < 0)
1043 return ret;
Jarkko Nikula4792b0d2014-04-28 14:17:52 +02001044
Liam Girdwoodddee6272011-06-09 14:45:53 +01001045 return 0;
1046}
1047
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001048static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1049{
1050 int ret;
1051
1052 switch (cmd) {
1053 case SNDRV_PCM_TRIGGER_START:
1054 case SNDRV_PCM_TRIGGER_RESUME:
1055 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1056 ret = soc_pcm_trigger_start(substream, cmd);
1057 break;
1058 case SNDRV_PCM_TRIGGER_STOP:
1059 case SNDRV_PCM_TRIGGER_SUSPEND:
1060 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
1061 ret = soc_pcm_trigger_stop(substream, cmd);
1062 break;
1063 default:
1064 return -EINVAL;
1065 }
1066
1067 return ret;
1068}
1069
Mark Brown45c0a182012-05-09 21:46:27 +01001070static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
1071 int cmd)
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001072{
1073 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001074 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001075 struct snd_soc_dai *codec_dai;
1076 int i, ret;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001077
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001078 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto5c0769af2019-07-22 10:33:56 +09001079 ret = snd_soc_dai_bespoke_trigger(codec_dai, substream, cmd);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001080 if (ret < 0)
1081 return ret;
1082 }
Kuninori Morimoto5c0769af2019-07-22 10:33:56 +09001083
Dan Carpenter901e8222019-09-23 17:22:57 +03001084 ret = snd_soc_dai_bespoke_trigger(cpu_dai, substream, cmd);
Kuninori Morimoto5c0769af2019-07-22 10:33:56 +09001085 if (ret < 0)
1086 return ret;
1087
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001088 return 0;
1089}
Liam Girdwoodddee6272011-06-09 14:45:53 +01001090/*
1091 * soc level wrapper for pointer callback
Charles Keepaxef050be2018-04-24 16:39:02 +01001092 * If cpu_dai, codec_dai, component driver has the delay callback, then
Liam Girdwoodddee6272011-06-09 14:45:53 +01001093 * the runtime->delay will be updated accordingly.
1094 */
1095static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
1096{
1097 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001098 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001099 struct snd_soc_dai *codec_dai;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001100 struct snd_pcm_runtime *runtime = substream->runtime;
1101 snd_pcm_uframes_t offset = 0;
1102 snd_pcm_sframes_t delay = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001103 snd_pcm_sframes_t codec_delay = 0;
1104 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001105
Akshu Agrawal9fb4c2bf2018-08-01 15:37:33 +05301106 /* clearing the previous total delay */
1107 runtime->delay = 0;
1108
Kuninori Morimoto0035e252019-07-26 13:51:47 +09001109 offset = snd_soc_pcm_component_pointer(substream);
Kuninori Morimotob8135862017-10-11 01:37:23 +00001110
Akshu Agrawal9fb4c2bf2018-08-01 15:37:33 +05301111 /* base delay if assigned in pointer callback */
1112 delay = runtime->delay;
Kuninori Morimotob8135862017-10-11 01:37:23 +00001113
Kuninori Morimoto1dea80d2019-07-22 10:34:09 +09001114 delay += snd_soc_dai_delay(cpu_dai, substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001115
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001116 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto1dea80d2019-07-22 10:34:09 +09001117 codec_delay = max(codec_delay,
1118 snd_soc_dai_delay(codec_dai, substream));
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001119 }
1120 delay += codec_delay;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001121
Liam Girdwoodddee6272011-06-09 14:45:53 +01001122 runtime->delay = delay;
1123
1124 return offset;
1125}
1126
Liam Girdwood01d75842012-04-25 12:12:49 +01001127/* connect a FE and BE */
1128static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
1129 struct snd_soc_pcm_runtime *be, int stream)
1130{
1131 struct snd_soc_dpcm *dpcm;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001132 unsigned long flags;
Takashi Iwaibd0b6092019-11-07 14:48:33 +01001133#ifdef CONFIG_DEBUG_FS
Hans de Goede0632fa02019-10-05 23:22:02 +02001134 char *name;
Takashi Iwaibd0b6092019-11-07 14:48:33 +01001135#endif
Liam Girdwood01d75842012-04-25 12:12:49 +01001136
1137 /* only add new dpcms */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001138 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001139 if (dpcm->be == be && dpcm->fe == fe)
1140 return 0;
1141 }
1142
1143 dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_KERNEL);
1144 if (!dpcm)
1145 return -ENOMEM;
1146
1147 dpcm->be = be;
1148 dpcm->fe = fe;
1149 be->dpcm[stream].runtime = fe->dpcm[stream].runtime;
1150 dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001151 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001152 list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients);
1153 list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001154 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001155
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001156 dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001157 stream ? "capture" : "playback", fe->dai_link->name,
1158 stream ? "<-" : "->", be->dai_link->name);
1159
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001160#ifdef CONFIG_DEBUG_FS
Hans de Goede0632fa02019-10-05 23:22:02 +02001161 name = kasprintf(GFP_KERNEL, "%s:%s", be->dai_link->name,
1162 stream ? "capture" : "playback");
1163 if (name) {
1164 dpcm->debugfs_state = debugfs_create_dir(name,
1165 fe->debugfs_dpcm_root);
1166 debugfs_create_u32("state", 0644, dpcm->debugfs_state,
1167 &dpcm->state);
1168 kfree(name);
1169 }
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001170#endif
Liam Girdwood01d75842012-04-25 12:12:49 +01001171 return 1;
1172}
1173
1174/* reparent a BE onto another FE */
1175static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
1176 struct snd_soc_pcm_runtime *be, int stream)
1177{
1178 struct snd_soc_dpcm *dpcm;
1179 struct snd_pcm_substream *fe_substream, *be_substream;
1180
1181 /* reparent if BE is connected to other FEs */
1182 if (!be->dpcm[stream].users)
1183 return;
1184
1185 be_substream = snd_soc_dpcm_get_substream(be, stream);
1186
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00001187 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001188 if (dpcm->fe == fe)
1189 continue;
1190
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001191 dev_dbg(fe->dev, "reparent %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001192 stream ? "capture" : "playback",
1193 dpcm->fe->dai_link->name,
1194 stream ? "<-" : "->", dpcm->be->dai_link->name);
1195
1196 fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, stream);
1197 be_substream->runtime = fe_substream->runtime;
1198 break;
1199 }
1200}
1201
1202/* disconnect a BE and FE */
Liam Girdwood23607022014-01-17 17:03:55 +00001203void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001204{
1205 struct snd_soc_dpcm *dpcm, *d;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001206 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001207
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001208 for_each_dpcm_be_safe(fe, stream, dpcm, d) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001209 dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001210 stream ? "capture" : "playback",
1211 dpcm->be->dai_link->name);
1212
1213 if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE)
1214 continue;
1215
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001216 dev_dbg(fe->dev, "freed DSP %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001217 stream ? "capture" : "playback", fe->dai_link->name,
1218 stream ? "<-" : "->", dpcm->be->dai_link->name);
1219
1220 /* BEs still alive need new FE */
1221 dpcm_be_reparent(fe, dpcm->be, stream);
1222
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001223#ifdef CONFIG_DEBUG_FS
Greg Kroah-Hartmanfee531d2019-07-31 15:17:15 +02001224 debugfs_remove_recursive(dpcm->debugfs_state);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001225#endif
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001226 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001227 list_del(&dpcm->list_be);
1228 list_del(&dpcm->list_fe);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001229 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001230 kfree(dpcm);
1231 }
1232}
1233
1234/* get BE for DAI widget and stream */
1235static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
1236 struct snd_soc_dapm_widget *widget, int stream)
1237{
1238 struct snd_soc_pcm_runtime *be;
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001239 struct snd_soc_dapm_widget *w;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001240 struct snd_soc_dai *dai;
Mengdong Lin1a497982015-11-18 02:34:11 -05001241 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01001242
Liam Girdwood3c146462018-03-14 20:43:51 +00001243 dev_dbg(card->dev, "ASoC: find BE for widget %s\n", widget->name);
1244
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001245 for_each_card_rtds(card, be) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001246
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001247 if (!be->dai_link->no_pcm)
1248 continue;
Liam Girdwood35ea0652012-06-05 19:26:59 +01001249
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001250 w = dai_get_widget(be->cpu_dai, stream);
Liam Girdwood3c146462018-03-14 20:43:51 +00001251
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001252 dev_dbg(card->dev, "ASoC: try BE : %s\n",
1253 w ? w->name : "(not set)");
1254
1255 if (w == widget)
1256 return be;
1257
1258 for_each_rtd_codec_dai(be, i, dai) {
1259 w = dai_get_widget(dai, stream);
1260
1261 if (w == widget)
Liam Girdwood01d75842012-04-25 12:12:49 +01001262 return be;
Liam Girdwood01d75842012-04-25 12:12:49 +01001263 }
1264 }
1265
Jerome Brunet9d6ee362020-02-19 12:50:48 +01001266 /* Widget provided is not a BE */
Liam Girdwood01d75842012-04-25 12:12:49 +01001267 return NULL;
1268}
1269
Liam Girdwood01d75842012-04-25 12:12:49 +01001270static int widget_in_list(struct snd_soc_dapm_widget_list *list,
1271 struct snd_soc_dapm_widget *widget)
1272{
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001273 struct snd_soc_dapm_widget *w;
Liam Girdwood01d75842012-04-25 12:12:49 +01001274 int i;
1275
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001276 for_each_dapm_widgets(list, i, w)
1277 if (widget == w)
Liam Girdwood01d75842012-04-25 12:12:49 +01001278 return 1;
Liam Girdwood01d75842012-04-25 12:12:49 +01001279
1280 return 0;
1281}
1282
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001283static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget,
1284 enum snd_soc_dapm_direction dir)
1285{
1286 struct snd_soc_card *card = widget->dapm->card;
1287 struct snd_soc_pcm_runtime *rtd;
Kuninori Morimotoc2cd8212020-02-17 17:27:48 +09001288 int stream;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001289
Kuninori Morimotoc2cd8212020-02-17 17:27:48 +09001290 /* adjust dir to stream */
1291 if (dir == SND_SOC_DAPM_DIR_OUT)
1292 stream = SNDRV_PCM_STREAM_PLAYBACK;
1293 else
1294 stream = SNDRV_PCM_STREAM_CAPTURE;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001295
Kuninori Morimoto027a4832020-02-17 17:27:53 +09001296 rtd = dpcm_get_be(card, widget, stream);
1297 if (rtd)
1298 return true;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001299
1300 return false;
1301}
1302
Liam Girdwood23607022014-01-17 17:03:55 +00001303int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001304 int stream, struct snd_soc_dapm_widget_list **list)
Liam Girdwood01d75842012-04-25 12:12:49 +01001305{
1306 struct snd_soc_dai *cpu_dai = fe->cpu_dai;
Liam Girdwood01d75842012-04-25 12:12:49 +01001307 int paths;
1308
Liam Girdwood01d75842012-04-25 12:12:49 +01001309 /* get number of valid DAI paths and their widgets */
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001310 paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list,
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001311 dpcm_end_walk_at_be);
Liam Girdwood01d75842012-04-25 12:12:49 +01001312
Liam Girdwood103d84a2012-11-19 14:39:15 +00001313 dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths,
Liam Girdwood01d75842012-04-25 12:12:49 +01001314 stream ? "capture" : "playback");
1315
Liam Girdwood01d75842012-04-25 12:12:49 +01001316 return paths;
1317}
1318
Liam Girdwood01d75842012-04-25 12:12:49 +01001319static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
1320 struct snd_soc_dapm_widget_list **list_)
1321{
1322 struct snd_soc_dpcm *dpcm;
1323 struct snd_soc_dapm_widget_list *list = *list_;
1324 struct snd_soc_dapm_widget *widget;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001325 struct snd_soc_dai *dai;
Liam Girdwood01d75842012-04-25 12:12:49 +01001326 int prune = 0;
Kuninori Morimotobed646d2019-10-15 12:59:38 +09001327 int do_prune;
Liam Girdwood01d75842012-04-25 12:12:49 +01001328
1329 /* Destroy any old FE <--> BE connections */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001330 for_each_dpcm_be(fe, stream, dpcm) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001331 unsigned int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01001332
1333 /* is there a valid CPU DAI widget for this BE */
Benoit Cousson37018612014-04-24 14:01:45 +02001334 widget = dai_get_widget(dpcm->be->cpu_dai, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001335
1336 /* prune the BE if it's no longer in our active list */
1337 if (widget && widget_in_list(list, widget))
1338 continue;
1339
1340 /* is there a valid CODEC DAI widget for this BE */
Kuninori Morimotobed646d2019-10-15 12:59:38 +09001341 do_prune = 1;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001342 for_each_rtd_codec_dai(dpcm->be, i, dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001343 widget = dai_get_widget(dai, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001344
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001345 /* prune the BE if it's no longer in our active list */
1346 if (widget && widget_in_list(list, widget))
Kuninori Morimotobed646d2019-10-15 12:59:38 +09001347 do_prune = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001348 }
Kuninori Morimotobed646d2019-10-15 12:59:38 +09001349 if (!do_prune)
1350 continue;
Liam Girdwood01d75842012-04-25 12:12:49 +01001351
Liam Girdwood103d84a2012-11-19 14:39:15 +00001352 dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001353 stream ? "capture" : "playback",
1354 dpcm->be->dai_link->name, fe->dai_link->name);
1355 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
1356 dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1357 prune++;
1358 }
1359
Liam Girdwood103d84a2012-11-19 14:39:15 +00001360 dev_dbg(fe->dev, "ASoC: found %d old BE paths for pruning\n", prune);
Liam Girdwood01d75842012-04-25 12:12:49 +01001361 return prune;
1362}
1363
1364static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
1365 struct snd_soc_dapm_widget_list **list_)
1366{
1367 struct snd_soc_card *card = fe->card;
1368 struct snd_soc_dapm_widget_list *list = *list_;
1369 struct snd_soc_pcm_runtime *be;
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001370 struct snd_soc_dapm_widget *widget;
Liam Girdwood01d75842012-04-25 12:12:49 +01001371 int i, new = 0, err;
1372
1373 /* Create any new FE <--> BE connections */
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001374 for_each_dapm_widgets(list, i, widget) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001375
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001376 switch (widget->id) {
Mark Brown46162742013-06-05 19:36:11 +01001377 case snd_soc_dapm_dai_in:
Koro Chenc5b85402015-07-06 10:02:10 +08001378 if (stream != SNDRV_PCM_STREAM_PLAYBACK)
1379 continue;
1380 break;
Mark Brown46162742013-06-05 19:36:11 +01001381 case snd_soc_dapm_dai_out:
Koro Chenc5b85402015-07-06 10:02:10 +08001382 if (stream != SNDRV_PCM_STREAM_CAPTURE)
1383 continue;
Mark Brown46162742013-06-05 19:36:11 +01001384 break;
1385 default:
Liam Girdwood01d75842012-04-25 12:12:49 +01001386 continue;
Mark Brown46162742013-06-05 19:36:11 +01001387 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001388
1389 /* is there a valid BE rtd for this widget */
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001390 be = dpcm_get_be(card, widget, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001391 if (!be) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001392 dev_err(fe->dev, "ASoC: no BE found for %s\n",
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001393 widget->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001394 continue;
1395 }
1396
1397 /* make sure BE is a real BE */
1398 if (!be->dai_link->no_pcm)
1399 continue;
1400
1401 /* don't connect if FE is not running */
Liam Girdwood23607022014-01-17 17:03:55 +00001402 if (!fe->dpcm[stream].runtime && !fe->fe_compr)
Liam Girdwood01d75842012-04-25 12:12:49 +01001403 continue;
1404
1405 /* newly connected FE and BE */
1406 err = dpcm_be_connect(fe, be, stream);
1407 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001408 dev_err(fe->dev, "ASoC: can't connect %s\n",
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001409 widget->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001410 break;
1411 } else if (err == 0) /* already connected */
1412 continue;
1413
1414 /* new */
1415 be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1416 new++;
1417 }
1418
Liam Girdwood103d84a2012-11-19 14:39:15 +00001419 dev_dbg(fe->dev, "ASoC: found %d new BE paths\n", new);
Liam Girdwood01d75842012-04-25 12:12:49 +01001420 return new;
1421}
1422
1423/*
1424 * Find the corresponding BE DAIs that source or sink audio to this
1425 * FE substream.
1426 */
Liam Girdwood23607022014-01-17 17:03:55 +00001427int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
Liam Girdwood01d75842012-04-25 12:12:49 +01001428 int stream, struct snd_soc_dapm_widget_list **list, int new)
1429{
1430 if (new)
1431 return dpcm_add_paths(fe, stream, list);
1432 else
1433 return dpcm_prune_paths(fe, stream, list);
1434}
1435
Liam Girdwood23607022014-01-17 17:03:55 +00001436void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001437{
1438 struct snd_soc_dpcm *dpcm;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001439 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001440
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001441 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001442 for_each_dpcm_be(fe, stream, dpcm)
Liam Girdwood01d75842012-04-25 12:12:49 +01001443 dpcm->be->dpcm[stream].runtime_update =
1444 SND_SOC_DPCM_UPDATE_NO;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001445 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001446}
1447
1448static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe,
1449 int stream)
1450{
1451 struct snd_soc_dpcm *dpcm;
1452
1453 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001454 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001455
1456 struct snd_soc_pcm_runtime *be = dpcm->be;
1457 struct snd_pcm_substream *be_substream =
1458 snd_soc_dpcm_get_substream(be, stream);
1459
1460 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001461 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001462 stream ? "capture" : "playback",
1463 be->dpcm[stream].state);
1464
1465 if (--be->dpcm[stream].users != 0)
1466 continue;
1467
1468 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1469 continue;
1470
1471 soc_pcm_close(be_substream);
1472 be_substream->runtime = NULL;
1473 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1474 }
1475}
1476
Liam Girdwood23607022014-01-17 17:03:55 +00001477int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001478{
1479 struct snd_soc_dpcm *dpcm;
1480 int err, count = 0;
1481
1482 /* only startup BE DAIs that are either sinks or sources to this FE DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001483 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001484
1485 struct snd_soc_pcm_runtime *be = dpcm->be;
1486 struct snd_pcm_substream *be_substream =
1487 snd_soc_dpcm_get_substream(be, stream);
1488
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001489 if (!be_substream) {
1490 dev_err(be->dev, "ASoC: no backend %s stream\n",
1491 stream ? "capture" : "playback");
1492 continue;
1493 }
1494
Liam Girdwood01d75842012-04-25 12:12:49 +01001495 /* is this op for this BE ? */
1496 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1497 continue;
1498
1499 /* first time the dpcm is open ? */
1500 if (be->dpcm[stream].users == DPCM_MAX_BE_USERS)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001501 dev_err(be->dev, "ASoC: too many users %s at open %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001502 stream ? "capture" : "playback",
1503 be->dpcm[stream].state);
1504
1505 if (be->dpcm[stream].users++ != 0)
1506 continue;
1507
1508 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
1509 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
1510 continue;
1511
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001512 dev_dbg(be->dev, "ASoC: open %s BE %s\n",
1513 stream ? "capture" : "playback", be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001514
1515 be_substream->runtime = be->dpcm[stream].runtime;
1516 err = soc_pcm_open(be_substream);
1517 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001518 dev_err(be->dev, "ASoC: BE open failed %d\n", err);
Liam Girdwood01d75842012-04-25 12:12:49 +01001519 be->dpcm[stream].users--;
1520 if (be->dpcm[stream].users < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001521 dev_err(be->dev, "ASoC: no users %s at unwind %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001522 stream ? "capture" : "playback",
1523 be->dpcm[stream].state);
1524
1525 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1526 goto unwind;
1527 }
1528
1529 be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1530 count++;
1531 }
1532
1533 return count;
1534
1535unwind:
1536 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001537 for_each_dpcm_be_rollback(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001538 struct snd_soc_pcm_runtime *be = dpcm->be;
1539 struct snd_pcm_substream *be_substream =
1540 snd_soc_dpcm_get_substream(be, stream);
1541
1542 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1543 continue;
1544
1545 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001546 dev_err(be->dev, "ASoC: no users %s at close %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_OPEN)
1554 continue;
1555
1556 soc_pcm_close(be_substream);
1557 be_substream->runtime = NULL;
1558 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1559 }
1560
1561 return err;
1562}
1563
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001564static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
Jerome Brunet435ffb72018-07-05 12:13:48 +02001565 struct snd_soc_pcm_stream *stream)
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001566{
1567 runtime->hw.rate_min = stream->rate_min;
Charles Keepaxe33ffbd9c2018-08-27 14:26:47 +01001568 runtime->hw.rate_max = min_not_zero(stream->rate_max, UINT_MAX);
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001569 runtime->hw.channels_min = stream->channels_min;
1570 runtime->hw.channels_max = stream->channels_max;
Lars-Peter Clausen002220a2014-01-06 14:19:07 +01001571 if (runtime->hw.formats)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001572 runtime->hw.formats &= stream->formats;
Lars-Peter Clausen002220a2014-01-06 14:19:07 +01001573 else
Jerome Brunet435ffb72018-07-05 12:13:48 +02001574 runtime->hw.formats = stream->formats;
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001575 runtime->hw.rates = stream->rates;
1576}
1577
Jerome Brunet435ffb72018-07-05 12:13:48 +02001578static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream,
1579 u64 *formats)
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001580{
1581 struct snd_soc_pcm_runtime *fe = substream->private_data;
1582 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001583 struct snd_soc_dai *dai;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001584 int stream = substream->stream;
1585
1586 if (!fe->dai_link->dpcm_merged_format)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001587 return;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001588
1589 /*
1590 * It returns merged BE codec format
1591 * if FE want to use it (= dpcm_merged_format)
1592 */
1593
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001594 for_each_dpcm_be(fe, stream, dpcm) {
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001595 struct snd_soc_pcm_runtime *be = dpcm->be;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001596 struct snd_soc_pcm_stream *codec_stream;
1597 int i;
1598
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001599 for_each_rtd_codec_dai(be, i, dai) {
Jerome Brunet4febced2018-06-27 17:36:38 +02001600 /*
1601 * Skip CODECs which don't support the current stream
1602 * type. See soc_pcm_init_runtime_hw() for more details
1603 */
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001604 if (!snd_soc_dai_stream_valid(dai, stream))
Jerome Brunet4febced2018-06-27 17:36:38 +02001605 continue;
1606
Kuninori Morimotoacf253c2020-02-19 15:56:30 +09001607 codec_stream = snd_soc_dai_get_pcm_stream(dai, stream);
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001608
Jerome Brunet435ffb72018-07-05 12:13:48 +02001609 *formats &= codec_stream->formats;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001610 }
1611 }
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001612}
1613
Jerome Brunet435ffb72018-07-05 12:13:48 +02001614static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream,
1615 unsigned int *channels_min,
1616 unsigned int *channels_max)
Jiada Wangf4c277b2018-06-20 18:25:20 +09001617{
1618 struct snd_soc_pcm_runtime *fe = substream->private_data;
1619 struct snd_soc_dpcm *dpcm;
1620 int stream = substream->stream;
1621
1622 if (!fe->dai_link->dpcm_merged_chan)
1623 return;
1624
Jiada Wangf4c277b2018-06-20 18:25:20 +09001625 /*
1626 * It returns merged BE codec channel;
1627 * if FE want to use it (= dpcm_merged_chan)
1628 */
1629
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001630 for_each_dpcm_be(fe, stream, dpcm) {
Jiada Wangf4c277b2018-06-20 18:25:20 +09001631 struct snd_soc_pcm_runtime *be = dpcm->be;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001632 struct snd_soc_pcm_stream *codec_stream;
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001633 struct snd_soc_pcm_stream *cpu_stream;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001634
Kuninori Morimotoacf253c2020-02-19 15:56:30 +09001635 cpu_stream = snd_soc_dai_get_pcm_stream(be->cpu_dai, stream);
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001636
1637 *channels_min = max(*channels_min, cpu_stream->channels_min);
1638 *channels_max = min(*channels_max, cpu_stream->channels_max);
1639
1640 /*
1641 * chan min/max cannot be enforced if there are multiple CODEC
1642 * DAIs connected to a single CPU DAI, use CPU DAI's directly
1643 */
1644 if (be->num_codecs == 1) {
Kuninori Morimotoacf253c2020-02-19 15:56:30 +09001645 codec_stream = snd_soc_dai_get_pcm_stream(be->codec_dais[0], stream);
Jiada Wangf4c277b2018-06-20 18:25:20 +09001646
1647 *channels_min = max(*channels_min,
1648 codec_stream->channels_min);
1649 *channels_max = min(*channels_max,
1650 codec_stream->channels_max);
1651 }
1652 }
1653}
1654
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001655static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream,
1656 unsigned int *rates,
1657 unsigned int *rate_min,
1658 unsigned int *rate_max)
1659{
1660 struct snd_soc_pcm_runtime *fe = substream->private_data;
1661 struct snd_soc_dpcm *dpcm;
1662 int stream = substream->stream;
1663
1664 if (!fe->dai_link->dpcm_merged_rate)
1665 return;
1666
1667 /*
1668 * It returns merged BE codec channel;
1669 * if FE want to use it (= dpcm_merged_chan)
1670 */
1671
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001672 for_each_dpcm_be(fe, stream, dpcm) {
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001673 struct snd_soc_pcm_runtime *be = dpcm->be;
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001674 struct snd_soc_pcm_stream *codec_stream;
1675 struct snd_soc_pcm_stream *cpu_stream;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001676 struct snd_soc_dai *dai;
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001677 int i;
1678
Kuninori Morimotoacf253c2020-02-19 15:56:30 +09001679 cpu_stream = snd_soc_dai_get_pcm_stream(be->cpu_dai, stream);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001680
1681 *rate_min = max(*rate_min, cpu_stream->rate_min);
1682 *rate_max = min_not_zero(*rate_max, cpu_stream->rate_max);
1683 *rates = snd_pcm_rate_mask_intersect(*rates, cpu_stream->rates);
1684
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001685 for_each_rtd_codec_dai(be, i, dai) {
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001686 /*
1687 * Skip CODECs which don't support the current stream
1688 * type. See soc_pcm_init_runtime_hw() for more details
1689 */
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001690 if (!snd_soc_dai_stream_valid(dai, stream))
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001691 continue;
1692
Kuninori Morimotoacf253c2020-02-19 15:56:30 +09001693 codec_stream = snd_soc_dai_get_pcm_stream(dai, stream);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001694
1695 *rate_min = max(*rate_min, codec_stream->rate_min);
1696 *rate_max = min_not_zero(*rate_max,
1697 codec_stream->rate_max);
1698 *rates = snd_pcm_rate_mask_intersect(*rates,
1699 codec_stream->rates);
1700 }
1701 }
1702}
1703
Mark Brown45c0a182012-05-09 21:46:27 +01001704static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001705{
1706 struct snd_pcm_runtime *runtime = substream->runtime;
1707 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1708 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
1709 struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
1710
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001711 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001712 dpcm_init_runtime_hw(runtime, &cpu_dai_drv->playback);
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001713 else
Jerome Brunet435ffb72018-07-05 12:13:48 +02001714 dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture);
Jiada Wangf4c277b2018-06-20 18:25:20 +09001715
Jerome Brunet435ffb72018-07-05 12:13:48 +02001716 dpcm_runtime_merge_format(substream, &runtime->hw.formats);
1717 dpcm_runtime_merge_chan(substream, &runtime->hw.channels_min,
1718 &runtime->hw.channels_max);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001719 dpcm_runtime_merge_rate(substream, &runtime->hw.rates,
1720 &runtime->hw.rate_min, &runtime->hw.rate_max);
Liam Girdwood01d75842012-04-25 12:12:49 +01001721}
1722
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001723static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
1724
1725/* Set FE's runtime_update state; the state is protected via PCM stream lock
1726 * for avoiding the race with trigger callback.
1727 * If the state is unset and a trigger is pending while the previous operation,
1728 * process the pending trigger action here.
1729 */
1730static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
1731 int stream, enum snd_soc_dpcm_update state)
1732{
1733 struct snd_pcm_substream *substream =
1734 snd_soc_dpcm_get_substream(fe, stream);
1735
1736 snd_pcm_stream_lock_irq(substream);
1737 if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) {
1738 dpcm_fe_dai_do_trigger(substream,
1739 fe->dpcm[stream].trigger_pending - 1);
1740 fe->dpcm[stream].trigger_pending = 0;
1741 }
1742 fe->dpcm[stream].runtime_update = state;
1743 snd_pcm_stream_unlock_irq(substream);
1744}
1745
PC Liao906c7d62015-12-11 11:33:51 +08001746static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
1747 int stream)
1748{
1749 struct snd_soc_dpcm *dpcm;
1750 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
1751 struct snd_soc_dai *fe_cpu_dai = fe->cpu_dai;
1752 int err;
1753
1754 /* apply symmetry for FE */
1755 if (soc_pcm_has_symmetry(fe_substream))
1756 fe_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1757
1758 /* Symmetry only applies if we've got an active stream. */
1759 if (fe_cpu_dai->active) {
1760 err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai);
1761 if (err < 0)
1762 return err;
1763 }
1764
1765 /* apply symmetry for BE */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001766 for_each_dpcm_be(fe, stream, dpcm) {
PC Liao906c7d62015-12-11 11:33:51 +08001767 struct snd_soc_pcm_runtime *be = dpcm->be;
1768 struct snd_pcm_substream *be_substream =
1769 snd_soc_dpcm_get_substream(be, stream);
Jerome Brunet6246f282019-04-01 15:03:54 +02001770 struct snd_soc_pcm_runtime *rtd;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001771 struct snd_soc_dai *codec_dai;
PC Liao906c7d62015-12-11 11:33:51 +08001772 int i;
1773
Jerome Brunet6246f282019-04-01 15:03:54 +02001774 /* A backend may not have the requested substream */
1775 if (!be_substream)
1776 continue;
1777
1778 rtd = be_substream->private_data;
Jeeja KPf1176612016-09-06 14:17:55 +05301779 if (rtd->dai_link->be_hw_params_fixup)
1780 continue;
1781
PC Liao906c7d62015-12-11 11:33:51 +08001782 if (soc_pcm_has_symmetry(be_substream))
1783 be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1784
1785 /* Symmetry only applies if we've got an active stream. */
1786 if (rtd->cpu_dai->active) {
Kai Chieh Chuang99bcedb2018-05-28 10:18:19 +08001787 err = soc_pcm_apply_symmetry(fe_substream,
1788 rtd->cpu_dai);
PC Liao906c7d62015-12-11 11:33:51 +08001789 if (err < 0)
1790 return err;
1791 }
1792
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001793 for_each_rtd_codec_dai(rtd, i, codec_dai) {
1794 if (codec_dai->active) {
Kai Chieh Chuang99bcedb2018-05-28 10:18:19 +08001795 err = soc_pcm_apply_symmetry(fe_substream,
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001796 codec_dai);
PC Liao906c7d62015-12-11 11:33:51 +08001797 if (err < 0)
1798 return err;
1799 }
1800 }
1801 }
1802
1803 return 0;
1804}
1805
Liam Girdwood01d75842012-04-25 12:12:49 +01001806static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
1807{
1808 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
1809 struct snd_pcm_runtime *runtime = fe_substream->runtime;
1810 int stream = fe_substream->stream, ret = 0;
1811
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001812 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001813
1814 ret = dpcm_be_dai_startup(fe, fe_substream->stream);
1815 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001816 dev_err(fe->dev,"ASoC: failed to start some BEs %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001817 goto be_err;
1818 }
1819
Liam Girdwood103d84a2012-11-19 14:39:15 +00001820 dev_dbg(fe->dev, "ASoC: open FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001821
1822 /* start the DAI frontend */
1823 ret = soc_pcm_open(fe_substream);
1824 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001825 dev_err(fe->dev,"ASoC: failed to start FE %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001826 goto unwind;
1827 }
1828
1829 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1830
1831 dpcm_set_fe_runtime(fe_substream);
1832 snd_pcm_limit_hw_rates(runtime);
1833
PC Liao906c7d62015-12-11 11:33:51 +08001834 ret = dpcm_apply_symmetry(fe_substream, stream);
1835 if (ret < 0) {
1836 dev_err(fe->dev, "ASoC: failed to apply dpcm symmetry %d\n",
1837 ret);
1838 goto unwind;
1839 }
1840
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001841 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001842 return 0;
1843
1844unwind:
1845 dpcm_be_dai_startup_unwind(fe, fe_substream->stream);
1846be_err:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001847 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001848 return ret;
1849}
1850
Liam Girdwood23607022014-01-17 17:03:55 +00001851int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001852{
1853 struct snd_soc_dpcm *dpcm;
1854
1855 /* only shutdown BEs that are either sinks or sources to this FE DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001856 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001857
1858 struct snd_soc_pcm_runtime *be = dpcm->be;
1859 struct snd_pcm_substream *be_substream =
1860 snd_soc_dpcm_get_substream(be, stream);
1861
1862 /* is this op for this BE ? */
1863 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1864 continue;
1865
1866 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001867 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001868 stream ? "capture" : "playback",
1869 be->dpcm[stream].state);
1870
1871 if (--be->dpcm[stream].users != 0)
1872 continue;
1873
1874 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Kai Chieh Chuang9c0ac702018-05-28 10:18:18 +08001875 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) {
1876 soc_pcm_hw_free(be_substream);
1877 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1878 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001879
Liam Girdwood103d84a2012-11-19 14:39:15 +00001880 dev_dbg(be->dev, "ASoC: close BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001881 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001882
1883 soc_pcm_close(be_substream);
1884 be_substream->runtime = NULL;
1885
1886 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1887 }
1888 return 0;
1889}
1890
1891static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
1892{
1893 struct snd_soc_pcm_runtime *fe = substream->private_data;
1894 int stream = substream->stream;
1895
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001896 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001897
1898 /* shutdown the BEs */
1899 dpcm_be_dai_shutdown(fe, substream->stream);
1900
Liam Girdwood103d84a2012-11-19 14:39:15 +00001901 dev_dbg(fe->dev, "ASoC: close FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001902
1903 /* now shutdown the frontend */
1904 soc_pcm_close(substream);
1905
1906 /* run the stream event for each BE */
Kuninori Morimotob0edff42020-01-10 11:36:56 +09001907 snd_soc_dapm_stream_stop(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001908
1909 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
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}
1913
Liam Girdwood23607022014-01-17 17:03:55 +00001914int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001915{
1916 struct snd_soc_dpcm *dpcm;
1917
1918 /* only hw_params backends that are either sinks or sources
1919 * to this frontend DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001920 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001921
1922 struct snd_soc_pcm_runtime *be = dpcm->be;
1923 struct snd_pcm_substream *be_substream =
1924 snd_soc_dpcm_get_substream(be, stream);
1925
1926 /* is this op for this BE ? */
1927 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1928 continue;
1929
1930 /* only free hw when no longer used - check all FEs */
1931 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1932 continue;
1933
Qiao Zhou36fba622014-12-03 10:13:43 +08001934 /* do not free hw if this BE is used by other FE */
1935 if (be->dpcm[stream].users > 1)
1936 continue;
1937
Liam Girdwood01d75842012-04-25 12:12:49 +01001938 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1939 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
1940 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Patrick Lai08b27842012-12-19 19:36:02 -08001941 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
Vinod Koul5e82d2b2016-02-01 22:26:40 +05301942 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
1943 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
Liam Girdwood01d75842012-04-25 12:12:49 +01001944 continue;
1945
Liam Girdwood103d84a2012-11-19 14:39:15 +00001946 dev_dbg(be->dev, "ASoC: hw_free BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001947 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001948
1949 soc_pcm_hw_free(be_substream);
1950
1951 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1952 }
1953
1954 return 0;
1955}
1956
Mark Brown45c0a182012-05-09 21:46:27 +01001957static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001958{
1959 struct snd_soc_pcm_runtime *fe = substream->private_data;
1960 int err, stream = substream->stream;
1961
1962 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001963 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001964
Liam Girdwood103d84a2012-11-19 14:39:15 +00001965 dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001966
1967 /* call hw_free on the frontend */
1968 err = soc_pcm_hw_free(substream);
1969 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001970 dev_err(fe->dev,"ASoC: hw_free FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001971 fe->dai_link->name);
1972
1973 /* only hw_params backends that are either sinks or sources
1974 * to this frontend DAI */
1975 err = dpcm_be_dai_hw_free(fe, stream);
1976
1977 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001978 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001979
1980 mutex_unlock(&fe->card->mutex);
1981 return 0;
1982}
1983
Liam Girdwood23607022014-01-17 17:03:55 +00001984int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001985{
1986 struct snd_soc_dpcm *dpcm;
1987 int ret;
1988
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
Liam Girdwood01d75842012-04-25 12:12:49 +01001999 /* copy params for each dpcm */
2000 memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params,
2001 sizeof(struct snd_pcm_hw_params));
2002
2003 /* perform any hw_params fixups */
2004 if (be->dai_link->be_hw_params_fixup) {
2005 ret = be->dai_link->be_hw_params_fixup(be,
2006 &dpcm->hw_params);
2007 if (ret < 0) {
2008 dev_err(be->dev,
Liam Girdwood103d84a2012-11-19 14:39:15 +00002009 "ASoC: hw_params BE fixup failed %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002010 ret);
2011 goto unwind;
2012 }
2013 }
2014
Libin Yangae061d22019-04-19 09:53:12 +08002015 /* copy the fixed-up hw params for BE dai */
2016 memcpy(&be->dpcm[stream].hw_params, &dpcm->hw_params,
2017 sizeof(struct snd_pcm_hw_params));
2018
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00002019 /* only allow hw_params() if no connected FEs are running */
2020 if (!snd_soc_dpcm_can_be_params(fe, be, stream))
2021 continue;
2022
2023 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
2024 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2025 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE))
2026 continue;
2027
2028 dev_dbg(be->dev, "ASoC: hw_params BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002029 be->dai_link->name);
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00002030
Liam Girdwood01d75842012-04-25 12:12:49 +01002031 ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params);
2032 if (ret < 0) {
2033 dev_err(dpcm->be->dev,
Liam Girdwood103d84a2012-11-19 14:39:15 +00002034 "ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002035 goto unwind;
2036 }
2037
2038 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2039 }
2040 return 0;
2041
2042unwind:
2043 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002044 for_each_dpcm_be_rollback(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002045 struct snd_soc_pcm_runtime *be = dpcm->be;
2046 struct snd_pcm_substream *be_substream =
2047 snd_soc_dpcm_get_substream(be, stream);
2048
2049 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2050 continue;
2051
2052 /* only allow hw_free() if no connected FEs are running */
2053 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2054 continue;
2055
2056 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
2057 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2058 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
2059 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
2060 continue;
2061
2062 soc_pcm_hw_free(be_substream);
2063 }
2064
2065 return ret;
2066}
2067
Mark Brown45c0a182012-05-09 21:46:27 +01002068static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
2069 struct snd_pcm_hw_params *params)
Liam Girdwood01d75842012-04-25 12:12:49 +01002070{
2071 struct snd_soc_pcm_runtime *fe = substream->private_data;
2072 int ret, stream = substream->stream;
2073
2074 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002075 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002076
2077 memcpy(&fe->dpcm[substream->stream].hw_params, params,
2078 sizeof(struct snd_pcm_hw_params));
2079 ret = dpcm_be_dai_hw_params(fe, substream->stream);
2080 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002081 dev_err(fe->dev,"ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002082 goto out;
2083 }
2084
Liam Girdwood103d84a2012-11-19 14:39:15 +00002085 dev_dbg(fe->dev, "ASoC: hw_params FE %s rate %d chan %x fmt %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002086 fe->dai_link->name, params_rate(params),
2087 params_channels(params), params_format(params));
2088
2089 /* call hw_params on the frontend */
2090 ret = soc_pcm_hw_params(substream, params);
2091 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002092 dev_err(fe->dev,"ASoC: hw_params FE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002093 dpcm_be_dai_hw_free(fe, stream);
2094 } else
2095 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2096
2097out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002098 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002099 mutex_unlock(&fe->card->mutex);
2100 return ret;
2101}
2102
2103static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm,
2104 struct snd_pcm_substream *substream, int cmd)
2105{
2106 int ret;
2107
Liam Girdwood103d84a2012-11-19 14:39:15 +00002108 dev_dbg(dpcm->be->dev, "ASoC: trigger BE %s cmd %d\n",
彭东林94d215c2016-09-26 08:29:31 +00002109 dpcm->be->dai_link->name, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002110
2111 ret = soc_pcm_trigger(substream, cmd);
2112 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002113 dev_err(dpcm->be->dev,"ASoC: trigger BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002114
2115 return ret;
2116}
2117
Liam Girdwood23607022014-01-17 17:03:55 +00002118int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
Mark Brown45c0a182012-05-09 21:46:27 +01002119 int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002120{
2121 struct snd_soc_dpcm *dpcm;
2122 int ret = 0;
2123
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002124 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002125
2126 struct snd_soc_pcm_runtime *be = dpcm->be;
2127 struct snd_pcm_substream *be_substream =
2128 snd_soc_dpcm_get_substream(be, stream);
2129
2130 /* is this op for this BE ? */
2131 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2132 continue;
2133
2134 switch (cmd) {
2135 case SNDRV_PCM_TRIGGER_START:
2136 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
2137 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
2138 continue;
2139
2140 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2141 if (ret)
2142 return ret;
2143
2144 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2145 break;
2146 case SNDRV_PCM_TRIGGER_RESUME:
2147 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
2148 continue;
2149
2150 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2151 if (ret)
2152 return ret;
2153
2154 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2155 break;
2156 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2157 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
2158 continue;
2159
2160 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2161 if (ret)
2162 return ret;
2163
2164 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2165 break;
2166 case SNDRV_PCM_TRIGGER_STOP:
2167 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2168 continue;
2169
2170 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2171 continue;
2172
2173 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2174 if (ret)
2175 return ret;
2176
2177 be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2178 break;
2179 case SNDRV_PCM_TRIGGER_SUSPEND:
Nicolin Chen868a6ca2014-05-12 20:12:05 +08002180 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
Liam Girdwood01d75842012-04-25 12:12:49 +01002181 continue;
2182
2183 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2184 continue;
2185
2186 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2187 if (ret)
2188 return ret;
2189
2190 be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND;
2191 break;
2192 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2193 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2194 continue;
2195
2196 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2197 continue;
2198
2199 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2200 if (ret)
2201 return ret;
2202
2203 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2204 break;
2205 }
2206 }
2207
2208 return ret;
2209}
2210EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
2211
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002212static int dpcm_dai_trigger_fe_be(struct snd_pcm_substream *substream,
2213 int cmd, bool fe_first)
2214{
2215 struct snd_soc_pcm_runtime *fe = substream->private_data;
2216 int ret;
2217
2218 /* call trigger on the frontend before the backend. */
2219 if (fe_first) {
2220 dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n",
2221 fe->dai_link->name, cmd);
2222
2223 ret = soc_pcm_trigger(substream, cmd);
2224 if (ret < 0)
2225 return ret;
2226
2227 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2228 return ret;
2229 }
2230
2231 /* call trigger on the frontend after the backend. */
2232 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2233 if (ret < 0)
2234 return ret;
2235
2236 dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n",
2237 fe->dai_link->name, cmd);
2238
2239 ret = soc_pcm_trigger(substream, cmd);
2240
2241 return ret;
2242}
2243
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002244static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002245{
2246 struct snd_soc_pcm_runtime *fe = substream->private_data;
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002247 int stream = substream->stream;
2248 int ret = 0;
Liam Girdwood01d75842012-04-25 12:12:49 +01002249 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
2250
2251 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
2252
2253 switch (trigger) {
2254 case SND_SOC_DPCM_TRIGGER_PRE:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002255 switch (cmd) {
2256 case SNDRV_PCM_TRIGGER_START:
2257 case SNDRV_PCM_TRIGGER_RESUME:
2258 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2259 ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
2260 break;
2261 case SNDRV_PCM_TRIGGER_STOP:
2262 case SNDRV_PCM_TRIGGER_SUSPEND:
2263 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2264 ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
2265 break;
2266 default:
2267 ret = -EINVAL;
2268 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002269 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002270 break;
2271 case SND_SOC_DPCM_TRIGGER_POST:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002272 switch (cmd) {
2273 case SNDRV_PCM_TRIGGER_START:
2274 case SNDRV_PCM_TRIGGER_RESUME:
2275 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2276 ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
2277 break;
2278 case SNDRV_PCM_TRIGGER_STOP:
2279 case SNDRV_PCM_TRIGGER_SUSPEND:
2280 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2281 ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
2282 break;
2283 default:
2284 ret = -EINVAL;
2285 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002286 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002287 break;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002288 case SND_SOC_DPCM_TRIGGER_BESPOKE:
2289 /* bespoke trigger() - handles both FE and BEs */
2290
Liam Girdwood103d84a2012-11-19 14:39:15 +00002291 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd %d\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002292 fe->dai_link->name, cmd);
2293
2294 ret = soc_pcm_bespoke_trigger(substream, cmd);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002295 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002296 default:
Liam Girdwood103d84a2012-11-19 14:39:15 +00002297 dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd,
Liam Girdwood01d75842012-04-25 12:12:49 +01002298 fe->dai_link->name);
2299 ret = -EINVAL;
2300 goto out;
2301 }
2302
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002303 if (ret < 0) {
2304 dev_err(fe->dev, "ASoC: trigger FE cmd: %d failed: %d\n",
2305 cmd, ret);
2306 goto out;
2307 }
2308
Liam Girdwood01d75842012-04-25 12:12:49 +01002309 switch (cmd) {
2310 case SNDRV_PCM_TRIGGER_START:
2311 case SNDRV_PCM_TRIGGER_RESUME:
2312 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2313 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2314 break;
2315 case SNDRV_PCM_TRIGGER_STOP:
2316 case SNDRV_PCM_TRIGGER_SUSPEND:
Liam Girdwood01d75842012-04-25 12:12:49 +01002317 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2318 break;
Patrick Lai9f169b92016-12-31 22:44:39 -08002319 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2320 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2321 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002322 }
2323
2324out:
2325 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
2326 return ret;
2327}
2328
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002329static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
2330{
2331 struct snd_soc_pcm_runtime *fe = substream->private_data;
2332 int stream = substream->stream;
2333
2334 /* if FE's runtime_update is already set, we're in race;
2335 * process this trigger later at exit
2336 */
2337 if (fe->dpcm[stream].runtime_update != SND_SOC_DPCM_UPDATE_NO) {
2338 fe->dpcm[stream].trigger_pending = cmd + 1;
2339 return 0; /* delayed, assuming it's successful */
2340 }
2341
2342 /* we're alone, let's trigger */
2343 return dpcm_fe_dai_do_trigger(substream, cmd);
2344}
2345
Liam Girdwood23607022014-01-17 17:03:55 +00002346int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002347{
2348 struct snd_soc_dpcm *dpcm;
2349 int ret = 0;
2350
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002351 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002352
2353 struct snd_soc_pcm_runtime *be = dpcm->be;
2354 struct snd_pcm_substream *be_substream =
2355 snd_soc_dpcm_get_substream(be, stream);
2356
2357 /* is this op for this BE ? */
2358 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2359 continue;
2360
2361 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
Koro Chen95f444d2015-10-28 10:15:34 +08002362 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
Libin Yang5087a8f2019-05-08 10:32:41 +08002363 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND) &&
2364 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Liam Girdwood01d75842012-04-25 12:12:49 +01002365 continue;
2366
Liam Girdwood103d84a2012-11-19 14:39:15 +00002367 dev_dbg(be->dev, "ASoC: prepare BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002368 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002369
2370 ret = soc_pcm_prepare(be_substream);
2371 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002372 dev_err(be->dev, "ASoC: backend prepare failed %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002373 ret);
2374 break;
2375 }
2376
2377 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2378 }
2379 return ret;
2380}
2381
Mark Brown45c0a182012-05-09 21:46:27 +01002382static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002383{
2384 struct snd_soc_pcm_runtime *fe = substream->private_data;
2385 int stream = substream->stream, ret = 0;
2386
2387 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2388
Liam Girdwood103d84a2012-11-19 14:39:15 +00002389 dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002390
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002391 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002392
2393 /* there is no point preparing this FE if there are no BEs */
2394 if (list_empty(&fe->dpcm[stream].be_clients)) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002395 dev_err(fe->dev, "ASoC: no backend DAIs enabled for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002396 fe->dai_link->name);
2397 ret = -EINVAL;
2398 goto out;
2399 }
2400
2401 ret = dpcm_be_dai_prepare(fe, substream->stream);
2402 if (ret < 0)
2403 goto out;
2404
2405 /* call prepare on the frontend */
2406 ret = soc_pcm_prepare(substream);
2407 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002408 dev_err(fe->dev,"ASoC: prepare FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002409 fe->dai_link->name);
2410 goto out;
2411 }
2412
2413 /* run the stream event for each BE */
2414 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
2415 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2416
2417out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002418 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002419 mutex_unlock(&fe->card->mutex);
2420
2421 return ret;
2422}
2423
Liam Girdwood618dae12012-04-25 12:12:51 +01002424static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
2425{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002426 struct snd_pcm_substream *substream =
2427 snd_soc_dpcm_get_substream(fe, stream);
2428 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01002429 int err;
Liam Girdwood01d75842012-04-25 12:12:49 +01002430
Liam Girdwood103d84a2012-11-19 14:39:15 +00002431 dev_dbg(fe->dev, "ASoC: runtime %s close on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002432 stream ? "capture" : "playback", fe->dai_link->name);
2433
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002434 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2435 /* call bespoke trigger - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002436 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002437 fe->dai_link->name);
2438
2439 err = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
2440 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002441 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002442 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002443 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002444 fe->dai_link->name);
2445
2446 err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
2447 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002448 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002449 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002450
2451 err = dpcm_be_dai_hw_free(fe, stream);
2452 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002453 dev_err(fe->dev,"ASoC: hw_free FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002454
2455 err = dpcm_be_dai_shutdown(fe, stream);
2456 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002457 dev_err(fe->dev,"ASoC: shutdown FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002458
2459 /* run the stream event for each BE */
2460 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2461
2462 return 0;
2463}
2464
2465static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
2466{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002467 struct snd_pcm_substream *substream =
2468 snd_soc_dpcm_get_substream(fe, stream);
Liam Girdwood618dae12012-04-25 12:12:51 +01002469 struct snd_soc_dpcm *dpcm;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002470 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01002471 int ret;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002472 unsigned long flags;
Liam Girdwood618dae12012-04-25 12:12:51 +01002473
Liam Girdwood103d84a2012-11-19 14:39:15 +00002474 dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002475 stream ? "capture" : "playback", fe->dai_link->name);
2476
2477 /* Only start the BE if the FE is ready */
2478 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
2479 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE)
2480 return -EINVAL;
2481
2482 /* startup must always be called for new BEs */
2483 ret = dpcm_be_dai_startup(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002484 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002485 goto disconnect;
Liam Girdwood618dae12012-04-25 12:12:51 +01002486
2487 /* keep going if FE state is > open */
2488 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN)
2489 return 0;
2490
2491 ret = dpcm_be_dai_hw_params(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002492 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002493 goto close;
Liam Girdwood618dae12012-04-25 12:12:51 +01002494
2495 /* keep going if FE state is > hw_params */
2496 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS)
2497 return 0;
2498
2499
2500 ret = dpcm_be_dai_prepare(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002501 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002502 goto hw_free;
Liam Girdwood618dae12012-04-25 12:12:51 +01002503
2504 /* run the stream event for each BE */
2505 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2506
2507 /* keep going if FE state is > prepare */
2508 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE ||
2509 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP)
2510 return 0;
2511
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002512 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2513 /* call trigger on the frontend - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002514 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002515 fe->dai_link->name);
Liam Girdwood618dae12012-04-25 12:12:51 +01002516
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002517 ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
2518 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002519 dev_err(fe->dev,"ASoC: bespoke trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002520 goto hw_free;
2521 }
2522 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002523 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002524 fe->dai_link->name);
2525
2526 ret = dpcm_be_dai_trigger(fe, stream,
2527 SNDRV_PCM_TRIGGER_START);
2528 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002529 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002530 goto hw_free;
2531 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002532 }
2533
2534 return 0;
2535
2536hw_free:
2537 dpcm_be_dai_hw_free(fe, stream);
2538close:
2539 dpcm_be_dai_shutdown(fe, stream);
2540disconnect:
2541 /* disconnect any non started BEs */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002542 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002543 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood618dae12012-04-25 12:12:51 +01002544 struct snd_soc_pcm_runtime *be = dpcm->be;
2545 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2546 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2547 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002548 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood618dae12012-04-25 12:12:51 +01002549
2550 return ret;
2551}
2552
2553static int dpcm_run_new_update(struct snd_soc_pcm_runtime *fe, int stream)
2554{
2555 int ret;
2556
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002557 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood618dae12012-04-25 12:12:51 +01002558 ret = dpcm_run_update_startup(fe, stream);
2559 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002560 dev_err(fe->dev, "ASoC: failed to startup some BEs\n");
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002561 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood618dae12012-04-25 12:12:51 +01002562
2563 return ret;
2564}
2565
2566static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream)
2567{
2568 int ret;
2569
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002570 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood618dae12012-04-25 12:12:51 +01002571 ret = dpcm_run_update_shutdown(fe, stream);
2572 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002573 dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n");
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002574 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood618dae12012-04-25 12:12:51 +01002575
2576 return ret;
2577}
2578
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002579static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
2580{
2581 struct snd_soc_dapm_widget_list *list;
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002582 int stream;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002583 int count, paths;
2584
2585 if (!fe->dai_link->dynamic)
2586 return 0;
2587
2588 /* only check active links */
2589 if (!fe->cpu_dai->active)
2590 return 0;
2591
2592 /* DAPM sync will call this to update DSP paths */
2593 dev_dbg(fe->dev, "ASoC: DPCM %s runtime update for FE %s\n",
2594 new ? "new" : "old", fe->dai_link->name);
2595
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002596 for_each_pcm_streams(stream) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002597
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002598 /* skip if FE doesn't have playback/capture capability */
2599 if (!snd_soc_dai_stream_valid(fe->cpu_dai, stream) ||
2600 !snd_soc_dai_stream_valid(fe->codec_dai, stream))
2601 continue;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002602
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002603 /* skip if FE isn't currently playing/capturing */
2604 if (!fe->cpu_dai->stream_active[stream] ||
2605 !fe->codec_dai->stream_active[stream])
2606 continue;
2607
2608 paths = dpcm_path_get(fe, stream, &list);
2609 if (paths < 0) {
2610 dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
2611 fe->dai_link->name,
2612 stream == SNDRV_PCM_STREAM_PLAYBACK ?
2613 "playback" : "capture");
2614 return paths;
2615 }
2616
2617 /* update any playback/capture paths */
2618 count = dpcm_process_paths(fe, stream, &list, new);
2619 if (count) {
2620 if (new)
2621 dpcm_run_new_update(fe, stream);
2622 else
2623 dpcm_run_old_update(fe, stream);
2624
2625 dpcm_clear_pending_state(fe, stream);
2626 dpcm_be_disconnect(fe, stream);
2627 }
2628
2629 dpcm_path_put(&list);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002630 }
2631
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002632 return 0;
2633}
2634
Liam Girdwood618dae12012-04-25 12:12:51 +01002635/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
2636 * any DAI links.
2637 */
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002638int soc_dpcm_runtime_update(struct snd_soc_card *card)
Liam Girdwood618dae12012-04-25 12:12:51 +01002639{
Mengdong Lin1a497982015-11-18 02:34:11 -05002640 struct snd_soc_pcm_runtime *fe;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002641 int ret = 0;
Liam Girdwood618dae12012-04-25 12:12:51 +01002642
Liam Girdwood618dae12012-04-25 12:12:51 +01002643 mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002644 /* shutdown all old paths first */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002645 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002646 ret = soc_dpcm_fe_runtime_update(fe, 0);
2647 if (ret)
2648 goto out;
Liam Girdwood618dae12012-04-25 12:12:51 +01002649 }
2650
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002651 /* bring new paths up */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002652 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002653 ret = soc_dpcm_fe_runtime_update(fe, 1);
2654 if (ret)
2655 goto out;
2656 }
2657
2658out:
Liam Girdwood618dae12012-04-25 12:12:51 +01002659 mutex_unlock(&card->mutex);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002660 return ret;
Liam Girdwood618dae12012-04-25 12:12:51 +01002661}
Liam Girdwood01d75842012-04-25 12:12:49 +01002662
Mark Brown45c0a182012-05-09 21:46:27 +01002663static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002664{
2665 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
2666 struct snd_soc_dpcm *dpcm;
2667 struct snd_soc_dapm_widget_list *list;
2668 int ret;
2669 int stream = fe_substream->stream;
2670
2671 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2672 fe->dpcm[stream].runtime = fe_substream->runtime;
2673
Qiao Zhou8f70e512014-09-10 17:54:07 +08002674 ret = dpcm_path_get(fe, stream, &list);
2675 if (ret < 0) {
Kuninori Morimotocae06eb2020-02-17 17:28:11 +09002676 goto open_end;
Qiao Zhou8f70e512014-09-10 17:54:07 +08002677 } else if (ret == 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002678 dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002679 fe->dai_link->name, stream ? "capture" : "playback");
Liam Girdwood01d75842012-04-25 12:12:49 +01002680 }
2681
2682 /* calculate valid and active FE <-> BE dpcms */
2683 dpcm_process_paths(fe, stream, &list, 1);
2684
2685 ret = dpcm_fe_dai_startup(fe_substream);
2686 if (ret < 0) {
2687 /* clean up all links */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002688 for_each_dpcm_be(fe, stream, dpcm)
Liam Girdwood01d75842012-04-25 12:12:49 +01002689 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2690
2691 dpcm_be_disconnect(fe, stream);
2692 fe->dpcm[stream].runtime = NULL;
2693 }
2694
2695 dpcm_clear_pending_state(fe, stream);
2696 dpcm_path_put(&list);
Kuninori Morimotocae06eb2020-02-17 17:28:11 +09002697open_end:
Liam Girdwood01d75842012-04-25 12:12:49 +01002698 mutex_unlock(&fe->card->mutex);
2699 return ret;
2700}
2701
Mark Brown45c0a182012-05-09 21:46:27 +01002702static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002703{
2704 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
2705 struct snd_soc_dpcm *dpcm;
2706 int stream = fe_substream->stream, ret;
2707
2708 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2709 ret = dpcm_fe_dai_shutdown(fe_substream);
2710
2711 /* mark FE's links ready to prune */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002712 for_each_dpcm_be(fe, stream, dpcm)
Liam Girdwood01d75842012-04-25 12:12:49 +01002713 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2714
2715 dpcm_be_disconnect(fe, stream);
2716
2717 fe->dpcm[stream].runtime = NULL;
2718 mutex_unlock(&fe->card->mutex);
2719 return ret;
2720}
2721
Liam Girdwoodddee6272011-06-09 14:45:53 +01002722/* create a new pcm */
2723int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
2724{
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002725 struct snd_soc_dai *codec_dai;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002726 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto2b544dd2019-10-15 12:59:31 +09002727 struct snd_soc_component *component;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002728 struct snd_pcm *pcm;
2729 char new_name[64];
2730 int ret = 0, playback = 0, capture = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002731 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002732
Liam Girdwood01d75842012-04-25 12:12:49 +01002733 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
Liam Girdwood1e9de422014-01-07 17:51:42 +00002734 playback = rtd->dai_link->dpcm_playback;
2735 capture = rtd->dai_link->dpcm_capture;
Liam Girdwood01d75842012-04-25 12:12:49 +01002736 } else {
Jerome Bruneta3420312019-07-25 18:59:47 +02002737 /* Adapt stream for codec2codec links */
Stephan Gerholda4877a62020-02-18 11:38:24 +01002738 int cpu_capture = rtd->dai_link->params ?
2739 SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
2740 int cpu_playback = rtd->dai_link->params ?
2741 SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
Jerome Bruneta3420312019-07-25 18:59:47 +02002742
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00002743 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto467fece2019-07-22 10:36:16 +09002744 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
Stephan Gerholda4877a62020-02-18 11:38:24 +01002745 snd_soc_dai_stream_valid(cpu_dai, cpu_playback))
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002746 playback = 1;
Kuninori Morimoto467fece2019-07-22 10:36:16 +09002747 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
Stephan Gerholda4877a62020-02-18 11:38:24 +01002748 snd_soc_dai_stream_valid(cpu_dai, cpu_capture))
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002749 capture = 1;
2750 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002751 }
Sangsu Parka5002312012-01-02 17:15:10 +09002752
Fabio Estevamd6bead02013-08-29 10:32:13 -03002753 if (rtd->dai_link->playback_only) {
2754 playback = 1;
2755 capture = 0;
2756 }
2757
2758 if (rtd->dai_link->capture_only) {
2759 playback = 0;
2760 capture = 1;
2761 }
2762
Liam Girdwood01d75842012-04-25 12:12:49 +01002763 /* create the PCM */
Jerome Bruneta3420312019-07-25 18:59:47 +02002764 if (rtd->dai_link->params) {
2765 snprintf(new_name, sizeof(new_name), "codec2codec(%s)",
2766 rtd->dai_link->stream_name);
2767
2768 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
2769 playback, capture, &pcm);
2770 } else if (rtd->dai_link->no_pcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002771 snprintf(new_name, sizeof(new_name), "(%s)",
2772 rtd->dai_link->stream_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002773
Liam Girdwood01d75842012-04-25 12:12:49 +01002774 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
2775 playback, capture, &pcm);
2776 } else {
2777 if (rtd->dai_link->dynamic)
2778 snprintf(new_name, sizeof(new_name), "%s (*)",
2779 rtd->dai_link->stream_name);
2780 else
2781 snprintf(new_name, sizeof(new_name), "%s %s-%d",
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002782 rtd->dai_link->stream_name,
2783 (rtd->num_codecs > 1) ?
2784 "multicodec" : rtd->codec_dai->name, num);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002785
Liam Girdwood01d75842012-04-25 12:12:49 +01002786 ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
2787 capture, &pcm);
2788 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01002789 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002790 dev_err(rtd->card->dev, "ASoC: can't create pcm for %s\n",
Liam Girdwood5cb9b742012-07-06 16:54:52 +01002791 rtd->dai_link->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002792 return ret;
2793 }
Liam Girdwood103d84a2012-11-19 14:39:15 +00002794 dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002795
2796 /* DAPM dai link stream work */
Jerome Bruneta3420312019-07-25 18:59:47 +02002797 if (rtd->dai_link->params)
Curtis Malainey4bf2e382019-12-03 09:30:07 -08002798 rtd->close_delayed_work_func = codec2codec_close_delayed_work;
Jerome Bruneta3420312019-07-25 18:59:47 +02002799 else
Kuninori Morimoto83f94a22020-01-10 11:36:17 +09002800 rtd->close_delayed_work_func = snd_soc_close_delayed_work;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002801
Vinod Koul48c76992015-02-12 09:59:53 +05302802 pcm->nonatomic = rtd->dai_link->nonatomic;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002803 rtd->pcm = pcm;
2804 pcm->private_data = rtd;
Liam Girdwood01d75842012-04-25 12:12:49 +01002805
Jerome Bruneta3420312019-07-25 18:59:47 +02002806 if (rtd->dai_link->no_pcm || rtd->dai_link->params) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002807 if (playback)
2808 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
2809 if (capture)
2810 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
2811 goto out;
2812 }
2813
2814 /* ASoC PCM operations */
2815 if (rtd->dai_link->dynamic) {
2816 rtd->ops.open = dpcm_fe_dai_open;
2817 rtd->ops.hw_params = dpcm_fe_dai_hw_params;
2818 rtd->ops.prepare = dpcm_fe_dai_prepare;
2819 rtd->ops.trigger = dpcm_fe_dai_trigger;
2820 rtd->ops.hw_free = dpcm_fe_dai_hw_free;
2821 rtd->ops.close = dpcm_fe_dai_close;
2822 rtd->ops.pointer = soc_pcm_pointer;
2823 } else {
2824 rtd->ops.open = soc_pcm_open;
2825 rtd->ops.hw_params = soc_pcm_hw_params;
2826 rtd->ops.prepare = soc_pcm_prepare;
2827 rtd->ops.trigger = soc_pcm_trigger;
2828 rtd->ops.hw_free = soc_pcm_hw_free;
2829 rtd->ops.close = soc_pcm_close;
2830 rtd->ops.pointer = soc_pcm_pointer;
2831 }
2832
Kuninori Morimoto613fb502020-01-10 11:35:21 +09002833 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto2b544dd2019-10-15 12:59:31 +09002834 const struct snd_soc_component_driver *drv = component->driver;
Kuninori Morimotob8135862017-10-11 01:37:23 +00002835
Takashi Iwai3b1c9522019-11-21 20:07:08 +01002836 if (drv->ioctl)
2837 rtd->ops.ioctl = snd_soc_pcm_component_ioctl;
Takashi Iwai1e5ddb62019-11-21 20:07:09 +01002838 if (drv->sync_stop)
2839 rtd->ops.sync_stop = snd_soc_pcm_component_sync_stop;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002840 if (drv->copy_user)
Kuninori Morimoto82d81f52019-07-26 13:51:56 +09002841 rtd->ops.copy_user = snd_soc_pcm_component_copy_user;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002842 if (drv->page)
Kuninori Morimoto9c712e42019-07-26 13:52:00 +09002843 rtd->ops.page = snd_soc_pcm_component_page;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002844 if (drv->mmap)
Kuninori Morimoto205875e2019-07-26 13:52:04 +09002845 rtd->ops.mmap = snd_soc_pcm_component_mmap;
Kuninori Morimotob8135862017-10-11 01:37:23 +00002846 }
2847
Liam Girdwoodddee6272011-06-09 14:45:53 +01002848 if (playback)
Liam Girdwood01d75842012-04-25 12:12:49 +01002849 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002850
2851 if (capture)
Liam Girdwood01d75842012-04-25 12:12:49 +01002852 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002853
Kuninori Morimotob2b2afb2019-11-18 10:50:32 +09002854 ret = snd_soc_pcm_component_new(rtd);
Kuninori Morimoto74842912019-07-26 13:52:08 +09002855 if (ret < 0) {
2856 dev_err(rtd->dev, "ASoC: pcm constructor failed: %d\n", ret);
2857 return ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002858 }
Johan Hovoldc641e5b2017-07-12 17:55:29 +02002859
Takashi Iwai3d21ef02019-01-11 15:58:39 +01002860 pcm->no_device_suspend = true;
Liam Girdwood01d75842012-04-25 12:12:49 +01002861out:
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002862 dev_info(rtd->card->dev, "%s <-> %s mapping ok\n",
2863 (rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name,
2864 cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002865 return ret;
2866}
Liam Girdwood01d75842012-04-25 12:12:49 +01002867
2868/* is the current PCM operation for this FE ? */
2869int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream)
2870{
2871 if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE)
2872 return 1;
2873 return 0;
2874}
2875EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update);
2876
2877/* is the current PCM operation for this BE ? */
2878int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
2879 struct snd_soc_pcm_runtime *be, int stream)
2880{
2881 if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) ||
2882 ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) &&
2883 be->dpcm[stream].runtime_update))
2884 return 1;
2885 return 0;
2886}
2887EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update);
2888
2889/* get the substream for this BE */
2890struct snd_pcm_substream *
2891 snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream)
2892{
2893 return be->pcm->streams[stream].substream;
2894}
2895EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream);
2896
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002897static int snd_soc_dpcm_check_state(struct snd_soc_pcm_runtime *fe,
2898 struct snd_soc_pcm_runtime *be,
2899 int stream,
2900 const enum snd_soc_dpcm_state *states,
2901 int num_states)
Liam Girdwood01d75842012-04-25 12:12:49 +01002902{
2903 struct snd_soc_dpcm *dpcm;
2904 int state;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002905 int ret = 1;
2906 unsigned long flags;
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002907 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01002908
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002909 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00002910 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002911
2912 if (dpcm->fe == fe)
2913 continue;
2914
2915 state = dpcm->fe->dpcm[stream].state;
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002916 for (i = 0; i < num_states; i++) {
2917 if (state == states[i]) {
2918 ret = 0;
2919 break;
2920 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002921 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002922 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002923 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01002924
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002925 /* it's safe to do this BE DAI */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002926 return ret;
Liam Girdwood01d75842012-04-25 12:12:49 +01002927}
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002928
2929/*
2930 * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE
2931 * are not running, paused or suspended for the specified stream direction.
2932 */
2933int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
2934 struct snd_soc_pcm_runtime *be, int stream)
2935{
2936 const enum snd_soc_dpcm_state state[] = {
2937 SND_SOC_DPCM_STATE_START,
2938 SND_SOC_DPCM_STATE_PAUSED,
2939 SND_SOC_DPCM_STATE_SUSPEND,
2940 };
2941
2942 return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
2943}
Liam Girdwood01d75842012-04-25 12:12:49 +01002944EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop);
2945
2946/*
2947 * We can only change hw params a BE DAI if any of it's FE are not prepared,
2948 * running, paused or suspended for the specified stream direction.
2949 */
2950int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
2951 struct snd_soc_pcm_runtime *be, int stream)
2952{
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002953 const enum snd_soc_dpcm_state state[] = {
2954 SND_SOC_DPCM_STATE_START,
2955 SND_SOC_DPCM_STATE_PAUSED,
2956 SND_SOC_DPCM_STATE_SUSPEND,
2957 SND_SOC_DPCM_STATE_PREPARE,
2958 };
Liam Girdwood01d75842012-04-25 12:12:49 +01002959
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002960 return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
Liam Girdwood01d75842012-04-25 12:12:49 +01002961}
2962EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01002963
2964#ifdef CONFIG_DEBUG_FS
Lars-Peter Clausen852801412016-11-22 11:29:14 +01002965static const char *dpcm_state_string(enum snd_soc_dpcm_state state)
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01002966{
2967 switch (state) {
2968 case SND_SOC_DPCM_STATE_NEW:
2969 return "new";
2970 case SND_SOC_DPCM_STATE_OPEN:
2971 return "open";
2972 case SND_SOC_DPCM_STATE_HW_PARAMS:
2973 return "hw_params";
2974 case SND_SOC_DPCM_STATE_PREPARE:
2975 return "prepare";
2976 case SND_SOC_DPCM_STATE_START:
2977 return "start";
2978 case SND_SOC_DPCM_STATE_STOP:
2979 return "stop";
2980 case SND_SOC_DPCM_STATE_SUSPEND:
2981 return "suspend";
2982 case SND_SOC_DPCM_STATE_PAUSED:
2983 return "paused";
2984 case SND_SOC_DPCM_STATE_HW_FREE:
2985 return "hw_free";
2986 case SND_SOC_DPCM_STATE_CLOSE:
2987 return "close";
2988 }
2989
2990 return "unknown";
2991}
2992
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01002993static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
2994 int stream, char *buf, size_t size)
2995{
2996 struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params;
2997 struct snd_soc_dpcm *dpcm;
2998 ssize_t offset = 0;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002999 unsigned long flags;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003000
3001 /* FE state */
3002 offset += snprintf(buf + offset, size - offset,
3003 "[%s - %s]\n", fe->dai_link->name,
3004 stream ? "Capture" : "Playback");
3005
3006 offset += snprintf(buf + offset, size - offset, "State: %s\n",
3007 dpcm_state_string(fe->dpcm[stream].state));
3008
3009 if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
3010 (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
3011 offset += snprintf(buf + offset, size - offset,
3012 "Hardware Params: "
3013 "Format = %s, Channels = %d, Rate = %d\n",
3014 snd_pcm_format_name(params_format(params)),
3015 params_channels(params),
3016 params_rate(params));
3017
3018 /* BEs state */
3019 offset += snprintf(buf + offset, size - offset, "Backends:\n");
3020
3021 if (list_empty(&fe->dpcm[stream].be_clients)) {
3022 offset += snprintf(buf + offset, size - offset,
3023 " No active DSP links\n");
3024 goto out;
3025 }
3026
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003027 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00003028 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003029 struct snd_soc_pcm_runtime *be = dpcm->be;
3030 params = &dpcm->hw_params;
3031
3032 offset += snprintf(buf + offset, size - offset,
3033 "- %s\n", be->dai_link->name);
3034
3035 offset += snprintf(buf + offset, size - offset,
3036 " State: %s\n",
3037 dpcm_state_string(be->dpcm[stream].state));
3038
3039 if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
3040 (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
3041 offset += snprintf(buf + offset, size - offset,
3042 " Hardware Params: "
3043 "Format = %s, Channels = %d, Rate = %d\n",
3044 snd_pcm_format_name(params_format(params)),
3045 params_channels(params),
3046 params_rate(params));
3047 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003048 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003049out:
3050 return offset;
3051}
3052
3053static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf,
3054 size_t count, loff_t *ppos)
3055{
3056 struct snd_soc_pcm_runtime *fe = file->private_data;
3057 ssize_t out_count = PAGE_SIZE, offset = 0, ret = 0;
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09003058 int stream;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003059 char *buf;
3060
3061 buf = kmalloc(out_count, GFP_KERNEL);
3062 if (!buf)
3063 return -ENOMEM;
3064
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09003065 for_each_pcm_streams(stream)
3066 if (snd_soc_dai_stream_valid(fe->cpu_dai, stream))
3067 offset += dpcm_show_state(fe, stream,
3068 buf + offset,
3069 out_count - offset);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003070
Liam Girdwoodf57b8482012-04-27 11:33:46 +01003071 ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003072
Liam Girdwoodf57b8482012-04-27 11:33:46 +01003073 kfree(buf);
3074 return ret;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003075}
3076
3077static const struct file_operations dpcm_state_fops = {
Liam Girdwoodf57b8482012-04-27 11:33:46 +01003078 .open = simple_open,
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003079 .read = dpcm_state_read_file,
3080 .llseek = default_llseek,
3081};
3082
Lars-Peter Clausen2e55b902015-04-09 10:52:37 +02003083void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003084{
Mark Brownb3bba9a2012-05-08 10:33:47 +01003085 if (!rtd->dai_link)
Lars-Peter Clausen2e55b902015-04-09 10:52:37 +02003086 return;
Mark Brownb3bba9a2012-05-08 10:33:47 +01003087
Kuninori Morimoto596becd2019-08-07 10:31:36 +09003088 if (!rtd->dai_link->dynamic)
3089 return;
3090
Lars-Peter Clausen6553bf062015-04-09 10:52:38 +02003091 if (!rtd->card->debugfs_card_root)
3092 return;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003093
3094 rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name,
3095 rtd->card->debugfs_card_root);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003096
Fabio Estevamf1e3f402017-07-29 11:40:55 -03003097 debugfs_create_file("state", 0444, rtd->debugfs_dpcm_root,
3098 rtd, &dpcm_state_fops);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003099}
3100#endif