blob: dcab9527ba3d7ead6b179802d871cbb7da397940 [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>
Kuninori Morimotoa5e6c102020-05-25 09:57:19 +090027#include <sound/soc-link.h>
Liam Girdwoodddee6272011-06-09 14:45:53 +010028#include <sound/initval.h>
29
Liam Girdwood01d75842012-04-25 12:12:49 +010030#define DPCM_MAX_BE_USERS 8
31
Kuninori Morimotoc3212822020-02-19 15:56:57 +090032#ifdef CONFIG_DEBUG_FS
33static const char *dpcm_state_string(enum snd_soc_dpcm_state state)
34{
35 switch (state) {
36 case SND_SOC_DPCM_STATE_NEW:
37 return "new";
38 case SND_SOC_DPCM_STATE_OPEN:
39 return "open";
40 case SND_SOC_DPCM_STATE_HW_PARAMS:
41 return "hw_params";
42 case SND_SOC_DPCM_STATE_PREPARE:
43 return "prepare";
44 case SND_SOC_DPCM_STATE_START:
45 return "start";
46 case SND_SOC_DPCM_STATE_STOP:
47 return "stop";
48 case SND_SOC_DPCM_STATE_SUSPEND:
49 return "suspend";
50 case SND_SOC_DPCM_STATE_PAUSED:
51 return "paused";
52 case SND_SOC_DPCM_STATE_HW_FREE:
53 return "hw_free";
54 case SND_SOC_DPCM_STATE_CLOSE:
55 return "close";
56 }
57
58 return "unknown";
59}
60
61static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
62 int stream, char *buf, size_t size)
63{
64 struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params;
65 struct snd_soc_dpcm *dpcm;
66 ssize_t offset = 0;
67 unsigned long flags;
68
69 /* FE state */
Takashi Iwaid0c9abb2020-03-10 17:36:25 +010070 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +090071 "[%s - %s]\n", fe->dai_link->name,
72 stream ? "Capture" : "Playback");
73
Takashi Iwaid0c9abb2020-03-10 17:36:25 +010074 offset += scnprintf(buf + offset, size - offset, "State: %s\n",
Kuninori Morimotoc3212822020-02-19 15:56:57 +090075 dpcm_state_string(fe->dpcm[stream].state));
76
77 if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
78 (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
Takashi Iwaid0c9abb2020-03-10 17:36:25 +010079 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +090080 "Hardware Params: "
81 "Format = %s, Channels = %d, Rate = %d\n",
82 snd_pcm_format_name(params_format(params)),
83 params_channels(params),
84 params_rate(params));
85
86 /* BEs state */
Takashi Iwaid0c9abb2020-03-10 17:36:25 +010087 offset += scnprintf(buf + offset, size - offset, "Backends:\n");
Kuninori Morimotoc3212822020-02-19 15:56:57 +090088
89 if (list_empty(&fe->dpcm[stream].be_clients)) {
Takashi Iwaid0c9abb2020-03-10 17:36:25 +010090 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +090091 " No active DSP links\n");
92 goto out;
93 }
94
95 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
96 for_each_dpcm_be(fe, stream, dpcm) {
97 struct snd_soc_pcm_runtime *be = dpcm->be;
98 params = &dpcm->hw_params;
99
Takashi Iwaid0c9abb2020-03-10 17:36:25 +0100100 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900101 "- %s\n", be->dai_link->name);
102
Takashi Iwaid0c9abb2020-03-10 17:36:25 +0100103 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900104 " State: %s\n",
105 dpcm_state_string(be->dpcm[stream].state));
106
107 if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
108 (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
Takashi Iwaid0c9abb2020-03-10 17:36:25 +0100109 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900110 " Hardware Params: "
111 "Format = %s, Channels = %d, Rate = %d\n",
112 snd_pcm_format_name(params_format(params)),
113 params_channels(params),
114 params_rate(params));
115 }
116 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
117out:
118 return offset;
119}
120
121static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf,
122 size_t count, loff_t *ppos)
123{
124 struct snd_soc_pcm_runtime *fe = file->private_data;
125 ssize_t out_count = PAGE_SIZE, offset = 0, ret = 0;
126 int stream;
127 char *buf;
128
Bard Liao6e1276a2020-02-25 21:39:16 +0800129 if (fe->num_cpus > 1) {
130 dev_err(fe->dev,
131 "%s doesn't support Multi CPU yet\n", __func__);
132 return -EINVAL;
133 }
134
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900135 buf = kmalloc(out_count, GFP_KERNEL);
136 if (!buf)
137 return -ENOMEM;
138
139 for_each_pcm_streams(stream)
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900140 if (snd_soc_dai_stream_valid(asoc_rtd_to_cpu(fe, 0), stream))
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900141 offset += dpcm_show_state(fe, stream,
142 buf + offset,
143 out_count - offset);
144
145 ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
146
147 kfree(buf);
148 return ret;
149}
150
151static const struct file_operations dpcm_state_fops = {
152 .open = simple_open,
153 .read = dpcm_state_read_file,
154 .llseek = default_llseek,
155};
156
157void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
158{
159 if (!rtd->dai_link)
160 return;
161
162 if (!rtd->dai_link->dynamic)
163 return;
164
165 if (!rtd->card->debugfs_card_root)
166 return;
167
168 rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name,
169 rtd->card->debugfs_card_root);
170
171 debugfs_create_file("state", 0444, rtd->debugfs_dpcm_root,
172 rtd, &dpcm_state_fops);
173}
Kuninori Morimoto154dae82020-02-19 15:57:06 +0900174
175static void dpcm_create_debugfs_state(struct snd_soc_dpcm *dpcm, int stream)
176{
177 char *name;
178
179 name = kasprintf(GFP_KERNEL, "%s:%s", dpcm->be->dai_link->name,
180 stream ? "capture" : "playback");
181 if (name) {
182 dpcm->debugfs_state = debugfs_create_dir(
183 name, dpcm->fe->debugfs_dpcm_root);
184 debugfs_create_u32("state", 0644, dpcm->debugfs_state,
185 &dpcm->state);
186 kfree(name);
187 }
188}
189
190static void dpcm_remove_debugfs_state(struct snd_soc_dpcm *dpcm)
191{
192 debugfs_remove_recursive(dpcm->debugfs_state);
193}
194
195#else
196static inline void dpcm_create_debugfs_state(struct snd_soc_dpcm *dpcm,
197 int stream)
198{
199}
200
201static inline void dpcm_remove_debugfs_state(struct snd_soc_dpcm *dpcm)
202{
203}
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900204#endif
205
Kuninori Morimotod9051d82020-05-15 09:46:21 +0900206/**
207 * snd_soc_runtime_action() - Increment/Decrement active count for
208 * PCM runtime components
209 * @rtd: ASoC PCM runtime that is activated
210 * @stream: Direction of the PCM stream
Colton Lewisb6d6e9e2020-06-26 05:40:24 +0000211 * @action: Activate stream if 1. Deactivate if -1.
Kuninori Morimotod9051d82020-05-15 09:46:21 +0900212 *
213 * Increments/Decrements the active count for all the DAIs and components
214 * attached to a PCM runtime.
215 * Should typically be called when a stream is opened.
216 *
217 * Must be called with the rtd->card->pcm_mutex being held
218 */
219void snd_soc_runtime_action(struct snd_soc_pcm_runtime *rtd,
220 int stream, int action)
Kuninori Morimoto7a5aaba2020-02-10 12:14:12 +0900221{
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900222 struct snd_soc_dai *dai;
Kuninori Morimoto7a5aaba2020-02-10 12:14:12 +0900223 int i;
224
225 lockdep_assert_held(&rtd->card->pcm_mutex);
226
Kuninori Morimotodc829102020-05-15 09:46:27 +0900227 for_each_rtd_dais(rtd, i, dai)
228 snd_soc_dai_action(dai, stream, action);
Kuninori Morimoto7a5aaba2020-02-10 12:14:12 +0900229}
Kuninori Morimotod9051d82020-05-15 09:46:21 +0900230EXPORT_SYMBOL_GPL(snd_soc_runtime_action);
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100231
232/**
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100233 * snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay
234 * @rtd: The ASoC PCM runtime that should be checked.
235 *
236 * This function checks whether the power down delay should be ignored for a
237 * specific PCM runtime. Returns true if the delay is 0, if it the DAI link has
238 * been configured to ignore the delay, or if none of the components benefits
239 * from having the delay.
240 */
241bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
242{
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000243 struct snd_soc_component *component;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200244 bool ignore = true;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900245 int i;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200246
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100247 if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
248 return true;
249
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900250 for_each_rtd_components(rtd, i, component)
Kuninori Morimoto72c38182018-01-19 05:21:19 +0000251 ignore &= !component->driver->use_pmdown_time;
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000252
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000253 return ignore;
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100254}
255
256/**
Lars-Peter Clausen90996f42013-05-14 11:05:30 +0200257 * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
258 * @substream: the pcm substream
259 * @hw: the hardware parameters
260 *
261 * Sets the substream runtime hardware parameters.
262 */
263int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
264 const struct snd_pcm_hardware *hw)
265{
266 struct snd_pcm_runtime *runtime = substream->runtime;
267 runtime->hw.info = hw->info;
268 runtime->hw.formats = hw->formats;
269 runtime->hw.period_bytes_min = hw->period_bytes_min;
270 runtime->hw.period_bytes_max = hw->period_bytes_max;
271 runtime->hw.periods_min = hw->periods_min;
272 runtime->hw.periods_max = hw->periods_max;
273 runtime->hw.buffer_bytes_max = hw->buffer_bytes_max;
274 runtime->hw.fifo_size = hw->fifo_size;
275 return 0;
276}
277EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
278
Liam Girdwood01d75842012-04-25 12:12:49 +0100279/* DPCM stream event, send event to FE and all active BEs. */
Liam Girdwood23607022014-01-17 17:03:55 +0000280int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
Liam Girdwood01d75842012-04-25 12:12:49 +0100281 int event)
282{
283 struct snd_soc_dpcm *dpcm;
284
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +0000285 for_each_dpcm_be(fe, dir, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +0100286
287 struct snd_soc_pcm_runtime *be = dpcm->be;
288
Liam Girdwood103d84a2012-11-19 14:39:15 +0000289 dev_dbg(be->dev, "ASoC: BE %s event %d dir %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +0100290 be->dai_link->name, event, dir);
291
Banajit Goswamib1cd2e32017-07-14 23:15:05 -0700292 if ((event == SND_SOC_DAPM_STREAM_STOP) &&
293 (be->dpcm[dir].users >= 1))
294 continue;
295
Liam Girdwood01d75842012-04-25 12:12:49 +0100296 snd_soc_dapm_stream_event(be, dir, event);
297 }
298
299 snd_soc_dapm_stream_event(fe, dir, event);
300
301 return 0;
302}
303
Dong Aisheng17841022011-08-29 17:15:14 +0800304static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
305 struct snd_soc_dai *soc_dai)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100306{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900307 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100308 int ret;
309
Nicolin Chen3635bf02013-11-13 18:56:24 +0800310 if (soc_dai->rate && (soc_dai->driver->symmetric_rates ||
311 rtd->dai_link->symmetric_rates)) {
312 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n",
313 soc_dai->rate);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100314
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200315 ret = snd_pcm_hw_constraint_single(substream->runtime,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800316 SNDRV_PCM_HW_PARAM_RATE,
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200317 soc_dai->rate);
Nicolin Chen3635bf02013-11-13 18:56:24 +0800318 if (ret < 0) {
319 dev_err(soc_dai->dev,
320 "ASoC: Unable to apply rate constraint: %d\n",
321 ret);
322 return ret;
323 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100324 }
325
Nicolin Chen3635bf02013-11-13 18:56:24 +0800326 if (soc_dai->channels && (soc_dai->driver->symmetric_channels ||
327 rtd->dai_link->symmetric_channels)) {
328 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d channel(s)\n",
329 soc_dai->channels);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100330
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200331 ret = snd_pcm_hw_constraint_single(substream->runtime,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800332 SNDRV_PCM_HW_PARAM_CHANNELS,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800333 soc_dai->channels);
334 if (ret < 0) {
335 dev_err(soc_dai->dev,
336 "ASoC: Unable to apply channel symmetry constraint: %d\n",
337 ret);
338 return ret;
339 }
340 }
341
342 if (soc_dai->sample_bits && (soc_dai->driver->symmetric_samplebits ||
343 rtd->dai_link->symmetric_samplebits)) {
344 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d sample bits\n",
345 soc_dai->sample_bits);
346
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200347 ret = snd_pcm_hw_constraint_single(substream->runtime,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800348 SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800349 soc_dai->sample_bits);
350 if (ret < 0) {
351 dev_err(soc_dai->dev,
352 "ASoC: Unable to apply sample bits symmetry constraint: %d\n",
353 ret);
354 return ret;
355 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100356 }
357
358 return 0;
359}
360
Nicolin Chen3635bf02013-11-13 18:56:24 +0800361static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
362 struct snd_pcm_hw_params *params)
363{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900364 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900365 struct snd_soc_dai *dai;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800366 struct snd_soc_dai *cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200367 unsigned int rate, channels, sample_bits, symmetry, i;
Nicolin Chen3635bf02013-11-13 18:56:24 +0800368
369 rate = params_rate(params);
370 channels = params_channels(params);
371 sample_bits = snd_pcm_format_physical_width(params_format(params));
372
373 /* reject unmatched parameters when applying symmetry */
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800374 symmetry = rtd->dai_link->symmetric_rates;
375
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900376 for_each_rtd_cpu_dais(rtd, i, dai)
377 symmetry |= dai->driver->symmetric_rates;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200378
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800379 if (symmetry) {
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900380 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800381 if (cpu_dai->rate && cpu_dai->rate != rate) {
382 dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n",
383 cpu_dai->rate, rate);
384 return -EINVAL;
385 }
386 }
Nicolin Chen3635bf02013-11-13 18:56:24 +0800387 }
388
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800389 symmetry = rtd->dai_link->symmetric_channels;
390
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900391 for_each_rtd_dais(rtd, i, dai)
392 symmetry |= dai->driver->symmetric_channels;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200393
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800394 if (symmetry) {
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900395 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800396 if (cpu_dai->channels &&
397 cpu_dai->channels != channels) {
398 dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n",
399 cpu_dai->channels, channels);
400 return -EINVAL;
401 }
402 }
Nicolin Chen3635bf02013-11-13 18:56:24 +0800403 }
404
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800405 symmetry = rtd->dai_link->symmetric_samplebits;
406
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900407 for_each_rtd_dais(rtd, i, dai)
408 symmetry |= dai->driver->symmetric_samplebits;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200409
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800410 if (symmetry) {
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900411 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800412 if (cpu_dai->sample_bits &&
413 cpu_dai->sample_bits != sample_bits) {
414 dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n",
415 cpu_dai->sample_bits, sample_bits);
416 return -EINVAL;
417 }
418 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100419 }
420
421 return 0;
422}
423
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100424static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream)
425{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900426 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100427 struct snd_soc_dai_link *link = rtd->dai_link;
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900428 struct snd_soc_dai *dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200429 unsigned int symmetry, i;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100430
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800431 symmetry = link->symmetric_rates ||
432 link->symmetric_channels ||
433 link->symmetric_samplebits;
434
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900435 for_each_rtd_dais(rtd, i, dai)
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800436 symmetry = symmetry ||
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900437 dai->driver->symmetric_rates ||
438 dai->driver->symmetric_channels ||
439 dai->driver->symmetric_samplebits;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200440
441 return symmetry;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100442}
443
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200444static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits)
Mark Brown58ba9b22012-01-16 18:38:51 +0000445{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900446 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Takashi Iwaic6068d32014-12-31 17:10:34 +0100447 int ret;
Mark Brown58ba9b22012-01-16 18:38:51 +0000448
449 if (!bits)
450 return;
451
Lars-Peter Clausen0e2a3752014-12-29 18:43:38 +0100452 ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 0, bits);
453 if (ret != 0)
454 dev_warn(rtd->dev, "ASoC: Failed to set MSB %d: %d\n",
455 bits, ret);
Mark Brown58ba9b22012-01-16 18:38:51 +0000456}
457
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200458static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200459{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900460 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800461 struct snd_soc_dai *cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200462 struct snd_soc_dai *codec_dai;
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900463 struct snd_soc_pcm_stream *pcm_codec, *pcm_cpu;
464 int stream = substream->stream;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200465 int i;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800466 unsigned int bits = 0, cpu_bits = 0;
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200467
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900468 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900469 pcm_codec = snd_soc_dai_get_pcm_stream(codec_dai, stream);
470
471 if (pcm_codec->sig_bits == 0) {
472 bits = 0;
473 break;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200474 }
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900475 bits = max(pcm_codec->sig_bits, bits);
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200476 }
477
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900478 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800479 pcm_cpu = snd_soc_dai_get_pcm_stream(cpu_dai, stream);
480
481 if (pcm_cpu->sig_bits == 0) {
482 cpu_bits = 0;
483 break;
484 }
485 cpu_bits = max(pcm_cpu->sig_bits, cpu_bits);
486 }
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900487
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200488 soc_pcm_set_msb(substream, bits);
489 soc_pcm_set_msb(substream, cpu_bits);
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200490}
491
Samuel Holland5854a462020-03-04 23:11:42 -0600492/**
493 * snd_soc_runtime_calc_hw() - Calculate hw limits for a PCM stream
494 * @rtd: ASoC PCM runtime
495 * @hw: PCM hardware parameters (output)
496 * @stream: Direction of the PCM stream
497 *
498 * Calculates the subset of stream parameters supported by all DAIs
499 * associated with the PCM stream.
500 */
501int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd,
502 struct snd_pcm_hardware *hw, int stream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200503{
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000504 struct snd_soc_dai *codec_dai;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800505 struct snd_soc_dai *cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200506 struct snd_soc_pcm_stream *codec_stream;
507 struct snd_soc_pcm_stream *cpu_stream;
508 unsigned int chan_min = 0, chan_max = UINT_MAX;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800509 unsigned int cpu_chan_min = 0, cpu_chan_max = UINT_MAX;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200510 unsigned int rate_min = 0, rate_max = UINT_MAX;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800511 unsigned int cpu_rate_min = 0, cpu_rate_max = UINT_MAX;
512 unsigned int rates = UINT_MAX, cpu_rates = UINT_MAX;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200513 u64 formats = ULLONG_MAX;
514 int i;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100515
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800516 /* first calculate min/max only for CPUs in the DAI link */
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900517 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800518
519 /*
520 * Skip CPUs which don't support the current stream type.
521 * Otherwise, since the rate, channel, and format values will
522 * zero in that case, we would have no usable settings left,
523 * causing the resulting setup to fail.
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800524 */
Samuel Holland5854a462020-03-04 23:11:42 -0600525 if (!snd_soc_dai_stream_valid(cpu_dai, stream))
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800526 continue;
527
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800528 cpu_stream = snd_soc_dai_get_pcm_stream(cpu_dai, stream);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100529
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800530 cpu_chan_min = max(cpu_chan_min, cpu_stream->channels_min);
531 cpu_chan_max = min(cpu_chan_max, cpu_stream->channels_max);
532 cpu_rate_min = max(cpu_rate_min, cpu_stream->rate_min);
533 cpu_rate_max = min_not_zero(cpu_rate_max, cpu_stream->rate_max);
534 formats &= cpu_stream->formats;
535 cpu_rates = snd_pcm_rate_mask_intersect(cpu_stream->rates,
536 cpu_rates);
537 }
538
539 /* second calculate min/max only for CODECs in the DAI link */
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900540 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200541
542 /*
543 * Skip CODECs which don't support the current stream type.
544 * Otherwise, since the rate, channel, and format values will
545 * zero in that case, we would have no usable settings left,
546 * causing the resulting setup to fail.
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200547 */
Kuninori Morimoto25c2f512020-02-27 10:54:38 +0900548 if (!snd_soc_dai_stream_valid(codec_dai, stream))
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200549 continue;
550
Kuninori Morimotoacf253c2020-02-19 15:56:30 +0900551 codec_stream = snd_soc_dai_get_pcm_stream(codec_dai, stream);
552
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200553 chan_min = max(chan_min, codec_stream->channels_min);
554 chan_max = min(chan_max, codec_stream->channels_max);
555 rate_min = max(rate_min, codec_stream->rate_min);
556 rate_max = min_not_zero(rate_max, codec_stream->rate_max);
557 formats &= codec_stream->formats;
558 rates = snd_pcm_rate_mask_intersect(codec_stream->rates, rates);
559 }
560
Samuel Holland5854a462020-03-04 23:11:42 -0600561 /* Verify both a valid CPU DAI and a valid CODEC DAI were found */
562 if (!chan_min || !cpu_chan_min)
563 return -EINVAL;
564
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200565 /*
566 * chan min/max cannot be enforced if there are multiple CODEC DAIs
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800567 * connected to CPU DAI(s), use CPU DAI's directly and let
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200568 * channel allocation be fixed up later
569 */
570 if (rtd->num_codecs > 1) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800571 chan_min = cpu_chan_min;
572 chan_max = cpu_chan_max;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200573 }
574
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800575 /* finally find a intersection between CODECs and CPUs */
576 hw->channels_min = max(chan_min, cpu_chan_min);
577 hw->channels_max = min(chan_max, cpu_chan_max);
Samuel Holland5854a462020-03-04 23:11:42 -0600578 hw->formats = formats;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800579 hw->rates = snd_pcm_rate_mask_intersect(rates, cpu_rates);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100580
Samuel Holland5854a462020-03-04 23:11:42 -0600581 snd_pcm_hw_limit_rates(hw);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100582
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800583 hw->rate_min = max(hw->rate_min, cpu_rate_min);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200584 hw->rate_min = max(hw->rate_min, rate_min);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800585 hw->rate_max = min_not_zero(hw->rate_max, cpu_rate_max);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200586 hw->rate_max = min_not_zero(hw->rate_max, rate_max);
Samuel Holland5854a462020-03-04 23:11:42 -0600587
588 return 0;
589}
590EXPORT_SYMBOL_GPL(snd_soc_runtime_calc_hw);
591
592static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
593{
594 struct snd_pcm_hardware *hw = &substream->runtime->hw;
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900595 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Samuel Holland5854a462020-03-04 23:11:42 -0600596 u64 formats = hw->formats;
597
598 /*
599 * At least one CPU and one CODEC should match. Otherwise, we should
600 * have bailed out on a higher level, since there would be no CPU or
601 * CODEC to support the transfer direction in that case.
602 */
603 snd_soc_runtime_calc_hw(rtd, hw, substream->stream);
604
605 if (formats)
606 hw->formats &= formats;
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200607}
608
Kuninori Morimotodd039072020-02-10 12:14:37 +0900609static int soc_pcm_components_open(struct snd_pcm_substream *substream)
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900610{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900611 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900612 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900613 int i, ret = 0;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900614
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900615 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto51aff912020-09-28 09:01:04 +0900616 ret = snd_soc_component_module_get_when_open(component, substream);
Kuninori Morimotobcae16312020-09-28 09:01:36 +0900617 if (ret < 0)
Kai Vehmanend2aaa8d2020-02-20 11:49:55 +0200618 break;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900619
Kuninori Morimotoae2f4842019-07-26 13:50:01 +0900620 ret = snd_soc_component_open(component, substream);
Kuninori Morimotobcae16312020-09-28 09:01:36 +0900621 if (ret < 0)
Kai Vehmanend2aaa8d2020-02-20 11:49:55 +0200622 break;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900623 }
Kuninori Morimotodd039072020-02-10 12:14:37 +0900624
Kai Vehmanend2aaa8d2020-02-20 11:49:55 +0200625 return ret;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900626}
627
Kuninori Morimoto51aff912020-09-28 09:01:04 +0900628static int soc_pcm_components_close(struct snd_pcm_substream *substream,
629 int rollback)
Charles Keepax244e2932018-06-19 16:22:09 +0100630{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900631 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Charles Keepax244e2932018-06-19 16:22:09 +0100632 struct snd_soc_component *component;
Kuninori Morimotoe82ebff2020-02-10 12:14:26 +0900633 int i, r, ret = 0;
Charles Keepax244e2932018-06-19 16:22:09 +0100634
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900635 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto51aff912020-09-28 09:01:04 +0900636 r = snd_soc_component_close(component, substream, rollback);
Kuninori Morimotoe82ebff2020-02-10 12:14:26 +0900637 if (r < 0)
638 ret = r; /* use last ret */
639
Kuninori Morimoto51aff912020-09-28 09:01:04 +0900640 snd_soc_component_module_put_when_close(component, substream, rollback);
Charles Keepax244e2932018-06-19 16:22:09 +0100641 }
642
Kuninori Morimoto3672beb2019-07-26 13:50:07 +0900643 return ret;
Charles Keepax244e2932018-06-19 16:22:09 +0100644}
645
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900646static int soc_pcm_clean(struct snd_pcm_substream *substream, int rollback)
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900647{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900648 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900649 struct snd_soc_component *component;
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900650 struct snd_soc_dai *dai;
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900651 int i;
652
653 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
654
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900655 if (!rollback)
656 snd_soc_runtime_deactivate(rtd, substream->stream);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900657
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900658 for_each_rtd_dais(rtd, i, dai)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900659 snd_soc_dai_shutdown(dai, substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900660
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900661 snd_soc_link_shutdown(substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900662
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900663 soc_pcm_components_close(substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900664
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900665 if (!rollback)
666 snd_soc_dapm_stream_stop(rtd, substream->stream);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900667
668 mutex_unlock(&rtd->card->pcm_mutex);
669
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900670 snd_soc_pcm_component_pm_runtime_put(rtd, substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900671
672 for_each_rtd_components(rtd, i, component)
Kuninori Morimotob3dea622020-05-15 09:46:51 +0900673 if (!snd_soc_component_active(component))
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900674 pinctrl_pm_select_sleep_state(component->dev);
675
676 return 0;
677}
678
679/*
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900680 * Called by ALSA when a PCM substream is closed. Private data can be
681 * freed here. The cpu DAI, codec DAI, machine and components are also
682 * shutdown.
683 */
684static int soc_pcm_close(struct snd_pcm_substream *substream)
685{
686 return soc_pcm_clean(substream, 0);
687}
688
689/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100690 * Called by ALSA when a PCM substream is opened, the runtime->hw record is
691 * then initialized and any private data can be allocated. This also calls
Charles Keepaxef050be2018-04-24 16:39:02 +0100692 * startup for the cpu DAI, component, machine and codec DAI.
Liam Girdwoodddee6272011-06-09 14:45:53 +0100693 */
694static int soc_pcm_open(struct snd_pcm_substream *substream)
695{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900696 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100697 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000698 struct snd_soc_component *component;
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900699 struct snd_soc_dai *dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200700 const char *codec_dai_name = "multicodec";
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800701 const char *cpu_dai_name = "multicpu";
Charles Keepax244e2932018-06-19 16:22:09 +0100702 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100703
Kuninori Morimoto76c39e82020-01-10 11:36:13 +0900704 for_each_rtd_components(rtd, i, component)
705 pinctrl_pm_select_default_state(component->dev);
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000706
Kuninori Morimoto939a5cf2020-09-28 09:01:17 +0900707 ret = snd_soc_pcm_component_pm_runtime_get(rtd, substream);
708 if (ret < 0)
Kuninori Morimotocb2fce92020-10-01 10:32:48 +0900709 goto pm_err;
Mark Brownd6652ef2011-12-03 20:14:31 +0000710
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300711 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100712
Kuninori Morimoto5d9fa032020-02-10 12:14:45 +0900713 ret = soc_pcm_components_open(substream);
714 if (ret < 0)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900715 goto err;
Kuninori Morimoto5d9fa032020-02-10 12:14:45 +0900716
Kuninori Morimoto7cf3c5b2020-05-25 09:57:31 +0900717 ret = snd_soc_link_startup(substream);
Kuninori Morimotoa5e6c102020-05-25 09:57:19 +0900718 if (ret < 0)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900719 goto err;
Kuninori Morimoto5d9fa032020-02-10 12:14:45 +0900720
Liam Girdwoodddee6272011-06-09 14:45:53 +0100721 /* startup the audio subsystem */
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900722 for_each_rtd_dais(rtd, i, dai) {
723 ret = snd_soc_dai_startup(dai, substream);
Kuninori Morimotoce820142020-09-28 09:01:29 +0900724 if (ret < 0)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900725 goto err;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200726
727 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900728 dai->tx_mask = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200729 else
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900730 dai->rx_mask = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100731 }
732
Liam Girdwood01d75842012-04-25 12:12:49 +0100733 /* Dynamic PCM DAI links compat checks use dynamic capabilities */
734 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm)
735 goto dynamic;
736
Liam Girdwoodddee6272011-06-09 14:45:53 +0100737 /* Check that the codec and cpu DAIs are compatible */
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200738 soc_pcm_init_runtime_hw(substream);
739
740 if (rtd->num_codecs == 1)
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900741 codec_dai_name = asoc_rtd_to_codec(rtd, 0)->name;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100742
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800743 if (rtd->num_cpus == 1)
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900744 cpu_dai_name = asoc_rtd_to_cpu(rtd, 0)->name;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800745
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100746 if (soc_pcm_has_symmetry(substream))
747 runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
748
Liam Girdwoodddee6272011-06-09 14:45:53 +0100749 ret = -EINVAL;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100750 if (!runtime->hw.rates) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000751 printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n",
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800752 codec_dai_name, cpu_dai_name);
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900753 goto err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100754 }
755 if (!runtime->hw.formats) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000756 printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n",
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800757 codec_dai_name, cpu_dai_name);
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900758 goto err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100759 }
760 if (!runtime->hw.channels_min || !runtime->hw.channels_max ||
761 runtime->hw.channels_min > runtime->hw.channels_max) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000762 printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n",
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800763 codec_dai_name, cpu_dai_name);
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900764 goto err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100765 }
766
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200767 soc_pcm_apply_msb(substream);
Mark Brown58ba9b22012-01-16 18:38:51 +0000768
Liam Girdwoodddee6272011-06-09 14:45:53 +0100769 /* Symmetry only applies if we've already got an active stream. */
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900770 for_each_rtd_dais(rtd, i, dai) {
Kuninori Morimotob3dea622020-05-15 09:46:51 +0900771 if (snd_soc_dai_active(dai)) {
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900772 ret = soc_pcm_apply_symmetry(substream, dai);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200773 if (ret != 0)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900774 goto err;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200775 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100776 }
777
Liam Girdwood103d84a2012-11-19 14:39:15 +0000778 pr_debug("ASoC: %s <-> %s info:\n",
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800779 codec_dai_name, cpu_dai_name);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000780 pr_debug("ASoC: rate mask 0x%x\n", runtime->hw.rates);
781 pr_debug("ASoC: min ch %d max ch %d\n", runtime->hw.channels_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100782 runtime->hw.channels_max);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000783 pr_debug("ASoC: min rate %d max rate %d\n", runtime->hw.rate_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100784 runtime->hw.rate_max);
Liam Girdwood01d75842012-04-25 12:12:49 +0100785dynamic:
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100786 snd_soc_runtime_activate(rtd, substream->stream);
Kuninori Morimoto8e7875a2020-10-01 14:07:41 +0900787 ret = 0;
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900788err:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300789 mutex_unlock(&rtd->card->pcm_mutex);
Kuninori Morimotocb2fce92020-10-01 10:32:48 +0900790pm_err:
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900791 if (ret < 0)
792 soc_pcm_clean(substream, 1);
Mark Brownd6652ef2011-12-03 20:14:31 +0000793
Liam Girdwoodddee6272011-06-09 14:45:53 +0100794 return ret;
795}
796
Curtis Malainey4bf2e382019-12-03 09:30:07 -0800797static void codec2codec_close_delayed_work(struct snd_soc_pcm_runtime *rtd)
Jerome Bruneta3420312019-07-25 18:59:47 +0200798{
799 /*
800 * Currently nothing to do for c2c links
801 * Since c2c links are internal nodes in the DAPM graph and
802 * don't interface with the outside world or application layer
803 * we don't have to do any special handling on close.
804 */
805}
806
Liam Girdwoodddee6272011-06-09 14:45:53 +0100807/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100808 * Called by ALSA when the PCM substream is prepared, can set format, sample
809 * rate, etc. This function is non atomic and can be called multiple times,
810 * it can refer to the runtime info.
811 */
812static int soc_pcm_prepare(struct snd_pcm_substream *substream)
813{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900814 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900815 struct snd_soc_dai *dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200816 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100817
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300818 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100819
Kuninori Morimoto7cf3c5b2020-05-25 09:57:31 +0900820 ret = snd_soc_link_prepare(substream);
Kuninori Morimotoa5e6c102020-05-25 09:57:19 +0900821 if (ret < 0)
Kuninori Morimoto44c1a752020-01-22 09:44:44 +0900822 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100823
Kuninori Morimoto4f395142020-06-04 17:06:58 +0900824 ret = snd_soc_pcm_component_prepare(substream);
825 if (ret < 0)
826 goto out;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000827
Kuninori Morimotod108c7f2020-04-24 08:14:53 +0900828 ret = snd_soc_pcm_dai_prepare(substream);
829 if (ret < 0) {
830 dev_err(rtd->dev, "ASoC: DAI prepare error: %d\n", ret);
831 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100832 }
833
834 /* cancel any delayed stream shutdown that is pending */
835 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600836 rtd->pop_wait) {
837 rtd->pop_wait = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100838 cancel_delayed_work(&rtd->delayed_work);
839 }
840
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000841 snd_soc_dapm_stream_event(rtd, substream->stream,
842 SND_SOC_DAPM_STREAM_START);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100843
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900844 for_each_rtd_dais(rtd, i, dai)
845 snd_soc_dai_digital_mute(dai, 0, substream->stream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100846
847out:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300848 mutex_unlock(&rtd->card->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100849 return ret;
850}
851
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200852static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params,
853 unsigned int mask)
854{
855 struct snd_interval *interval;
856 int channels = hweight_long(mask);
857
858 interval = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
859 interval->min = channels;
860 interval->max = channels;
861}
862
Liam Girdwoodddee6272011-06-09 14:45:53 +0100863/*
864 * Called by ALSA when the hardware params are set by application. This
865 * function can also be called multiple times and can allocate buffers
866 * (using snd_pcm_lib_* ). It's non-atomic.
867 */
868static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
869 struct snd_pcm_hw_params *params)
870{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900871 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimotob8135862017-10-11 01:37:23 +0000872 struct snd_soc_component *component;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800873 struct snd_soc_dai *cpu_dai;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000874 struct snd_soc_dai *codec_dai;
Charles Keepax244e2932018-06-19 16:22:09 +0100875 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100876
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300877 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Shengjiu Wang5cca5952019-11-12 18:46:42 +0800878
879 ret = soc_pcm_params_symmetry(substream, params);
880 if (ret)
881 goto out;
882
Kuninori Morimoto7cf3c5b2020-05-25 09:57:31 +0900883 ret = snd_soc_link_hw_params(substream, params);
Kuninori Morimotoa5e6c102020-05-25 09:57:19 +0900884 if (ret < 0)
Kuninori Morimotode9ad992020-01-22 09:44:48 +0900885 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100886
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900887 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200888 struct snd_pcm_hw_params codec_params;
889
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200890 /*
891 * Skip CODECs which don't support the current stream type,
892 * the idea being that if a CODEC is not used for the currently
893 * set up transfer direction, it should not need to be
894 * configured, especially since the configuration used might
895 * not even be supported by that CODEC. There may be cases
896 * however where a CODEC needs to be set up although it is
897 * actually not being used for the transfer, e.g. if a
898 * capture-only CODEC is acting as an LRCLK and/or BCLK master
899 * for the DAI link including a playback-only CODEC.
900 * If this becomes necessary, we will have to augment the
901 * machine driver setup with information on how to act, so
902 * we can do the right thing here.
903 */
904 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
905 continue;
906
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200907 /* copy params for each codec */
908 codec_params = *params;
909
910 /* fixup params based on TDM slot masks */
Rander Wang570f18b2019-03-08 16:38:57 +0800911 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
912 codec_dai->tx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200913 soc_pcm_codec_params_fixup(&codec_params,
914 codec_dai->tx_mask);
Rander Wang570f18b2019-03-08 16:38:57 +0800915
916 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
917 codec_dai->rx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200918 soc_pcm_codec_params_fixup(&codec_params,
919 codec_dai->rx_mask);
920
Kuninori Morimotoaa6166c2019-07-22 10:33:04 +0900921 ret = snd_soc_dai_hw_params(codec_dai, substream,
922 &codec_params);
Benoit Cousson93e69582014-07-08 23:19:38 +0200923 if(ret < 0)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100924 goto codec_err;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200925
926 codec_dai->rate = params_rate(&codec_params);
927 codec_dai->channels = params_channels(&codec_params);
928 codec_dai->sample_bits = snd_pcm_format_physical_width(
929 params_format(&codec_params));
Charles Keepax078a85f2019-01-31 13:30:18 +0000930
931 snd_soc_dapm_update_dai(substream, &codec_params, codec_dai);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100932 }
933
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900934 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800935 /*
936 * Skip CPUs which don't support the current stream
937 * type. See soc_pcm_init_runtime_hw() for more details
938 */
939 if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream))
940 continue;
941
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800942 ret = snd_soc_dai_hw_params(cpu_dai, substream, params);
943 if (ret < 0)
944 goto interface_err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100945
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800946 /* store the parameters for each DAI */
947 cpu_dai->rate = params_rate(params);
948 cpu_dai->channels = params_channels(params);
949 cpu_dai->sample_bits =
950 snd_pcm_format_physical_width(params_format(params));
Kuninori Morimotoca58221d2019-05-13 16:07:43 +0900951
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800952 snd_soc_dapm_update_dai(substream, params, cpu_dai);
953 }
Kuninori Morimotoca58221d2019-05-13 16:07:43 +0900954
Kuninori Morimotoe1bafa82020-06-04 17:07:11 +0900955 ret = snd_soc_pcm_component_hw_params(substream, params, &component);
956 if (ret < 0)
957 goto component_err;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000958
Liam Girdwoodddee6272011-06-09 14:45:53 +0100959out:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300960 mutex_unlock(&rtd->card->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100961 return ret;
962
Kuninori Morimotob8135862017-10-11 01:37:23 +0000963component_err:
Kuninori Morimoto04751112020-06-04 17:07:24 +0900964 snd_soc_pcm_component_hw_free(substream, component);
Kuninori Morimotob8135862017-10-11 01:37:23 +0000965
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800966 i = rtd->num_cpus;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100967
968interface_err:
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900969 for_each_rtd_cpu_dais_rollback(rtd, i, cpu_dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800970 if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream))
971 continue;
972
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800973 snd_soc_dai_hw_free(cpu_dai, substream);
974 cpu_dai->rate = 0;
975 }
976
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200977 i = rtd->num_codecs;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100978
979codec_err:
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900980 for_each_rtd_codec_dais_rollback(rtd, i, codec_dai) {
Jerome Brunetf47b9ad2019-04-29 11:47:50 +0200981 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
982 continue;
983
Kuninori Morimoto846faae2019-07-22 10:33:19 +0900984 snd_soc_dai_hw_free(codec_dai, substream);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200985 codec_dai->rate = 0;
986 }
987
Kuninori Morimoto7cf3c5b2020-05-25 09:57:31 +0900988 snd_soc_link_hw_free(substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100989
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300990 mutex_unlock(&rtd->card->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100991 return ret;
992}
993
994/*
995 * Frees resources allocated by hw_params, can be called multiple times
996 */
997static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
998{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900999 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001000 struct snd_soc_dai *dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001001 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001002
Peter Ujfalusi72b745e2019-08-13 13:45:32 +03001003 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001004
Nicolin Chend3383422013-11-20 18:37:09 +08001005 /* clear the corresponding DAIs parameters when going to be inactive */
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001006 for_each_rtd_dais(rtd, i, dai) {
Kuninori Morimotob3dea622020-05-15 09:46:51 +09001007 int active = snd_soc_dai_stream_active(dai, substream->stream);
Nicolin Chend3383422013-11-20 18:37:09 +08001008
Kuninori Morimotob3dea622020-05-15 09:46:51 +09001009 if (snd_soc_dai_active(dai) == 1) {
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001010 dai->rate = 0;
1011 dai->channels = 0;
1012 dai->sample_bits = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001013 }
Kuninori Morimoto0f6011f2020-02-17 17:28:15 +09001014
Kuninori Morimoto67ad8772020-03-06 10:10:04 +09001015 if (active == 1)
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001016 snd_soc_dai_digital_mute(dai, 1, substream->stream);
Kuninori Morimotoa9ee3312020-03-06 10:10:17 +09001017 }
1018
Liam Girdwoodddee6272011-06-09 14:45:53 +01001019 /* free any machine hw params */
Kuninori Morimoto7cf3c5b2020-05-25 09:57:31 +09001020 snd_soc_link_hw_free(substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001021
Kuninori Morimotob8135862017-10-11 01:37:23 +00001022 /* free any component resources */
Kuninori Morimoto04751112020-06-04 17:07:24 +09001023 snd_soc_pcm_component_hw_free(substream, NULL);
Kuninori Morimotob8135862017-10-11 01:37:23 +00001024
Liam Girdwoodddee6272011-06-09 14:45:53 +01001025 /* now free hw params for the DAIs */
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001026 for_each_rtd_dais(rtd, i, dai) {
1027 if (!snd_soc_dai_stream_valid(dai, substream->stream))
Jerome Brunetf47b9ad2019-04-29 11:47:50 +02001028 continue;
1029
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001030 snd_soc_dai_hw_free(dai, substream);
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001031 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01001032
Peter Ujfalusi72b745e2019-08-13 13:45:32 +03001033 mutex_unlock(&rtd->card->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001034 return 0;
1035}
1036
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001037static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1038{
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001039 int ret = -EINVAL;
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001040
1041 switch (cmd) {
1042 case SNDRV_PCM_TRIGGER_START:
1043 case SNDRV_PCM_TRIGGER_RESUME:
1044 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001045 ret = snd_soc_link_trigger(substream, cmd);
1046 if (ret < 0)
1047 break;
1048
1049 ret = snd_soc_pcm_component_trigger(substream, cmd);
1050 if (ret < 0)
1051 break;
1052
1053 ret = snd_soc_pcm_dai_trigger(substream, cmd);
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001054 break;
1055 case SNDRV_PCM_TRIGGER_STOP:
1056 case SNDRV_PCM_TRIGGER_SUSPEND:
1057 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001058 ret = snd_soc_pcm_dai_trigger(substream, cmd);
1059 if (ret < 0)
1060 break;
1061
1062 ret = snd_soc_pcm_component_trigger(substream, cmd);
1063 if (ret < 0)
1064 break;
1065
1066 ret = snd_soc_link_trigger(substream, cmd);
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001067 break;
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001068 }
1069
1070 return ret;
1071}
1072
Liam Girdwoodddee6272011-06-09 14:45:53 +01001073/*
1074 * soc level wrapper for pointer callback
Charles Keepaxef050be2018-04-24 16:39:02 +01001075 * If cpu_dai, codec_dai, component driver has the delay callback, then
Liam Girdwoodddee6272011-06-09 14:45:53 +01001076 * the runtime->delay will be updated accordingly.
1077 */
1078static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
1079{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001080 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001081 struct snd_soc_dai *cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001082 struct snd_soc_dai *codec_dai;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001083 struct snd_pcm_runtime *runtime = substream->runtime;
1084 snd_pcm_uframes_t offset = 0;
1085 snd_pcm_sframes_t delay = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001086 snd_pcm_sframes_t codec_delay = 0;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001087 snd_pcm_sframes_t cpu_delay = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001088 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001089
Akshu Agrawal9fb4c2bf2018-08-01 15:37:33 +05301090 /* clearing the previous total delay */
1091 runtime->delay = 0;
1092
Kuninori Morimoto0035e252019-07-26 13:51:47 +09001093 offset = snd_soc_pcm_component_pointer(substream);
Kuninori Morimotob8135862017-10-11 01:37:23 +00001094
Akshu Agrawal9fb4c2bf2018-08-01 15:37:33 +05301095 /* base delay if assigned in pointer callback */
1096 delay = runtime->delay;
Kuninori Morimotob8135862017-10-11 01:37:23 +00001097
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001098 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001099 cpu_delay = max(cpu_delay,
1100 snd_soc_dai_delay(cpu_dai, substream));
1101 }
1102 delay += cpu_delay;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001103
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001104 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Kuninori Morimoto1dea80d2019-07-22 10:34:09 +09001105 codec_delay = max(codec_delay,
1106 snd_soc_dai_delay(codec_dai, substream));
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001107 }
1108 delay += codec_delay;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001109
Liam Girdwoodddee6272011-06-09 14:45:53 +01001110 runtime->delay = delay;
1111
1112 return offset;
1113}
1114
Liam Girdwood01d75842012-04-25 12:12:49 +01001115/* connect a FE and BE */
1116static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
1117 struct snd_soc_pcm_runtime *be, int stream)
1118{
1119 struct snd_soc_dpcm *dpcm;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001120 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001121
1122 /* only add new dpcms */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001123 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001124 if (dpcm->be == be && dpcm->fe == fe)
1125 return 0;
1126 }
1127
1128 dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_KERNEL);
1129 if (!dpcm)
1130 return -ENOMEM;
1131
1132 dpcm->be = be;
1133 dpcm->fe = fe;
1134 be->dpcm[stream].runtime = fe->dpcm[stream].runtime;
1135 dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001136 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001137 list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients);
1138 list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001139 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001140
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001141 dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001142 stream ? "capture" : "playback", fe->dai_link->name,
1143 stream ? "<-" : "->", be->dai_link->name);
1144
Kuninori Morimoto154dae82020-02-19 15:57:06 +09001145 dpcm_create_debugfs_state(dpcm, stream);
1146
Liam Girdwood01d75842012-04-25 12:12:49 +01001147 return 1;
1148}
1149
1150/* reparent a BE onto another FE */
1151static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
1152 struct snd_soc_pcm_runtime *be, int stream)
1153{
1154 struct snd_soc_dpcm *dpcm;
1155 struct snd_pcm_substream *fe_substream, *be_substream;
1156
1157 /* reparent if BE is connected to other FEs */
1158 if (!be->dpcm[stream].users)
1159 return;
1160
1161 be_substream = snd_soc_dpcm_get_substream(be, stream);
1162
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00001163 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001164 if (dpcm->fe == fe)
1165 continue;
1166
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001167 dev_dbg(fe->dev, "reparent %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001168 stream ? "capture" : "playback",
1169 dpcm->fe->dai_link->name,
1170 stream ? "<-" : "->", dpcm->be->dai_link->name);
1171
1172 fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, stream);
1173 be_substream->runtime = fe_substream->runtime;
1174 break;
1175 }
1176}
1177
1178/* disconnect a BE and FE */
Liam Girdwood23607022014-01-17 17:03:55 +00001179void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001180{
1181 struct snd_soc_dpcm *dpcm, *d;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001182 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001183
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001184 for_each_dpcm_be_safe(fe, stream, dpcm, d) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001185 dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001186 stream ? "capture" : "playback",
1187 dpcm->be->dai_link->name);
1188
1189 if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE)
1190 continue;
1191
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001192 dev_dbg(fe->dev, "freed DSP %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001193 stream ? "capture" : "playback", fe->dai_link->name,
1194 stream ? "<-" : "->", dpcm->be->dai_link->name);
1195
1196 /* BEs still alive need new FE */
1197 dpcm_be_reparent(fe, dpcm->be, stream);
1198
Kuninori Morimoto154dae82020-02-19 15:57:06 +09001199 dpcm_remove_debugfs_state(dpcm);
1200
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001201 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001202 list_del(&dpcm->list_be);
1203 list_del(&dpcm->list_fe);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001204 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001205 kfree(dpcm);
1206 }
1207}
1208
1209/* get BE for DAI widget and stream */
1210static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
1211 struct snd_soc_dapm_widget *widget, int stream)
1212{
1213 struct snd_soc_pcm_runtime *be;
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001214 struct snd_soc_dapm_widget *w;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001215 struct snd_soc_dai *dai;
Mengdong Lin1a497982015-11-18 02:34:11 -05001216 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01001217
Liam Girdwood3c146462018-03-14 20:43:51 +00001218 dev_dbg(card->dev, "ASoC: find BE for widget %s\n", widget->name);
1219
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001220 for_each_card_rtds(card, be) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001221
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001222 if (!be->dai_link->no_pcm)
1223 continue;
Liam Girdwood35ea0652012-06-05 19:26:59 +01001224
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001225 for_each_rtd_dais(be, i, dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001226 w = snd_soc_dai_get_widget(dai, stream);
Liam Girdwood3c146462018-03-14 20:43:51 +00001227
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001228 dev_dbg(card->dev, "ASoC: try BE : %s\n",
1229 w ? w->name : "(not set)");
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001230
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001231 if (w == widget)
1232 return be;
1233 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001234 }
1235
Jerome Brunet9d6ee362020-02-19 12:50:48 +01001236 /* Widget provided is not a BE */
Liam Girdwood01d75842012-04-25 12:12:49 +01001237 return NULL;
1238}
1239
Liam Girdwood01d75842012-04-25 12:12:49 +01001240static int widget_in_list(struct snd_soc_dapm_widget_list *list,
1241 struct snd_soc_dapm_widget *widget)
1242{
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001243 struct snd_soc_dapm_widget *w;
Liam Girdwood01d75842012-04-25 12:12:49 +01001244 int i;
1245
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001246 for_each_dapm_widgets(list, i, w)
1247 if (widget == w)
Liam Girdwood01d75842012-04-25 12:12:49 +01001248 return 1;
Liam Girdwood01d75842012-04-25 12:12:49 +01001249
1250 return 0;
1251}
1252
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001253static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget,
1254 enum snd_soc_dapm_direction dir)
1255{
1256 struct snd_soc_card *card = widget->dapm->card;
1257 struct snd_soc_pcm_runtime *rtd;
Kuninori Morimotoc2cd8212020-02-17 17:27:48 +09001258 int stream;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001259
Kuninori Morimotoc2cd8212020-02-17 17:27:48 +09001260 /* adjust dir to stream */
1261 if (dir == SND_SOC_DAPM_DIR_OUT)
1262 stream = SNDRV_PCM_STREAM_PLAYBACK;
1263 else
1264 stream = SNDRV_PCM_STREAM_CAPTURE;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001265
Kuninori Morimoto027a4832020-02-17 17:27:53 +09001266 rtd = dpcm_get_be(card, widget, stream);
1267 if (rtd)
1268 return true;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001269
1270 return false;
1271}
1272
Liam Girdwood23607022014-01-17 17:03:55 +00001273int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001274 int stream, struct snd_soc_dapm_widget_list **list)
Liam Girdwood01d75842012-04-25 12:12:49 +01001275{
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09001276 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
Liam Girdwood01d75842012-04-25 12:12:49 +01001277 int paths;
1278
Bard Liao6e1276a2020-02-25 21:39:16 +08001279 if (fe->num_cpus > 1) {
1280 dev_err(fe->dev,
1281 "%s doesn't support Multi CPU yet\n", __func__);
1282 return -EINVAL;
1283 }
1284
Liam Girdwood01d75842012-04-25 12:12:49 +01001285 /* get number of valid DAI paths and their widgets */
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001286 paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list,
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001287 dpcm_end_walk_at_be);
Liam Girdwood01d75842012-04-25 12:12:49 +01001288
Liam Girdwood103d84a2012-11-19 14:39:15 +00001289 dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths,
Liam Girdwood01d75842012-04-25 12:12:49 +01001290 stream ? "capture" : "playback");
1291
Liam Girdwood01d75842012-04-25 12:12:49 +01001292 return paths;
1293}
1294
Kuninori Morimoto52645e332020-02-19 15:56:52 +09001295void dpcm_path_put(struct snd_soc_dapm_widget_list **list)
1296{
1297 snd_soc_dapm_dai_free_widgets(list);
1298}
1299
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001300static bool dpcm_be_is_active(struct snd_soc_dpcm *dpcm, int stream,
1301 struct snd_soc_dapm_widget_list *list)
Liam Girdwood01d75842012-04-25 12:12:49 +01001302{
Liam Girdwood01d75842012-04-25 12:12:49 +01001303 struct snd_soc_dapm_widget *widget;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001304 struct snd_soc_dai *dai;
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001305 unsigned int i;
1306
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001307 /* is there a valid DAI widget for this BE */
1308 for_each_rtd_dais(dpcm->be, i, dai) {
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001309 widget = snd_soc_dai_get_widget(dai, stream);
1310
1311 /*
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001312 * The BE is pruned only if none of the dai
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001313 * widgets are in the active list.
1314 */
1315 if (widget && widget_in_list(list, widget))
1316 return true;
1317 }
1318
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001319 return false;
1320}
1321
1322static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
1323 struct snd_soc_dapm_widget_list **list_)
1324{
1325 struct snd_soc_dpcm *dpcm;
Liam Girdwood01d75842012-04-25 12:12:49 +01001326 int prune = 0;
1327
1328 /* Destroy any old FE <--> BE connections */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001329 for_each_dpcm_be(fe, stream, dpcm) {
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001330 if (dpcm_be_is_active(dpcm, stream, *list_))
Kuninori Morimotobed646d2019-10-15 12:59:38 +09001331 continue;
Liam Girdwood01d75842012-04-25 12:12:49 +01001332
Liam Girdwood103d84a2012-11-19 14:39:15 +00001333 dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001334 stream ? "capture" : "playback",
1335 dpcm->be->dai_link->name, fe->dai_link->name);
1336 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
1337 dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1338 prune++;
1339 }
1340
Liam Girdwood103d84a2012-11-19 14:39:15 +00001341 dev_dbg(fe->dev, "ASoC: found %d old BE paths for pruning\n", prune);
Liam Girdwood01d75842012-04-25 12:12:49 +01001342 return prune;
1343}
1344
1345static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
1346 struct snd_soc_dapm_widget_list **list_)
1347{
1348 struct snd_soc_card *card = fe->card;
1349 struct snd_soc_dapm_widget_list *list = *list_;
1350 struct snd_soc_pcm_runtime *be;
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001351 struct snd_soc_dapm_widget *widget;
Liam Girdwood01d75842012-04-25 12:12:49 +01001352 int i, new = 0, err;
1353
1354 /* Create any new FE <--> BE connections */
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001355 for_each_dapm_widgets(list, i, widget) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001356
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001357 switch (widget->id) {
Mark Brown46162742013-06-05 19:36:11 +01001358 case snd_soc_dapm_dai_in:
Koro Chenc5b85402015-07-06 10:02:10 +08001359 if (stream != SNDRV_PCM_STREAM_PLAYBACK)
1360 continue;
1361 break;
Mark Brown46162742013-06-05 19:36:11 +01001362 case snd_soc_dapm_dai_out:
Koro Chenc5b85402015-07-06 10:02:10 +08001363 if (stream != SNDRV_PCM_STREAM_CAPTURE)
1364 continue;
Mark Brown46162742013-06-05 19:36:11 +01001365 break;
1366 default:
Liam Girdwood01d75842012-04-25 12:12:49 +01001367 continue;
Mark Brown46162742013-06-05 19:36:11 +01001368 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001369
1370 /* is there a valid BE rtd for this widget */
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001371 be = dpcm_get_be(card, widget, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001372 if (!be) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001373 dev_err(fe->dev, "ASoC: no BE found for %s\n",
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001374 widget->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001375 continue;
1376 }
1377
Liam Girdwood01d75842012-04-25 12:12:49 +01001378 /* don't connect if FE is not running */
Liam Girdwood23607022014-01-17 17:03:55 +00001379 if (!fe->dpcm[stream].runtime && !fe->fe_compr)
Liam Girdwood01d75842012-04-25 12:12:49 +01001380 continue;
1381
1382 /* newly connected FE and BE */
1383 err = dpcm_be_connect(fe, be, stream);
1384 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001385 dev_err(fe->dev, "ASoC: can't connect %s\n",
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001386 widget->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001387 break;
1388 } else if (err == 0) /* already connected */
1389 continue;
1390
1391 /* new */
1392 be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1393 new++;
1394 }
1395
Liam Girdwood103d84a2012-11-19 14:39:15 +00001396 dev_dbg(fe->dev, "ASoC: found %d new BE paths\n", new);
Liam Girdwood01d75842012-04-25 12:12:49 +01001397 return new;
1398}
1399
1400/*
1401 * Find the corresponding BE DAIs that source or sink audio to this
1402 * FE substream.
1403 */
Liam Girdwood23607022014-01-17 17:03:55 +00001404int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
Liam Girdwood01d75842012-04-25 12:12:49 +01001405 int stream, struct snd_soc_dapm_widget_list **list, int new)
1406{
1407 if (new)
1408 return dpcm_add_paths(fe, stream, list);
1409 else
1410 return dpcm_prune_paths(fe, stream, list);
1411}
1412
Liam Girdwood23607022014-01-17 17:03:55 +00001413void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001414{
1415 struct snd_soc_dpcm *dpcm;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001416 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001417
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001418 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001419 for_each_dpcm_be(fe, stream, dpcm)
Liam Girdwood01d75842012-04-25 12:12:49 +01001420 dpcm->be->dpcm[stream].runtime_update =
1421 SND_SOC_DPCM_UPDATE_NO;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001422 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001423}
1424
1425static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe,
1426 int stream)
1427{
1428 struct snd_soc_dpcm *dpcm;
1429
1430 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001431 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001432
1433 struct snd_soc_pcm_runtime *be = dpcm->be;
1434 struct snd_pcm_substream *be_substream =
1435 snd_soc_dpcm_get_substream(be, stream);
1436
1437 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001438 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001439 stream ? "capture" : "playback",
1440 be->dpcm[stream].state);
1441
1442 if (--be->dpcm[stream].users != 0)
1443 continue;
1444
1445 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1446 continue;
1447
1448 soc_pcm_close(be_substream);
1449 be_substream->runtime = NULL;
1450 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1451 }
1452}
1453
Liam Girdwood23607022014-01-17 17:03:55 +00001454int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001455{
1456 struct snd_soc_dpcm *dpcm;
1457 int err, count = 0;
1458
1459 /* only startup BE DAIs that are either sinks or sources to this FE DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001460 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001461
1462 struct snd_soc_pcm_runtime *be = dpcm->be;
1463 struct snd_pcm_substream *be_substream =
1464 snd_soc_dpcm_get_substream(be, stream);
1465
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001466 if (!be_substream) {
1467 dev_err(be->dev, "ASoC: no backend %s stream\n",
1468 stream ? "capture" : "playback");
1469 continue;
1470 }
1471
Liam Girdwood01d75842012-04-25 12:12:49 +01001472 /* is this op for this BE ? */
1473 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1474 continue;
1475
1476 /* first time the dpcm is open ? */
1477 if (be->dpcm[stream].users == DPCM_MAX_BE_USERS)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001478 dev_err(be->dev, "ASoC: too many users %s at open %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001479 stream ? "capture" : "playback",
1480 be->dpcm[stream].state);
1481
1482 if (be->dpcm[stream].users++ != 0)
1483 continue;
1484
1485 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
1486 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
1487 continue;
1488
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001489 dev_dbg(be->dev, "ASoC: open %s BE %s\n",
1490 stream ? "capture" : "playback", be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001491
1492 be_substream->runtime = be->dpcm[stream].runtime;
1493 err = soc_pcm_open(be_substream);
1494 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001495 dev_err(be->dev, "ASoC: BE open failed %d\n", err);
Liam Girdwood01d75842012-04-25 12:12:49 +01001496 be->dpcm[stream].users--;
1497 if (be->dpcm[stream].users < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001498 dev_err(be->dev, "ASoC: no users %s at unwind %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001499 stream ? "capture" : "playback",
1500 be->dpcm[stream].state);
1501
1502 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1503 goto unwind;
1504 }
1505
1506 be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1507 count++;
1508 }
1509
1510 return count;
1511
1512unwind:
1513 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001514 for_each_dpcm_be_rollback(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001515 struct snd_soc_pcm_runtime *be = dpcm->be;
1516 struct snd_pcm_substream *be_substream =
1517 snd_soc_dpcm_get_substream(be, stream);
1518
1519 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1520 continue;
1521
1522 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001523 dev_err(be->dev, "ASoC: no users %s at close %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001524 stream ? "capture" : "playback",
1525 be->dpcm[stream].state);
1526
1527 if (--be->dpcm[stream].users != 0)
1528 continue;
1529
1530 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1531 continue;
1532
1533 soc_pcm_close(be_substream);
1534 be_substream->runtime = NULL;
1535 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1536 }
1537
1538 return err;
1539}
1540
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001541static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
Jerome Brunet435ffb72018-07-05 12:13:48 +02001542 struct snd_soc_pcm_stream *stream)
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001543{
1544 runtime->hw.rate_min = stream->rate_min;
Charles Keepaxe33ffbd9c2018-08-27 14:26:47 +01001545 runtime->hw.rate_max = min_not_zero(stream->rate_max, UINT_MAX);
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001546 runtime->hw.channels_min = stream->channels_min;
1547 runtime->hw.channels_max = stream->channels_max;
Lars-Peter Clausen002220a2014-01-06 14:19:07 +01001548 if (runtime->hw.formats)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001549 runtime->hw.formats &= stream->formats;
Lars-Peter Clausen002220a2014-01-06 14:19:07 +01001550 else
Jerome Brunet435ffb72018-07-05 12:13:48 +02001551 runtime->hw.formats = stream->formats;
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001552 runtime->hw.rates = stream->rates;
1553}
1554
Jerome Brunet435ffb72018-07-05 12:13:48 +02001555static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream,
1556 u64 *formats)
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001557{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001558 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001559 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001560 struct snd_soc_dai *dai;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001561 int stream = substream->stream;
1562
1563 if (!fe->dai_link->dpcm_merged_format)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001564 return;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001565
1566 /*
1567 * It returns merged BE codec format
1568 * if FE want to use it (= dpcm_merged_format)
1569 */
1570
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001571 for_each_dpcm_be(fe, stream, dpcm) {
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001572 struct snd_soc_pcm_runtime *be = dpcm->be;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001573 struct snd_soc_pcm_stream *codec_stream;
1574 int i;
1575
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001576 for_each_rtd_codec_dais(be, i, dai) {
Jerome Brunet4febced2018-06-27 17:36:38 +02001577 /*
1578 * Skip CODECs which don't support the current stream
1579 * type. See soc_pcm_init_runtime_hw() for more details
1580 */
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001581 if (!snd_soc_dai_stream_valid(dai, stream))
Jerome Brunet4febced2018-06-27 17:36:38 +02001582 continue;
1583
Kuninori Morimotoacf253c2020-02-19 15:56:30 +09001584 codec_stream = snd_soc_dai_get_pcm_stream(dai, stream);
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001585
Jerome Brunet435ffb72018-07-05 12:13:48 +02001586 *formats &= codec_stream->formats;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001587 }
1588 }
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001589}
1590
Jerome Brunet435ffb72018-07-05 12:13:48 +02001591static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream,
1592 unsigned int *channels_min,
1593 unsigned int *channels_max)
Jiada Wangf4c277b2018-06-20 18:25:20 +09001594{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001595 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Jiada Wangf4c277b2018-06-20 18:25:20 +09001596 struct snd_soc_dpcm *dpcm;
1597 int stream = substream->stream;
1598
1599 if (!fe->dai_link->dpcm_merged_chan)
1600 return;
1601
Jiada Wangf4c277b2018-06-20 18:25:20 +09001602 /*
1603 * It returns merged BE codec channel;
1604 * if FE want to use it (= dpcm_merged_chan)
1605 */
1606
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001607 for_each_dpcm_be(fe, stream, dpcm) {
Jiada Wangf4c277b2018-06-20 18:25:20 +09001608 struct snd_soc_pcm_runtime *be = dpcm->be;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001609 struct snd_soc_pcm_stream *codec_stream;
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001610 struct snd_soc_pcm_stream *cpu_stream;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001611 struct snd_soc_dai *dai;
1612 int i;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001613
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001614 for_each_rtd_cpu_dais(be, i, dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001615 /*
1616 * Skip CPUs which don't support the current stream
1617 * type. See soc_pcm_init_runtime_hw() for more details
1618 */
1619 if (!snd_soc_dai_stream_valid(dai, stream))
1620 continue;
1621
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001622 cpu_stream = snd_soc_dai_get_pcm_stream(dai, stream);
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001623
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001624 *channels_min = max(*channels_min,
1625 cpu_stream->channels_min);
1626 *channels_max = min(*channels_max,
1627 cpu_stream->channels_max);
1628 }
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001629
1630 /*
1631 * chan min/max cannot be enforced if there are multiple CODEC
1632 * DAIs connected to a single CPU DAI, use CPU DAI's directly
1633 */
1634 if (be->num_codecs == 1) {
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09001635 codec_stream = snd_soc_dai_get_pcm_stream(asoc_rtd_to_codec(be, 0), stream);
Jiada Wangf4c277b2018-06-20 18:25:20 +09001636
1637 *channels_min = max(*channels_min,
1638 codec_stream->channels_min);
1639 *channels_max = min(*channels_max,
1640 codec_stream->channels_max);
1641 }
1642 }
1643}
1644
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001645static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream,
1646 unsigned int *rates,
1647 unsigned int *rate_min,
1648 unsigned int *rate_max)
1649{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001650 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001651 struct snd_soc_dpcm *dpcm;
1652 int stream = substream->stream;
1653
1654 if (!fe->dai_link->dpcm_merged_rate)
1655 return;
1656
1657 /*
1658 * It returns merged BE codec channel;
1659 * if FE want to use it (= dpcm_merged_chan)
1660 */
1661
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001662 for_each_dpcm_be(fe, stream, dpcm) {
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001663 struct snd_soc_pcm_runtime *be = dpcm->be;
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001664 struct snd_soc_pcm_stream *pcm;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001665 struct snd_soc_dai *dai;
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001666 int i;
1667
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001668 for_each_rtd_dais(be, i, dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001669 /*
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001670 * Skip DAIs which don't support the current stream
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001671 * type. See soc_pcm_init_runtime_hw() for more details
1672 */
1673 if (!snd_soc_dai_stream_valid(dai, stream))
1674 continue;
1675
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001676 pcm = snd_soc_dai_get_pcm_stream(dai, stream);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001677
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001678 *rate_min = max(*rate_min, pcm->rate_min);
1679 *rate_max = min_not_zero(*rate_max, pcm->rate_max);
1680 *rates = snd_pcm_rate_mask_intersect(*rates, pcm->rates);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001681 }
1682 }
1683}
1684
Mark Brown45c0a182012-05-09 21:46:27 +01001685static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001686{
1687 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001688 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001689 struct snd_soc_dai *cpu_dai;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001690 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01001691
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001692 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001693 /*
1694 * Skip CPUs which don't support the current stream
1695 * type. See soc_pcm_init_runtime_hw() for more details
1696 */
1697 if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream))
1698 continue;
1699
Kuninori Morimoto0c9ba722020-03-06 10:09:54 +09001700 dpcm_init_runtime_hw(runtime,
1701 snd_soc_dai_get_pcm_stream(cpu_dai,
1702 substream->stream));
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001703 }
Jiada Wangf4c277b2018-06-20 18:25:20 +09001704
Jerome Brunet435ffb72018-07-05 12:13:48 +02001705 dpcm_runtime_merge_format(substream, &runtime->hw.formats);
1706 dpcm_runtime_merge_chan(substream, &runtime->hw.channels_min,
1707 &runtime->hw.channels_max);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001708 dpcm_runtime_merge_rate(substream, &runtime->hw.rates,
1709 &runtime->hw.rate_min, &runtime->hw.rate_max);
Liam Girdwood01d75842012-04-25 12:12:49 +01001710}
1711
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001712static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
1713
1714/* Set FE's runtime_update state; the state is protected via PCM stream lock
1715 * for avoiding the race with trigger callback.
1716 * If the state is unset and a trigger is pending while the previous operation,
1717 * process the pending trigger action here.
1718 */
1719static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
1720 int stream, enum snd_soc_dpcm_update state)
1721{
1722 struct snd_pcm_substream *substream =
1723 snd_soc_dpcm_get_substream(fe, stream);
1724
1725 snd_pcm_stream_lock_irq(substream);
1726 if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) {
1727 dpcm_fe_dai_do_trigger(substream,
1728 fe->dpcm[stream].trigger_pending - 1);
1729 fe->dpcm[stream].trigger_pending = 0;
1730 }
1731 fe->dpcm[stream].runtime_update = state;
1732 snd_pcm_stream_unlock_irq(substream);
1733}
1734
PC Liao906c7d62015-12-11 11:33:51 +08001735static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
1736 int stream)
1737{
1738 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001739 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001740 struct snd_soc_dai *fe_cpu_dai;
PC Liao906c7d62015-12-11 11:33:51 +08001741 int err;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001742 int i;
PC Liao906c7d62015-12-11 11:33:51 +08001743
1744 /* apply symmetry for FE */
1745 if (soc_pcm_has_symmetry(fe_substream))
1746 fe_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1747
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001748 for_each_rtd_cpu_dais (fe, i, fe_cpu_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001749 /* Symmetry only applies if we've got an active stream. */
Kuninori Morimotob3dea622020-05-15 09:46:51 +09001750 if (snd_soc_dai_active(fe_cpu_dai)) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001751 err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai);
1752 if (err < 0)
1753 return err;
1754 }
PC Liao906c7d62015-12-11 11:33:51 +08001755 }
1756
1757 /* apply symmetry for BE */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001758 for_each_dpcm_be(fe, stream, dpcm) {
PC Liao906c7d62015-12-11 11:33:51 +08001759 struct snd_soc_pcm_runtime *be = dpcm->be;
1760 struct snd_pcm_substream *be_substream =
1761 snd_soc_dpcm_get_substream(be, stream);
Jerome Brunet6246f282019-04-01 15:03:54 +02001762 struct snd_soc_pcm_runtime *rtd;
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001763 struct snd_soc_dai *dai;
PC Liao906c7d62015-12-11 11:33:51 +08001764 int i;
1765
Jerome Brunet6246f282019-04-01 15:03:54 +02001766 /* A backend may not have the requested substream */
1767 if (!be_substream)
1768 continue;
1769
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001770 rtd = asoc_substream_to_rtd(be_substream);
Jeeja KPf1176612016-09-06 14:17:55 +05301771 if (rtd->dai_link->be_hw_params_fixup)
1772 continue;
1773
PC Liao906c7d62015-12-11 11:33:51 +08001774 if (soc_pcm_has_symmetry(be_substream))
1775 be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1776
1777 /* Symmetry only applies if we've got an active stream. */
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001778 for_each_rtd_dais(rtd, i, dai) {
Kuninori Morimotob3dea622020-05-15 09:46:51 +09001779 if (snd_soc_dai_active(dai)) {
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001780 err = soc_pcm_apply_symmetry(fe_substream, dai);
PC Liao906c7d62015-12-11 11:33:51 +08001781 if (err < 0)
1782 return err;
1783 }
1784 }
1785 }
1786
1787 return 0;
1788}
1789
Liam Girdwood01d75842012-04-25 12:12:49 +01001790static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
1791{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001792 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001793 struct snd_pcm_runtime *runtime = fe_substream->runtime;
1794 int stream = fe_substream->stream, ret = 0;
1795
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001796 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001797
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09001798 ret = dpcm_be_dai_startup(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001799 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001800 dev_err(fe->dev,"ASoC: failed to start some BEs %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001801 goto be_err;
1802 }
1803
Liam Girdwood103d84a2012-11-19 14:39:15 +00001804 dev_dbg(fe->dev, "ASoC: open FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001805
1806 /* start the DAI frontend */
1807 ret = soc_pcm_open(fe_substream);
1808 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001809 dev_err(fe->dev,"ASoC: failed to start FE %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001810 goto unwind;
1811 }
1812
1813 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1814
1815 dpcm_set_fe_runtime(fe_substream);
1816 snd_pcm_limit_hw_rates(runtime);
1817
PC Liao906c7d62015-12-11 11:33:51 +08001818 ret = dpcm_apply_symmetry(fe_substream, stream);
Kuninori Morimoto8a01fbf2020-03-06 10:09:59 +09001819 if (ret < 0)
PC Liao906c7d62015-12-11 11:33:51 +08001820 dev_err(fe->dev, "ASoC: failed to apply dpcm symmetry %d\n",
1821 ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001822
1823unwind:
Kuninori Morimoto8a01fbf2020-03-06 10:09:59 +09001824 if (ret < 0)
1825 dpcm_be_dai_startup_unwind(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001826be_err:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001827 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001828 return ret;
1829}
1830
Liam Girdwood23607022014-01-17 17:03:55 +00001831int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001832{
1833 struct snd_soc_dpcm *dpcm;
1834
1835 /* only shutdown BEs that are either sinks or sources to this FE DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001836 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001837
1838 struct snd_soc_pcm_runtime *be = dpcm->be;
1839 struct snd_pcm_substream *be_substream =
1840 snd_soc_dpcm_get_substream(be, stream);
1841
1842 /* is this op for this BE ? */
1843 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1844 continue;
1845
1846 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001847 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001848 stream ? "capture" : "playback",
1849 be->dpcm[stream].state);
1850
1851 if (--be->dpcm[stream].users != 0)
1852 continue;
1853
1854 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Kai Chieh Chuang9c0ac702018-05-28 10:18:18 +08001855 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) {
1856 soc_pcm_hw_free(be_substream);
1857 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1858 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001859
Liam Girdwood103d84a2012-11-19 14:39:15 +00001860 dev_dbg(be->dev, "ASoC: close BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001861 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001862
1863 soc_pcm_close(be_substream);
1864 be_substream->runtime = NULL;
1865
1866 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1867 }
1868 return 0;
1869}
1870
1871static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
1872{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001873 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001874 int stream = substream->stream;
1875
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001876 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001877
1878 /* shutdown the BEs */
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09001879 dpcm_be_dai_shutdown(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001880
Liam Girdwood103d84a2012-11-19 14:39:15 +00001881 dev_dbg(fe->dev, "ASoC: close FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001882
1883 /* now shutdown the frontend */
1884 soc_pcm_close(substream);
1885
1886 /* run the stream event for each BE */
Kuninori Morimoto1c531232020-02-21 10:25:18 +09001887 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
Liam Girdwood01d75842012-04-25 12:12:49 +01001888
1889 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001890 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001891 return 0;
1892}
1893
Liam Girdwood23607022014-01-17 17:03:55 +00001894int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001895{
1896 struct snd_soc_dpcm *dpcm;
1897
1898 /* only hw_params backends that are either sinks or sources
1899 * to this frontend DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001900 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001901
1902 struct snd_soc_pcm_runtime *be = dpcm->be;
1903 struct snd_pcm_substream *be_substream =
1904 snd_soc_dpcm_get_substream(be, stream);
1905
1906 /* is this op for this BE ? */
1907 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1908 continue;
1909
1910 /* only free hw when no longer used - check all FEs */
1911 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1912 continue;
1913
Qiao Zhou36fba622014-12-03 10:13:43 +08001914 /* do not free hw if this BE is used by other FE */
1915 if (be->dpcm[stream].users > 1)
1916 continue;
1917
Liam Girdwood01d75842012-04-25 12:12:49 +01001918 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1919 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
1920 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Patrick Lai08b27842012-12-19 19:36:02 -08001921 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
Vinod Koul5e82d2b2016-02-01 22:26:40 +05301922 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
1923 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
Liam Girdwood01d75842012-04-25 12:12:49 +01001924 continue;
1925
Liam Girdwood103d84a2012-11-19 14:39:15 +00001926 dev_dbg(be->dev, "ASoC: hw_free BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001927 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001928
1929 soc_pcm_hw_free(be_substream);
1930
1931 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1932 }
1933
1934 return 0;
1935}
1936
Mark Brown45c0a182012-05-09 21:46:27 +01001937static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001938{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001939 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001940 int err, stream = substream->stream;
1941
1942 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001943 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001944
Liam Girdwood103d84a2012-11-19 14:39:15 +00001945 dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001946
1947 /* call hw_free on the frontend */
1948 err = soc_pcm_hw_free(substream);
1949 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001950 dev_err(fe->dev,"ASoC: hw_free FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001951 fe->dai_link->name);
1952
1953 /* only hw_params backends that are either sinks or sources
1954 * to this frontend DAI */
1955 err = dpcm_be_dai_hw_free(fe, stream);
1956
1957 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001958 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001959
1960 mutex_unlock(&fe->card->mutex);
1961 return 0;
1962}
1963
Liam Girdwood23607022014-01-17 17:03:55 +00001964int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001965{
1966 struct snd_soc_dpcm *dpcm;
1967 int ret;
1968
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001969 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001970
1971 struct snd_soc_pcm_runtime *be = dpcm->be;
1972 struct snd_pcm_substream *be_substream =
1973 snd_soc_dpcm_get_substream(be, stream);
1974
1975 /* is this op for this BE ? */
1976 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1977 continue;
1978
Liam Girdwood01d75842012-04-25 12:12:49 +01001979 /* copy params for each dpcm */
1980 memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params,
1981 sizeof(struct snd_pcm_hw_params));
1982
1983 /* perform any hw_params fixups */
Kuninori Morimoto0cbbf8a2020-05-25 09:57:36 +09001984 ret = snd_soc_link_be_hw_params_fixup(be, &dpcm->hw_params);
1985 if (ret < 0)
1986 goto unwind;
Liam Girdwood01d75842012-04-25 12:12:49 +01001987
Libin Yangae061d22019-04-19 09:53:12 +08001988 /* copy the fixed-up hw params for BE dai */
1989 memcpy(&be->dpcm[stream].hw_params, &dpcm->hw_params,
1990 sizeof(struct snd_pcm_hw_params));
1991
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00001992 /* only allow hw_params() if no connected FEs are running */
1993 if (!snd_soc_dpcm_can_be_params(fe, be, stream))
1994 continue;
1995
1996 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
1997 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1998 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE))
1999 continue;
2000
2001 dev_dbg(be->dev, "ASoC: hw_params BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002002 be->dai_link->name);
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00002003
Liam Girdwood01d75842012-04-25 12:12:49 +01002004 ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params);
2005 if (ret < 0) {
2006 dev_err(dpcm->be->dev,
Liam Girdwood103d84a2012-11-19 14:39:15 +00002007 "ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002008 goto unwind;
2009 }
2010
2011 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2012 }
2013 return 0;
2014
2015unwind:
2016 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002017 for_each_dpcm_be_rollback(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002018 struct snd_soc_pcm_runtime *be = dpcm->be;
2019 struct snd_pcm_substream *be_substream =
2020 snd_soc_dpcm_get_substream(be, stream);
2021
2022 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2023 continue;
2024
2025 /* only allow hw_free() if no connected FEs are running */
2026 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2027 continue;
2028
2029 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
2030 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2031 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
2032 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
2033 continue;
2034
2035 soc_pcm_hw_free(be_substream);
2036 }
2037
2038 return ret;
2039}
2040
Mark Brown45c0a182012-05-09 21:46:27 +01002041static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
2042 struct snd_pcm_hw_params *params)
Liam Girdwood01d75842012-04-25 12:12:49 +01002043{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002044 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002045 int ret, stream = substream->stream;
2046
2047 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002048 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002049
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09002050 memcpy(&fe->dpcm[stream].hw_params, params,
Liam Girdwood01d75842012-04-25 12:12:49 +01002051 sizeof(struct snd_pcm_hw_params));
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09002052 ret = dpcm_be_dai_hw_params(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002053 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002054 dev_err(fe->dev,"ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002055 goto out;
2056 }
2057
Liam Girdwood103d84a2012-11-19 14:39:15 +00002058 dev_dbg(fe->dev, "ASoC: hw_params FE %s rate %d chan %x fmt %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002059 fe->dai_link->name, params_rate(params),
2060 params_channels(params), params_format(params));
2061
2062 /* call hw_params on the frontend */
2063 ret = soc_pcm_hw_params(substream, params);
2064 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002065 dev_err(fe->dev,"ASoC: hw_params FE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002066 dpcm_be_dai_hw_free(fe, stream);
2067 } else
2068 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2069
2070out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002071 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002072 mutex_unlock(&fe->card->mutex);
2073 return ret;
2074}
2075
2076static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm,
2077 struct snd_pcm_substream *substream, int cmd)
2078{
2079 int ret;
2080
Liam Girdwood103d84a2012-11-19 14:39:15 +00002081 dev_dbg(dpcm->be->dev, "ASoC: trigger BE %s cmd %d\n",
彭东林94d215c2016-09-26 08:29:31 +00002082 dpcm->be->dai_link->name, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002083
2084 ret = soc_pcm_trigger(substream, cmd);
2085 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002086 dev_err(dpcm->be->dev,"ASoC: trigger BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002087
2088 return ret;
2089}
2090
Liam Girdwood23607022014-01-17 17:03:55 +00002091int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
Mark Brown45c0a182012-05-09 21:46:27 +01002092 int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002093{
2094 struct snd_soc_dpcm *dpcm;
2095 int ret = 0;
2096
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002097 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002098
2099 struct snd_soc_pcm_runtime *be = dpcm->be;
2100 struct snd_pcm_substream *be_substream =
2101 snd_soc_dpcm_get_substream(be, stream);
2102
2103 /* is this op for this BE ? */
2104 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2105 continue;
2106
2107 switch (cmd) {
2108 case SNDRV_PCM_TRIGGER_START:
2109 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
이경택21fca8b2020-04-01 10:04:21 +09002110 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
2111 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Liam Girdwood01d75842012-04-25 12:12:49 +01002112 continue;
2113
2114 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2115 if (ret)
2116 return ret;
2117
2118 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2119 break;
2120 case SNDRV_PCM_TRIGGER_RESUME:
2121 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
2122 continue;
2123
2124 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2125 if (ret)
2126 return ret;
2127
2128 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2129 break;
2130 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2131 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
2132 continue;
2133
2134 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2135 if (ret)
2136 return ret;
2137
2138 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2139 break;
2140 case SNDRV_PCM_TRIGGER_STOP:
이경택21fca8b2020-04-01 10:04:21 +09002141 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) &&
2142 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Liam Girdwood01d75842012-04-25 12:12:49 +01002143 continue;
2144
2145 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2146 continue;
2147
2148 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2149 if (ret)
2150 return ret;
2151
2152 be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2153 break;
2154 case SNDRV_PCM_TRIGGER_SUSPEND:
Nicolin Chen868a6ca2014-05-12 20:12:05 +08002155 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
Liam Girdwood01d75842012-04-25 12:12:49 +01002156 continue;
2157
2158 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2159 continue;
2160
2161 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2162 if (ret)
2163 return ret;
2164
2165 be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND;
2166 break;
2167 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2168 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2169 continue;
2170
2171 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2172 continue;
2173
2174 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2175 if (ret)
2176 return ret;
2177
2178 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2179 break;
2180 }
2181 }
2182
2183 return ret;
2184}
2185EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
2186
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002187static int dpcm_dai_trigger_fe_be(struct snd_pcm_substream *substream,
2188 int cmd, bool fe_first)
2189{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002190 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002191 int ret;
2192
2193 /* call trigger on the frontend before the backend. */
2194 if (fe_first) {
2195 dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n",
2196 fe->dai_link->name, cmd);
2197
2198 ret = soc_pcm_trigger(substream, cmd);
2199 if (ret < 0)
2200 return ret;
2201
2202 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2203 return ret;
2204 }
2205
2206 /* call trigger on the frontend after the backend. */
2207 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2208 if (ret < 0)
2209 return ret;
2210
2211 dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n",
2212 fe->dai_link->name, cmd);
2213
2214 ret = soc_pcm_trigger(substream, cmd);
2215
2216 return ret;
2217}
2218
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002219static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002220{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002221 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002222 int stream = substream->stream;
2223 int ret = 0;
Liam Girdwood01d75842012-04-25 12:12:49 +01002224 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
2225
2226 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
2227
2228 switch (trigger) {
2229 case SND_SOC_DPCM_TRIGGER_PRE:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002230 switch (cmd) {
2231 case SNDRV_PCM_TRIGGER_START:
2232 case SNDRV_PCM_TRIGGER_RESUME:
2233 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2234 ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
2235 break;
2236 case SNDRV_PCM_TRIGGER_STOP:
2237 case SNDRV_PCM_TRIGGER_SUSPEND:
2238 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2239 ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
2240 break;
2241 default:
2242 ret = -EINVAL;
2243 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002244 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002245 break;
2246 case SND_SOC_DPCM_TRIGGER_POST:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002247 switch (cmd) {
2248 case SNDRV_PCM_TRIGGER_START:
2249 case SNDRV_PCM_TRIGGER_RESUME:
2250 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2251 ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
2252 break;
2253 case SNDRV_PCM_TRIGGER_STOP:
2254 case SNDRV_PCM_TRIGGER_SUSPEND:
2255 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2256 ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
2257 break;
2258 default:
2259 ret = -EINVAL;
2260 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002261 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002262 break;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002263 case SND_SOC_DPCM_TRIGGER_BESPOKE:
2264 /* bespoke trigger() - handles both FE and BEs */
2265
Liam Girdwood103d84a2012-11-19 14:39:15 +00002266 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd %d\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002267 fe->dai_link->name, cmd);
2268
Kuninori Morimoto308193582020-04-24 08:15:09 +09002269 ret = snd_soc_pcm_dai_bespoke_trigger(substream, cmd);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002270 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002271 default:
Liam Girdwood103d84a2012-11-19 14:39:15 +00002272 dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd,
Liam Girdwood01d75842012-04-25 12:12:49 +01002273 fe->dai_link->name);
2274 ret = -EINVAL;
2275 goto out;
2276 }
2277
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002278 if (ret < 0) {
2279 dev_err(fe->dev, "ASoC: trigger FE cmd: %d failed: %d\n",
2280 cmd, ret);
2281 goto out;
2282 }
2283
Liam Girdwood01d75842012-04-25 12:12:49 +01002284 switch (cmd) {
2285 case SNDRV_PCM_TRIGGER_START:
2286 case SNDRV_PCM_TRIGGER_RESUME:
2287 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2288 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2289 break;
2290 case SNDRV_PCM_TRIGGER_STOP:
2291 case SNDRV_PCM_TRIGGER_SUSPEND:
Liam Girdwood01d75842012-04-25 12:12:49 +01002292 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2293 break;
Patrick Lai9f169b92016-12-31 22:44:39 -08002294 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2295 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2296 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002297 }
2298
2299out:
2300 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
2301 return ret;
2302}
2303
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002304static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
2305{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002306 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002307 int stream = substream->stream;
2308
2309 /* if FE's runtime_update is already set, we're in race;
2310 * process this trigger later at exit
2311 */
2312 if (fe->dpcm[stream].runtime_update != SND_SOC_DPCM_UPDATE_NO) {
2313 fe->dpcm[stream].trigger_pending = cmd + 1;
2314 return 0; /* delayed, assuming it's successful */
2315 }
2316
2317 /* we're alone, let's trigger */
2318 return dpcm_fe_dai_do_trigger(substream, cmd);
2319}
2320
Liam Girdwood23607022014-01-17 17:03:55 +00002321int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002322{
2323 struct snd_soc_dpcm *dpcm;
2324 int ret = 0;
2325
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002326 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002327
2328 struct snd_soc_pcm_runtime *be = dpcm->be;
2329 struct snd_pcm_substream *be_substream =
2330 snd_soc_dpcm_get_substream(be, stream);
2331
2332 /* is this op for this BE ? */
2333 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2334 continue;
2335
2336 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
Koro Chen95f444d2015-10-28 10:15:34 +08002337 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
Libin Yang5087a8f2019-05-08 10:32:41 +08002338 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND) &&
2339 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Liam Girdwood01d75842012-04-25 12:12:49 +01002340 continue;
2341
Liam Girdwood103d84a2012-11-19 14:39:15 +00002342 dev_dbg(be->dev, "ASoC: prepare BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002343 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002344
2345 ret = soc_pcm_prepare(be_substream);
2346 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002347 dev_err(be->dev, "ASoC: backend prepare failed %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002348 ret);
2349 break;
2350 }
2351
2352 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2353 }
2354 return ret;
2355}
2356
Mark Brown45c0a182012-05-09 21:46:27 +01002357static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002358{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002359 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002360 int stream = substream->stream, ret = 0;
2361
2362 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2363
Liam Girdwood103d84a2012-11-19 14:39:15 +00002364 dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002365
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002366 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002367
2368 /* there is no point preparing this FE if there are no BEs */
2369 if (list_empty(&fe->dpcm[stream].be_clients)) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002370 dev_err(fe->dev, "ASoC: no backend DAIs enabled for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002371 fe->dai_link->name);
2372 ret = -EINVAL;
2373 goto out;
2374 }
2375
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09002376 ret = dpcm_be_dai_prepare(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002377 if (ret < 0)
2378 goto out;
2379
2380 /* call prepare on the frontend */
2381 ret = soc_pcm_prepare(substream);
2382 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002383 dev_err(fe->dev,"ASoC: prepare FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002384 fe->dai_link->name);
2385 goto out;
2386 }
2387
2388 /* run the stream event for each BE */
2389 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
2390 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2391
2392out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002393 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002394 mutex_unlock(&fe->card->mutex);
2395
2396 return ret;
2397}
2398
Liam Girdwood618dae12012-04-25 12:12:51 +01002399static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
2400{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002401 struct snd_pcm_substream *substream =
2402 snd_soc_dpcm_get_substream(fe, stream);
2403 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01002404 int err;
Liam Girdwood01d75842012-04-25 12:12:49 +01002405
Liam Girdwood103d84a2012-11-19 14:39:15 +00002406 dev_dbg(fe->dev, "ASoC: runtime %s close on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002407 stream ? "capture" : "playback", fe->dai_link->name);
2408
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002409 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2410 /* call bespoke trigger - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002411 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002412 fe->dai_link->name);
2413
Kuninori Morimoto308193582020-04-24 08:15:09 +09002414 err = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002415 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002416 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002417 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002418 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002419 fe->dai_link->name);
2420
2421 err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
2422 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002423 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002424 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002425
2426 err = dpcm_be_dai_hw_free(fe, stream);
2427 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002428 dev_err(fe->dev,"ASoC: hw_free FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002429
2430 err = dpcm_be_dai_shutdown(fe, stream);
2431 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002432 dev_err(fe->dev,"ASoC: shutdown FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002433
2434 /* run the stream event for each BE */
2435 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2436
2437 return 0;
2438}
2439
2440static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
2441{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002442 struct snd_pcm_substream *substream =
2443 snd_soc_dpcm_get_substream(fe, stream);
Liam Girdwood618dae12012-04-25 12:12:51 +01002444 struct snd_soc_dpcm *dpcm;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002445 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01002446 int ret;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002447 unsigned long flags;
Liam Girdwood618dae12012-04-25 12:12:51 +01002448
Liam Girdwood103d84a2012-11-19 14:39:15 +00002449 dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002450 stream ? "capture" : "playback", fe->dai_link->name);
2451
2452 /* Only start the BE if the FE is ready */
2453 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
2454 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE)
2455 return -EINVAL;
2456
2457 /* startup must always be called for new BEs */
2458 ret = dpcm_be_dai_startup(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002459 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002460 goto disconnect;
Liam Girdwood618dae12012-04-25 12:12:51 +01002461
2462 /* keep going if FE state is > open */
2463 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN)
2464 return 0;
2465
2466 ret = dpcm_be_dai_hw_params(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002467 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002468 goto close;
Liam Girdwood618dae12012-04-25 12:12:51 +01002469
2470 /* keep going if FE state is > hw_params */
2471 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS)
2472 return 0;
2473
2474
2475 ret = dpcm_be_dai_prepare(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002476 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002477 goto hw_free;
Liam Girdwood618dae12012-04-25 12:12:51 +01002478
2479 /* run the stream event for each BE */
2480 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2481
2482 /* keep going if FE state is > prepare */
2483 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE ||
2484 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP)
2485 return 0;
2486
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002487 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2488 /* call trigger on the frontend - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002489 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002490 fe->dai_link->name);
Liam Girdwood618dae12012-04-25 12:12:51 +01002491
Kuninori Morimoto308193582020-04-24 08:15:09 +09002492 ret = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002493 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002494 dev_err(fe->dev,"ASoC: bespoke trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002495 goto hw_free;
2496 }
2497 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002498 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002499 fe->dai_link->name);
2500
2501 ret = dpcm_be_dai_trigger(fe, stream,
2502 SNDRV_PCM_TRIGGER_START);
2503 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002504 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002505 goto hw_free;
2506 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002507 }
2508
2509 return 0;
2510
2511hw_free:
2512 dpcm_be_dai_hw_free(fe, stream);
2513close:
2514 dpcm_be_dai_shutdown(fe, stream);
2515disconnect:
朱灿灿68f8043e2020-05-29 18:12:44 +08002516 /* disconnect any closed BEs */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002517 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002518 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood618dae12012-04-25 12:12:51 +01002519 struct snd_soc_pcm_runtime *be = dpcm->be;
朱灿灿68f8043e2020-05-29 18:12:44 +08002520 if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE)
2521 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
Liam Girdwood618dae12012-04-25 12:12:51 +01002522 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002523 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood618dae12012-04-25 12:12:51 +01002524
2525 return ret;
2526}
2527
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002528static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
2529{
2530 struct snd_soc_dapm_widget_list *list;
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002531 int stream;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002532 int count, paths;
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002533 int ret;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002534
Pierre-Louis Bossart96bf62f2020-06-12 15:35:07 -05002535 if (!fe->dai_link->dynamic)
2536 return 0;
2537
Bard Liao6e1276a2020-02-25 21:39:16 +08002538 if (fe->num_cpus > 1) {
2539 dev_err(fe->dev,
2540 "%s doesn't support Multi CPU yet\n", __func__);
2541 return -EINVAL;
2542 }
2543
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002544 /* only check active links */
Kuninori Morimotob3dea622020-05-15 09:46:51 +09002545 if (!snd_soc_dai_active(asoc_rtd_to_cpu(fe, 0)))
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002546 return 0;
2547
2548 /* DAPM sync will call this to update DSP paths */
2549 dev_dbg(fe->dev, "ASoC: DPCM %s runtime update for FE %s\n",
2550 new ? "new" : "old", fe->dai_link->name);
2551
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002552 for_each_pcm_streams(stream) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002553
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002554 /* skip if FE doesn't have playback/capture capability */
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002555 if (!snd_soc_dai_stream_valid(asoc_rtd_to_cpu(fe, 0), stream) ||
2556 !snd_soc_dai_stream_valid(asoc_rtd_to_codec(fe, 0), stream))
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002557 continue;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002558
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002559 /* skip if FE isn't currently playing/capturing */
Kuninori Morimotob3dea622020-05-15 09:46:51 +09002560 if (!snd_soc_dai_stream_active(asoc_rtd_to_cpu(fe, 0), stream) ||
2561 !snd_soc_dai_stream_active(asoc_rtd_to_codec(fe, 0), stream))
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002562 continue;
2563
2564 paths = dpcm_path_get(fe, stream, &list);
2565 if (paths < 0) {
2566 dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
2567 fe->dai_link->name,
2568 stream == SNDRV_PCM_STREAM_PLAYBACK ?
2569 "playback" : "capture");
2570 return paths;
2571 }
2572
2573 /* update any playback/capture paths */
2574 count = dpcm_process_paths(fe, stream, &list, new);
2575 if (count) {
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002576 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002577 if (new)
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002578 ret = dpcm_run_update_startup(fe, stream);
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002579 else
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002580 ret = dpcm_run_update_shutdown(fe, stream);
2581 if (ret < 0)
2582 dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n");
2583 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002584
2585 dpcm_clear_pending_state(fe, stream);
2586 dpcm_be_disconnect(fe, stream);
2587 }
2588
2589 dpcm_path_put(&list);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002590 }
2591
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002592 return 0;
2593}
2594
Liam Girdwood618dae12012-04-25 12:12:51 +01002595/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
2596 * any DAI links.
2597 */
Guennadi Liakhovetskif17a1472020-03-12 10:52:14 +01002598int snd_soc_dpcm_runtime_update(struct snd_soc_card *card)
Liam Girdwood618dae12012-04-25 12:12:51 +01002599{
Mengdong Lin1a497982015-11-18 02:34:11 -05002600 struct snd_soc_pcm_runtime *fe;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002601 int ret = 0;
Liam Girdwood618dae12012-04-25 12:12:51 +01002602
Liam Girdwood618dae12012-04-25 12:12:51 +01002603 mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002604 /* shutdown all old paths first */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002605 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002606 ret = soc_dpcm_fe_runtime_update(fe, 0);
2607 if (ret)
2608 goto out;
Liam Girdwood618dae12012-04-25 12:12:51 +01002609 }
2610
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002611 /* bring new paths up */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002612 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002613 ret = soc_dpcm_fe_runtime_update(fe, 1);
2614 if (ret)
2615 goto out;
2616 }
2617
2618out:
Liam Girdwood618dae12012-04-25 12:12:51 +01002619 mutex_unlock(&card->mutex);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002620 return ret;
Liam Girdwood618dae12012-04-25 12:12:51 +01002621}
Guennadi Liakhovetskif17a1472020-03-12 10:52:14 +01002622EXPORT_SYMBOL_GPL(snd_soc_dpcm_runtime_update);
Liam Girdwood01d75842012-04-25 12:12:49 +01002623
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002624static void dpcm_fe_dai_cleanup(struct snd_pcm_substream *fe_substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002625{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002626 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002627 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002628 int stream = fe_substream->stream;
Kuninori Morimoto30fca262020-03-06 10:09:44 +09002629
2630 /* mark FE's links ready to prune */
2631 for_each_dpcm_be(fe, stream, dpcm)
2632 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2633
2634 dpcm_be_disconnect(fe, stream);
2635
2636 fe->dpcm[stream].runtime = NULL;
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002637}
2638
2639static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
2640{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002641 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002642 int ret;
2643
2644 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2645 ret = dpcm_fe_dai_shutdown(fe_substream);
2646
2647 dpcm_fe_dai_cleanup(fe_substream);
2648
Kuninori Morimoto30fca262020-03-06 10:09:44 +09002649 mutex_unlock(&fe->card->mutex);
2650 return ret;
2651}
2652
Liam Girdwood01d75842012-04-25 12:12:49 +01002653static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
2654{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002655 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002656 struct snd_soc_dapm_widget_list *list;
2657 int ret;
2658 int stream = fe_substream->stream;
2659
2660 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2661 fe->dpcm[stream].runtime = fe_substream->runtime;
2662
Qiao Zhou8f70e512014-09-10 17:54:07 +08002663 ret = dpcm_path_get(fe, stream, &list);
2664 if (ret < 0) {
Kuninori Morimotocae06eb2020-02-17 17:28:11 +09002665 goto open_end;
Qiao Zhou8f70e512014-09-10 17:54:07 +08002666 } else if (ret == 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002667 dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002668 fe->dai_link->name, stream ? "capture" : "playback");
Liam Girdwood01d75842012-04-25 12:12:49 +01002669 }
2670
2671 /* calculate valid and active FE <-> BE dpcms */
2672 dpcm_process_paths(fe, stream, &list, 1);
2673
2674 ret = dpcm_fe_dai_startup(fe_substream);
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002675 if (ret < 0)
2676 dpcm_fe_dai_cleanup(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002677
2678 dpcm_clear_pending_state(fe, stream);
2679 dpcm_path_put(&list);
Kuninori Morimotocae06eb2020-02-17 17:28:11 +09002680open_end:
Liam Girdwood01d75842012-04-25 12:12:49 +01002681 mutex_unlock(&fe->card->mutex);
2682 return ret;
2683}
2684
Liam Girdwoodddee6272011-06-09 14:45:53 +01002685/* create a new pcm */
2686int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
2687{
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002688 struct snd_soc_dai *codec_dai;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002689 struct snd_soc_dai *cpu_dai;
Kuninori Morimoto2b544dd2019-10-15 12:59:31 +09002690 struct snd_soc_component *component;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002691 struct snd_pcm *pcm;
2692 char new_name[64];
2693 int ret = 0, playback = 0, capture = 0;
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002694 int stream;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002695 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002696
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002697 if (rtd->dai_link->dynamic && rtd->num_cpus > 1) {
2698 dev_err(rtd->dev,
2699 "DPCM doesn't support Multi CPU for Front-Ends yet\n");
2700 return -EINVAL;
2701 }
Stephan Gerhold9b5db052020-04-15 12:49:28 +02002702
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002703 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
2704 if (rtd->dai_link->dpcm_playback) {
2705 stream = SNDRV_PCM_STREAM_PLAYBACK;
2706
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002707 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
2708 if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
2709 playback = 1;
2710 break;
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002711 }
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002712 }
2713
2714 if (!playback) {
2715 dev_err(rtd->card->dev,
2716 "No CPU DAIs support playback for stream %s\n",
2717 rtd->dai_link->stream_name);
2718 return -EINVAL;
2719 }
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002720 }
2721 if (rtd->dai_link->dpcm_capture) {
2722 stream = SNDRV_PCM_STREAM_CAPTURE;
2723
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002724 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
2725 if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
2726 capture = 1;
2727 break;
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002728 }
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002729 }
2730
2731 if (!capture) {
2732 dev_err(rtd->card->dev,
2733 "No CPU DAIs support capture for stream %s\n",
2734 rtd->dai_link->stream_name);
2735 return -EINVAL;
2736 }
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002737 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002738 } else {
Jerome Bruneta3420312019-07-25 18:59:47 +02002739 /* Adapt stream for codec2codec links */
Stephan Gerholda4877a62020-02-18 11:38:24 +01002740 int cpu_capture = rtd->dai_link->params ?
2741 SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
2742 int cpu_playback = rtd->dai_link->params ?
2743 SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
Jerome Bruneta3420312019-07-25 18:59:47 +02002744
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09002745 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002746 if (rtd->num_cpus == 1) {
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002747 cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002748 } else if (rtd->num_cpus == rtd->num_codecs) {
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002749 cpu_dai = asoc_rtd_to_cpu(rtd, i);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002750 } else {
2751 dev_err(rtd->card->dev,
2752 "N cpus to M codecs link is not supported yet\n");
2753 return -EINVAL;
2754 }
2755
Kuninori Morimoto467fece2019-07-22 10:36:16 +09002756 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
Stephan Gerholda4877a62020-02-18 11:38:24 +01002757 snd_soc_dai_stream_valid(cpu_dai, cpu_playback))
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002758 playback = 1;
Kuninori Morimoto467fece2019-07-22 10:36:16 +09002759 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
Stephan Gerholda4877a62020-02-18 11:38:24 +01002760 snd_soc_dai_stream_valid(cpu_dai, cpu_capture))
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002761 capture = 1;
2762 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002763 }
Sangsu Parka5002312012-01-02 17:15:10 +09002764
Fabio Estevamd6bead02013-08-29 10:32:13 -03002765 if (rtd->dai_link->playback_only) {
2766 playback = 1;
2767 capture = 0;
2768 }
2769
2770 if (rtd->dai_link->capture_only) {
2771 playback = 0;
2772 capture = 1;
2773 }
2774
Liam Girdwood01d75842012-04-25 12:12:49 +01002775 /* create the PCM */
Jerome Bruneta3420312019-07-25 18:59:47 +02002776 if (rtd->dai_link->params) {
2777 snprintf(new_name, sizeof(new_name), "codec2codec(%s)",
2778 rtd->dai_link->stream_name);
2779
2780 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
2781 playback, capture, &pcm);
2782 } else if (rtd->dai_link->no_pcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002783 snprintf(new_name, sizeof(new_name), "(%s)",
2784 rtd->dai_link->stream_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002785
Liam Girdwood01d75842012-04-25 12:12:49 +01002786 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
2787 playback, capture, &pcm);
2788 } else {
2789 if (rtd->dai_link->dynamic)
2790 snprintf(new_name, sizeof(new_name), "%s (*)",
2791 rtd->dai_link->stream_name);
2792 else
2793 snprintf(new_name, sizeof(new_name), "%s %s-%d",
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002794 rtd->dai_link->stream_name,
2795 (rtd->num_codecs > 1) ?
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002796 "multicodec" : asoc_rtd_to_codec(rtd, 0)->name, num);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002797
Liam Girdwood01d75842012-04-25 12:12:49 +01002798 ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
2799 capture, &pcm);
2800 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01002801 if (ret < 0) {
Pierre-Louis Bossart799827a2020-06-12 15:40:49 -05002802 dev_err(rtd->card->dev, "ASoC: can't create pcm %s for dailink %s: %d\n",
2803 new_name, rtd->dai_link->name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002804 return ret;
2805 }
Liam Girdwood103d84a2012-11-19 14:39:15 +00002806 dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002807
2808 /* DAPM dai link stream work */
Jerome Bruneta3420312019-07-25 18:59:47 +02002809 if (rtd->dai_link->params)
Curtis Malainey4bf2e382019-12-03 09:30:07 -08002810 rtd->close_delayed_work_func = codec2codec_close_delayed_work;
Jerome Bruneta3420312019-07-25 18:59:47 +02002811 else
Kuninori Morimoto83f94a22020-01-10 11:36:17 +09002812 rtd->close_delayed_work_func = snd_soc_close_delayed_work;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002813
Vinod Koul48c76992015-02-12 09:59:53 +05302814 pcm->nonatomic = rtd->dai_link->nonatomic;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002815 rtd->pcm = pcm;
2816 pcm->private_data = rtd;
Liam Girdwood01d75842012-04-25 12:12:49 +01002817
Jerome Bruneta3420312019-07-25 18:59:47 +02002818 if (rtd->dai_link->no_pcm || rtd->dai_link->params) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002819 if (playback)
2820 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
2821 if (capture)
2822 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
2823 goto out;
2824 }
2825
2826 /* ASoC PCM operations */
2827 if (rtd->dai_link->dynamic) {
2828 rtd->ops.open = dpcm_fe_dai_open;
2829 rtd->ops.hw_params = dpcm_fe_dai_hw_params;
2830 rtd->ops.prepare = dpcm_fe_dai_prepare;
2831 rtd->ops.trigger = dpcm_fe_dai_trigger;
2832 rtd->ops.hw_free = dpcm_fe_dai_hw_free;
2833 rtd->ops.close = dpcm_fe_dai_close;
2834 rtd->ops.pointer = soc_pcm_pointer;
2835 } else {
2836 rtd->ops.open = soc_pcm_open;
2837 rtd->ops.hw_params = soc_pcm_hw_params;
2838 rtd->ops.prepare = soc_pcm_prepare;
2839 rtd->ops.trigger = soc_pcm_trigger;
2840 rtd->ops.hw_free = soc_pcm_hw_free;
2841 rtd->ops.close = soc_pcm_close;
2842 rtd->ops.pointer = soc_pcm_pointer;
2843 }
2844
Kuninori Morimoto613fb502020-01-10 11:35:21 +09002845 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto2b544dd2019-10-15 12:59:31 +09002846 const struct snd_soc_component_driver *drv = component->driver;
Kuninori Morimotob8135862017-10-11 01:37:23 +00002847
Takashi Iwai3b1c9522019-11-21 20:07:08 +01002848 if (drv->ioctl)
2849 rtd->ops.ioctl = snd_soc_pcm_component_ioctl;
Takashi Iwai1e5ddb62019-11-21 20:07:09 +01002850 if (drv->sync_stop)
2851 rtd->ops.sync_stop = snd_soc_pcm_component_sync_stop;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002852 if (drv->copy_user)
Kuninori Morimoto82d81f52019-07-26 13:51:56 +09002853 rtd->ops.copy_user = snd_soc_pcm_component_copy_user;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002854 if (drv->page)
Kuninori Morimoto9c712e42019-07-26 13:52:00 +09002855 rtd->ops.page = snd_soc_pcm_component_page;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002856 if (drv->mmap)
Kuninori Morimoto205875e2019-07-26 13:52:04 +09002857 rtd->ops.mmap = snd_soc_pcm_component_mmap;
Kuninori Morimotob8135862017-10-11 01:37:23 +00002858 }
2859
Liam Girdwoodddee6272011-06-09 14:45:53 +01002860 if (playback)
Liam Girdwood01d75842012-04-25 12:12:49 +01002861 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002862
2863 if (capture)
Liam Girdwood01d75842012-04-25 12:12:49 +01002864 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002865
Kuninori Morimotob2b2afb2019-11-18 10:50:32 +09002866 ret = snd_soc_pcm_component_new(rtd);
Kuninori Morimoto74842912019-07-26 13:52:08 +09002867 if (ret < 0) {
Pierre-Louis Bossart799827a2020-06-12 15:40:49 -05002868 dev_err(rtd->dev, "ASoC: pcm %s constructor failed for dailink %s: %d\n",
2869 new_name, rtd->dai_link->name, ret);
Kuninori Morimoto74842912019-07-26 13:52:08 +09002870 return ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002871 }
Johan Hovoldc641e5b2017-07-12 17:55:29 +02002872
Takashi Iwai3d21ef02019-01-11 15:58:39 +01002873 pcm->no_device_suspend = true;
Liam Girdwood01d75842012-04-25 12:12:49 +01002874out:
Pierre-Louis Bossart1d5cd522020-06-12 15:40:50 -05002875 dev_dbg(rtd->card->dev, "%s <-> %s mapping ok\n",
2876 (rtd->num_codecs > 1) ? "multicodec" : asoc_rtd_to_codec(rtd, 0)->name,
2877 (rtd->num_cpus > 1) ? "multicpu" : asoc_rtd_to_cpu(rtd, 0)->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002878 return ret;
2879}
Liam Girdwood01d75842012-04-25 12:12:49 +01002880
2881/* is the current PCM operation for this FE ? */
2882int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream)
2883{
2884 if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE)
2885 return 1;
2886 return 0;
2887}
2888EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update);
2889
2890/* is the current PCM operation for this BE ? */
2891int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
2892 struct snd_soc_pcm_runtime *be, int stream)
2893{
2894 if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) ||
2895 ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) &&
2896 be->dpcm[stream].runtime_update))
2897 return 1;
2898 return 0;
2899}
2900EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update);
2901
2902/* get the substream for this BE */
2903struct snd_pcm_substream *
2904 snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream)
2905{
2906 return be->pcm->streams[stream].substream;
2907}
2908EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream);
2909
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002910static int snd_soc_dpcm_check_state(struct snd_soc_pcm_runtime *fe,
2911 struct snd_soc_pcm_runtime *be,
2912 int stream,
2913 const enum snd_soc_dpcm_state *states,
2914 int num_states)
Liam Girdwood01d75842012-04-25 12:12:49 +01002915{
2916 struct snd_soc_dpcm *dpcm;
2917 int state;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002918 int ret = 1;
2919 unsigned long flags;
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002920 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01002921
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002922 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00002923 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002924
2925 if (dpcm->fe == fe)
2926 continue;
2927
2928 state = dpcm->fe->dpcm[stream].state;
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002929 for (i = 0; i < num_states; i++) {
2930 if (state == states[i]) {
2931 ret = 0;
2932 break;
2933 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002934 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002935 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002936 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01002937
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002938 /* it's safe to do this BE DAI */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002939 return ret;
Liam Girdwood01d75842012-04-25 12:12:49 +01002940}
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002941
2942/*
2943 * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE
2944 * are not running, paused or suspended for the specified stream direction.
2945 */
2946int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
2947 struct snd_soc_pcm_runtime *be, int stream)
2948{
2949 const enum snd_soc_dpcm_state state[] = {
2950 SND_SOC_DPCM_STATE_START,
2951 SND_SOC_DPCM_STATE_PAUSED,
2952 SND_SOC_DPCM_STATE_SUSPEND,
2953 };
2954
2955 return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
2956}
Liam Girdwood01d75842012-04-25 12:12:49 +01002957EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop);
2958
2959/*
2960 * We can only change hw params a BE DAI if any of it's FE are not prepared,
2961 * running, paused or suspended for the specified stream direction.
2962 */
2963int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
2964 struct snd_soc_pcm_runtime *be, int stream)
2965{
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002966 const enum snd_soc_dpcm_state state[] = {
2967 SND_SOC_DPCM_STATE_START,
2968 SND_SOC_DPCM_STATE_PAUSED,
2969 SND_SOC_DPCM_STATE_SUSPEND,
2970 SND_SOC_DPCM_STATE_PREPARE,
2971 };
Liam Girdwood01d75842012-04-25 12:12:49 +01002972
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002973 return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
Liam Girdwood01d75842012-04-25 12:12:49 +01002974}
2975EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);