blob: b79f064887d4376fe7e6b4b4e064851e7754b1ec [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 Morimoto9c6d7f92020-12-11 14:55:16 +0900206/* Set FE's runtime_update state; the state is protected via PCM stream lock
207 * for avoiding the race with trigger callback.
208 * If the state is unset and a trigger is pending while the previous operation,
209 * process the pending trigger action here.
210 */
211static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
212static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
213 int stream, enum snd_soc_dpcm_update state)
214{
215 struct snd_pcm_substream *substream =
216 snd_soc_dpcm_get_substream(fe, stream);
217
218 snd_pcm_stream_lock_irq(substream);
219 if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) {
220 dpcm_fe_dai_do_trigger(substream,
221 fe->dpcm[stream].trigger_pending - 1);
222 fe->dpcm[stream].trigger_pending = 0;
223 }
224 fe->dpcm[stream].runtime_update = state;
225 snd_pcm_stream_unlock_irq(substream);
226}
227
Kuninori Morimotoa7e204442020-12-11 14:55:22 +0900228static void dpcm_set_be_update_state(struct snd_soc_pcm_runtime *be,
229 int stream, enum snd_soc_dpcm_update state)
230{
231 be->dpcm[stream].runtime_update = state;
232}
233
Kuninori Morimotod9051d82020-05-15 09:46:21 +0900234/**
235 * snd_soc_runtime_action() - Increment/Decrement active count for
236 * PCM runtime components
237 * @rtd: ASoC PCM runtime that is activated
238 * @stream: Direction of the PCM stream
Colton Lewisb6d6e9e2020-06-26 05:40:24 +0000239 * @action: Activate stream if 1. Deactivate if -1.
Kuninori Morimotod9051d82020-05-15 09:46:21 +0900240 *
241 * Increments/Decrements the active count for all the DAIs and components
242 * attached to a PCM runtime.
243 * Should typically be called when a stream is opened.
244 *
245 * Must be called with the rtd->card->pcm_mutex being held
246 */
247void snd_soc_runtime_action(struct snd_soc_pcm_runtime *rtd,
248 int stream, int action)
Kuninori Morimoto7a5aaba2020-02-10 12:14:12 +0900249{
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900250 struct snd_soc_dai *dai;
Kuninori Morimoto7a5aaba2020-02-10 12:14:12 +0900251 int i;
252
253 lockdep_assert_held(&rtd->card->pcm_mutex);
254
Kuninori Morimotodc829102020-05-15 09:46:27 +0900255 for_each_rtd_dais(rtd, i, dai)
256 snd_soc_dai_action(dai, stream, action);
Kuninori Morimoto7a5aaba2020-02-10 12:14:12 +0900257}
Kuninori Morimotod9051d82020-05-15 09:46:21 +0900258EXPORT_SYMBOL_GPL(snd_soc_runtime_action);
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100259
260/**
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100261 * snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay
262 * @rtd: The ASoC PCM runtime that should be checked.
263 *
264 * This function checks whether the power down delay should be ignored for a
265 * specific PCM runtime. Returns true if the delay is 0, if it the DAI link has
266 * been configured to ignore the delay, or if none of the components benefits
267 * from having the delay.
268 */
269bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
270{
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000271 struct snd_soc_component *component;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200272 bool ignore = true;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900273 int i;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200274
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100275 if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
276 return true;
277
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900278 for_each_rtd_components(rtd, i, component)
Kuninori Morimoto72c38182018-01-19 05:21:19 +0000279 ignore &= !component->driver->use_pmdown_time;
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000280
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000281 return ignore;
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100282}
283
284/**
Lars-Peter Clausen90996f42013-05-14 11:05:30 +0200285 * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
286 * @substream: the pcm substream
287 * @hw: the hardware parameters
288 *
289 * Sets the substream runtime hardware parameters.
290 */
291int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
292 const struct snd_pcm_hardware *hw)
293{
294 struct snd_pcm_runtime *runtime = substream->runtime;
295 runtime->hw.info = hw->info;
296 runtime->hw.formats = hw->formats;
297 runtime->hw.period_bytes_min = hw->period_bytes_min;
298 runtime->hw.period_bytes_max = hw->period_bytes_max;
299 runtime->hw.periods_min = hw->periods_min;
300 runtime->hw.periods_max = hw->periods_max;
301 runtime->hw.buffer_bytes_max = hw->buffer_bytes_max;
302 runtime->hw.fifo_size = hw->fifo_size;
303 return 0;
304}
305EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
306
Liam Girdwood01d75842012-04-25 12:12:49 +0100307/* DPCM stream event, send event to FE and all active BEs. */
Liam Girdwood23607022014-01-17 17:03:55 +0000308int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
Liam Girdwood01d75842012-04-25 12:12:49 +0100309 int event)
310{
311 struct snd_soc_dpcm *dpcm;
312
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +0000313 for_each_dpcm_be(fe, dir, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +0100314
315 struct snd_soc_pcm_runtime *be = dpcm->be;
316
Liam Girdwood103d84a2012-11-19 14:39:15 +0000317 dev_dbg(be->dev, "ASoC: BE %s event %d dir %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +0100318 be->dai_link->name, event, dir);
319
Banajit Goswamib1cd2e32017-07-14 23:15:05 -0700320 if ((event == SND_SOC_DAPM_STREAM_STOP) &&
321 (be->dpcm[dir].users >= 1))
322 continue;
323
Liam Girdwood01d75842012-04-25 12:12:49 +0100324 snd_soc_dapm_stream_event(be, dir, event);
325 }
326
327 snd_soc_dapm_stream_event(fe, dir, event);
328
329 return 0;
330}
331
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900332static void soc_pcm_set_dai_params(struct snd_soc_dai *dai,
333 struct snd_pcm_hw_params *params)
334{
335 if (params) {
336 dai->rate = params_rate(params);
337 dai->channels = params_channels(params);
338 dai->sample_bits = snd_pcm_format_physical_width(params_format(params));
339 } else {
340 dai->rate = 0;
341 dai->channels = 0;
342 dai->sample_bits = 0;
343 }
344}
345
Dong Aisheng17841022011-08-29 17:15:14 +0800346static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
347 struct snd_soc_dai *soc_dai)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100348{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900349 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100350 int ret;
351
Kuninori Morimotofac110c2021-01-15 13:56:35 +0900352#define __soc_pcm_apply_symmetry(name, NAME) \
353 if (soc_dai->name && (soc_dai->driver->symmetric_##name || \
354 rtd->dai_link->symmetric_##name)) { \
355 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %s to %d\n",\
356 #name, soc_dai->name); \
357 \
358 ret = snd_pcm_hw_constraint_single(substream->runtime, \
359 SNDRV_PCM_HW_PARAM_##NAME,\
360 soc_dai->name); \
361 if (ret < 0) { \
362 dev_err(soc_dai->dev, \
363 "ASoC: Unable to apply %s constraint: %d\n",\
364 #name, ret); \
365 return ret; \
366 } \
Liam Girdwoodddee6272011-06-09 14:45:53 +0100367 }
368
Kuninori Morimotofac110c2021-01-15 13:56:35 +0900369 __soc_pcm_apply_symmetry(rate, RATE);
370 __soc_pcm_apply_symmetry(channels, CHANNELS);
371 __soc_pcm_apply_symmetry(sample_bits, SAMPLE_BITS);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100372
373 return 0;
374}
375
Nicolin Chen3635bf02013-11-13 18:56:24 +0800376static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
377 struct snd_pcm_hw_params *params)
378{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900379 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900380 struct snd_soc_dai d;
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900381 struct snd_soc_dai *dai;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800382 struct snd_soc_dai *cpu_dai;
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900383 unsigned int symmetry, i;
Nicolin Chen3635bf02013-11-13 18:56:24 +0800384
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900385 soc_pcm_set_dai_params(&d, params);
Nicolin Chen3635bf02013-11-13 18:56:24 +0800386
Kuninori Morimoto3a906722021-01-15 13:56:39 +0900387#define __soc_pcm_params_symmetry(name) \
388 symmetry = rtd->dai_link->symmetric_##name; \
389 for_each_rtd_dais(rtd, i, dai) \
390 symmetry |= dai->driver->symmetric_##name; \
391 \
392 if (symmetry) \
393 for_each_rtd_cpu_dais(rtd, i, cpu_dai) \
394 if (cpu_dai->name && cpu_dai->name != d.name) { \
395 dev_err(rtd->dev, "ASoC: unmatched %s symmetry: %d - %d\n", \
396 #name, cpu_dai->name, d.name); \
397 return -EINVAL; \
398 }
399
Nicolin Chen3635bf02013-11-13 18:56:24 +0800400 /* reject unmatched parameters when applying symmetry */
Kuninori Morimoto3a906722021-01-15 13:56:39 +0900401 __soc_pcm_params_symmetry(rate);
402 __soc_pcm_params_symmetry(channels);
403 __soc_pcm_params_symmetry(sample_bits);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100404
405 return 0;
406}
407
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100408static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream)
409{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900410 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100411 struct snd_soc_dai_link *link = rtd->dai_link;
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900412 struct snd_soc_dai *dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200413 unsigned int symmetry, i;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100414
Kuninori Morimotof14654d2021-01-15 13:52:54 +0900415 symmetry = link->symmetric_rate ||
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800416 link->symmetric_channels ||
Kuninori Morimotof14654d2021-01-15 13:52:54 +0900417 link->symmetric_sample_bits;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800418
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900419 for_each_rtd_dais(rtd, i, dai)
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800420 symmetry = symmetry ||
Kuninori Morimotof14654d2021-01-15 13:52:54 +0900421 dai->driver->symmetric_rate ||
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900422 dai->driver->symmetric_channels ||
Kuninori Morimotof14654d2021-01-15 13:52:54 +0900423 dai->driver->symmetric_sample_bits;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200424
425 return symmetry;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100426}
427
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200428static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits)
Mark Brown58ba9b22012-01-16 18:38:51 +0000429{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900430 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Takashi Iwaic6068d32014-12-31 17:10:34 +0100431 int ret;
Mark Brown58ba9b22012-01-16 18:38:51 +0000432
433 if (!bits)
434 return;
435
Lars-Peter Clausen0e2a3752014-12-29 18:43:38 +0100436 ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 0, bits);
437 if (ret != 0)
438 dev_warn(rtd->dev, "ASoC: Failed to set MSB %d: %d\n",
439 bits, ret);
Mark Brown58ba9b22012-01-16 18:38:51 +0000440}
441
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200442static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200443{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900444 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800445 struct snd_soc_dai *cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200446 struct snd_soc_dai *codec_dai;
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900447 struct snd_soc_pcm_stream *pcm_codec, *pcm_cpu;
448 int stream = substream->stream;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200449 int i;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800450 unsigned int bits = 0, cpu_bits = 0;
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200451
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900452 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900453 pcm_codec = snd_soc_dai_get_pcm_stream(codec_dai, stream);
454
455 if (pcm_codec->sig_bits == 0) {
456 bits = 0;
457 break;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200458 }
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900459 bits = max(pcm_codec->sig_bits, bits);
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200460 }
461
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900462 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800463 pcm_cpu = snd_soc_dai_get_pcm_stream(cpu_dai, stream);
464
465 if (pcm_cpu->sig_bits == 0) {
466 cpu_bits = 0;
467 break;
468 }
469 cpu_bits = max(pcm_cpu->sig_bits, cpu_bits);
470 }
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900471
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200472 soc_pcm_set_msb(substream, bits);
473 soc_pcm_set_msb(substream, cpu_bits);
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200474}
475
Samuel Holland5854a462020-03-04 23:11:42 -0600476/**
477 * snd_soc_runtime_calc_hw() - Calculate hw limits for a PCM stream
478 * @rtd: ASoC PCM runtime
479 * @hw: PCM hardware parameters (output)
480 * @stream: Direction of the PCM stream
481 *
482 * Calculates the subset of stream parameters supported by all DAIs
483 * associated with the PCM stream.
484 */
485int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd,
486 struct snd_pcm_hardware *hw, int stream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200487{
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000488 struct snd_soc_dai *codec_dai;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800489 struct snd_soc_dai *cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200490 struct snd_soc_pcm_stream *codec_stream;
491 struct snd_soc_pcm_stream *cpu_stream;
492 unsigned int chan_min = 0, chan_max = UINT_MAX;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800493 unsigned int cpu_chan_min = 0, cpu_chan_max = UINT_MAX;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200494 unsigned int rate_min = 0, rate_max = UINT_MAX;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800495 unsigned int cpu_rate_min = 0, cpu_rate_max = UINT_MAX;
496 unsigned int rates = UINT_MAX, cpu_rates = UINT_MAX;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200497 u64 formats = ULLONG_MAX;
498 int i;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100499
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800500 /* first calculate min/max only for CPUs in the DAI link */
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900501 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800502
503 /*
504 * Skip CPUs which don't support the current stream type.
505 * Otherwise, since the rate, channel, and format values will
506 * zero in that case, we would have no usable settings left,
507 * causing the resulting setup to fail.
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800508 */
Samuel Holland5854a462020-03-04 23:11:42 -0600509 if (!snd_soc_dai_stream_valid(cpu_dai, stream))
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800510 continue;
511
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800512 cpu_stream = snd_soc_dai_get_pcm_stream(cpu_dai, stream);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100513
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800514 cpu_chan_min = max(cpu_chan_min, cpu_stream->channels_min);
515 cpu_chan_max = min(cpu_chan_max, cpu_stream->channels_max);
516 cpu_rate_min = max(cpu_rate_min, cpu_stream->rate_min);
517 cpu_rate_max = min_not_zero(cpu_rate_max, cpu_stream->rate_max);
518 formats &= cpu_stream->formats;
519 cpu_rates = snd_pcm_rate_mask_intersect(cpu_stream->rates,
520 cpu_rates);
521 }
522
523 /* second calculate min/max only for CODECs in the DAI link */
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900524 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200525
526 /*
527 * Skip CODECs which don't support the current stream type.
528 * Otherwise, since the rate, channel, and format values will
529 * zero in that case, we would have no usable settings left,
530 * causing the resulting setup to fail.
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200531 */
Kuninori Morimoto25c2f512020-02-27 10:54:38 +0900532 if (!snd_soc_dai_stream_valid(codec_dai, stream))
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200533 continue;
534
Kuninori Morimotoacf253c2020-02-19 15:56:30 +0900535 codec_stream = snd_soc_dai_get_pcm_stream(codec_dai, stream);
536
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200537 chan_min = max(chan_min, codec_stream->channels_min);
538 chan_max = min(chan_max, codec_stream->channels_max);
539 rate_min = max(rate_min, codec_stream->rate_min);
540 rate_max = min_not_zero(rate_max, codec_stream->rate_max);
541 formats &= codec_stream->formats;
542 rates = snd_pcm_rate_mask_intersect(codec_stream->rates, rates);
543 }
544
Samuel Holland5854a462020-03-04 23:11:42 -0600545 /* Verify both a valid CPU DAI and a valid CODEC DAI were found */
546 if (!chan_min || !cpu_chan_min)
547 return -EINVAL;
548
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200549 /*
550 * chan min/max cannot be enforced if there are multiple CODEC DAIs
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800551 * connected to CPU DAI(s), use CPU DAI's directly and let
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200552 * channel allocation be fixed up later
553 */
554 if (rtd->num_codecs > 1) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800555 chan_min = cpu_chan_min;
556 chan_max = cpu_chan_max;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200557 }
558
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800559 /* finally find a intersection between CODECs and CPUs */
560 hw->channels_min = max(chan_min, cpu_chan_min);
561 hw->channels_max = min(chan_max, cpu_chan_max);
Samuel Holland5854a462020-03-04 23:11:42 -0600562 hw->formats = formats;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800563 hw->rates = snd_pcm_rate_mask_intersect(rates, cpu_rates);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100564
Samuel Holland5854a462020-03-04 23:11:42 -0600565 snd_pcm_hw_limit_rates(hw);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100566
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800567 hw->rate_min = max(hw->rate_min, cpu_rate_min);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200568 hw->rate_min = max(hw->rate_min, rate_min);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800569 hw->rate_max = min_not_zero(hw->rate_max, cpu_rate_max);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200570 hw->rate_max = min_not_zero(hw->rate_max, rate_max);
Samuel Holland5854a462020-03-04 23:11:42 -0600571
572 return 0;
573}
574EXPORT_SYMBOL_GPL(snd_soc_runtime_calc_hw);
575
576static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
577{
578 struct snd_pcm_hardware *hw = &substream->runtime->hw;
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900579 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Samuel Holland5854a462020-03-04 23:11:42 -0600580 u64 formats = hw->formats;
581
582 /*
583 * At least one CPU and one CODEC should match. Otherwise, we should
584 * have bailed out on a higher level, since there would be no CPU or
585 * CODEC to support the transfer direction in that case.
586 */
587 snd_soc_runtime_calc_hw(rtd, hw, substream->stream);
588
589 if (formats)
590 hw->formats &= formats;
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200591}
592
Kuninori Morimotodd039072020-02-10 12:14:37 +0900593static int soc_pcm_components_open(struct snd_pcm_substream *substream)
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900594{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900595 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900596 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900597 int i, ret = 0;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900598
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900599 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto51aff912020-09-28 09:01:04 +0900600 ret = snd_soc_component_module_get_when_open(component, substream);
Kuninori Morimotobcae16312020-09-28 09:01:36 +0900601 if (ret < 0)
Kai Vehmanend2aaa8d2020-02-20 11:49:55 +0200602 break;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900603
Kuninori Morimotoae2f4842019-07-26 13:50:01 +0900604 ret = snd_soc_component_open(component, substream);
Kuninori Morimotobcae16312020-09-28 09:01:36 +0900605 if (ret < 0)
Kai Vehmanend2aaa8d2020-02-20 11:49:55 +0200606 break;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900607 }
Kuninori Morimotodd039072020-02-10 12:14:37 +0900608
Kai Vehmanend2aaa8d2020-02-20 11:49:55 +0200609 return ret;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900610}
611
Kuninori Morimoto51aff912020-09-28 09:01:04 +0900612static int soc_pcm_components_close(struct snd_pcm_substream *substream,
613 int rollback)
Charles Keepax244e2932018-06-19 16:22:09 +0100614{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900615 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Charles Keepax244e2932018-06-19 16:22:09 +0100616 struct snd_soc_component *component;
Kuninori Morimotoe82ebff2020-02-10 12:14:26 +0900617 int i, r, ret = 0;
Charles Keepax244e2932018-06-19 16:22:09 +0100618
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900619 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto51aff912020-09-28 09:01:04 +0900620 r = snd_soc_component_close(component, substream, rollback);
Kuninori Morimotoe82ebff2020-02-10 12:14:26 +0900621 if (r < 0)
622 ret = r; /* use last ret */
623
Kuninori Morimoto51aff912020-09-28 09:01:04 +0900624 snd_soc_component_module_put_when_close(component, substream, rollback);
Charles Keepax244e2932018-06-19 16:22:09 +0100625 }
626
Kuninori Morimoto3672beb2019-07-26 13:50:07 +0900627 return ret;
Charles Keepax244e2932018-06-19 16:22:09 +0100628}
629
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900630static int soc_pcm_clean(struct snd_pcm_substream *substream, int rollback)
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900631{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900632 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900633 struct snd_soc_component *component;
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900634 struct snd_soc_dai *dai;
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900635 int i;
636
637 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
638
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900639 if (!rollback)
640 snd_soc_runtime_deactivate(rtd, substream->stream);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900641
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900642 for_each_rtd_dais(rtd, i, dai)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900643 snd_soc_dai_shutdown(dai, substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900644
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900645 snd_soc_link_shutdown(substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900646
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900647 soc_pcm_components_close(substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900648
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900649
650 mutex_unlock(&rtd->card->pcm_mutex);
651
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900652 snd_soc_pcm_component_pm_runtime_put(rtd, substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900653
654 for_each_rtd_components(rtd, i, component)
Kuninori Morimotob3dea622020-05-15 09:46:51 +0900655 if (!snd_soc_component_active(component))
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900656 pinctrl_pm_select_sleep_state(component->dev);
657
658 return 0;
659}
660
661/*
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900662 * Called by ALSA when a PCM substream is closed. Private data can be
663 * freed here. The cpu DAI, codec DAI, machine and components are also
664 * shutdown.
665 */
666static int soc_pcm_close(struct snd_pcm_substream *substream)
667{
668 return soc_pcm_clean(substream, 0);
669}
670
671/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100672 * Called by ALSA when a PCM substream is opened, the runtime->hw record is
673 * then initialized and any private data can be allocated. This also calls
Charles Keepaxef050be2018-04-24 16:39:02 +0100674 * startup for the cpu DAI, component, machine and codec DAI.
Liam Girdwoodddee6272011-06-09 14:45:53 +0100675 */
676static int soc_pcm_open(struct snd_pcm_substream *substream)
677{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900678 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100679 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000680 struct snd_soc_component *component;
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900681 struct snd_soc_dai *dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200682 const char *codec_dai_name = "multicodec";
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800683 const char *cpu_dai_name = "multicpu";
Charles Keepax244e2932018-06-19 16:22:09 +0100684 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100685
Kuninori Morimoto76c39e82020-01-10 11:36:13 +0900686 for_each_rtd_components(rtd, i, component)
687 pinctrl_pm_select_default_state(component->dev);
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000688
Kuninori Morimoto939a5cf2020-09-28 09:01:17 +0900689 ret = snd_soc_pcm_component_pm_runtime_get(rtd, substream);
690 if (ret < 0)
Kuninori Morimotocb2fce92020-10-01 10:32:48 +0900691 goto pm_err;
Mark Brownd6652ef2011-12-03 20:14:31 +0000692
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300693 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100694
Kuninori Morimoto5d9fa032020-02-10 12:14:45 +0900695 ret = soc_pcm_components_open(substream);
696 if (ret < 0)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900697 goto err;
Kuninori Morimoto5d9fa032020-02-10 12:14:45 +0900698
Kuninori Morimoto7cf3c5b2020-05-25 09:57:31 +0900699 ret = snd_soc_link_startup(substream);
Kuninori Morimotoa5e6c102020-05-25 09:57:19 +0900700 if (ret < 0)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900701 goto err;
Kuninori Morimoto5d9fa032020-02-10 12:14:45 +0900702
Liam Girdwoodddee6272011-06-09 14:45:53 +0100703 /* startup the audio subsystem */
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900704 for_each_rtd_dais(rtd, i, dai) {
705 ret = snd_soc_dai_startup(dai, substream);
Kuninori Morimotoce820142020-09-28 09:01:29 +0900706 if (ret < 0)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900707 goto err;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200708
709 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900710 dai->tx_mask = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200711 else
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900712 dai->rx_mask = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100713 }
714
Liam Girdwood01d75842012-04-25 12:12:49 +0100715 /* Dynamic PCM DAI links compat checks use dynamic capabilities */
716 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm)
717 goto dynamic;
718
Liam Girdwoodddee6272011-06-09 14:45:53 +0100719 /* Check that the codec and cpu DAIs are compatible */
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200720 soc_pcm_init_runtime_hw(substream);
721
722 if (rtd->num_codecs == 1)
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900723 codec_dai_name = asoc_rtd_to_codec(rtd, 0)->name;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100724
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800725 if (rtd->num_cpus == 1)
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900726 cpu_dai_name = asoc_rtd_to_cpu(rtd, 0)->name;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800727
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100728 if (soc_pcm_has_symmetry(substream))
729 runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
730
Liam Girdwoodddee6272011-06-09 14:45:53 +0100731 ret = -EINVAL;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100732 if (!runtime->hw.rates) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000733 printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n",
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800734 codec_dai_name, cpu_dai_name);
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900735 goto err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100736 }
737 if (!runtime->hw.formats) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000738 printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n",
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800739 codec_dai_name, cpu_dai_name);
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900740 goto err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100741 }
742 if (!runtime->hw.channels_min || !runtime->hw.channels_max ||
743 runtime->hw.channels_min > runtime->hw.channels_max) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000744 printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n",
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800745 codec_dai_name, cpu_dai_name);
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900746 goto err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100747 }
748
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200749 soc_pcm_apply_msb(substream);
Mark Brown58ba9b22012-01-16 18:38:51 +0000750
Liam Girdwoodddee6272011-06-09 14:45:53 +0100751 /* Symmetry only applies if we've already got an active stream. */
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900752 for_each_rtd_dais(rtd, i, dai) {
Kuninori Morimotob3dea622020-05-15 09:46:51 +0900753 if (snd_soc_dai_active(dai)) {
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900754 ret = soc_pcm_apply_symmetry(substream, dai);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200755 if (ret != 0)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900756 goto err;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200757 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100758 }
759
Liam Girdwood103d84a2012-11-19 14:39:15 +0000760 pr_debug("ASoC: %s <-> %s info:\n",
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800761 codec_dai_name, cpu_dai_name);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000762 pr_debug("ASoC: rate mask 0x%x\n", runtime->hw.rates);
763 pr_debug("ASoC: min ch %d max ch %d\n", runtime->hw.channels_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100764 runtime->hw.channels_max);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000765 pr_debug("ASoC: min rate %d max rate %d\n", runtime->hw.rate_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100766 runtime->hw.rate_max);
Liam Girdwood01d75842012-04-25 12:12:49 +0100767dynamic:
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100768 snd_soc_runtime_activate(rtd, substream->stream);
Kuninori Morimoto8e7875a2020-10-01 14:07:41 +0900769 ret = 0;
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900770err:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300771 mutex_unlock(&rtd->card->pcm_mutex);
Kuninori Morimotocb2fce92020-10-01 10:32:48 +0900772pm_err:
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900773 if (ret < 0)
774 soc_pcm_clean(substream, 1);
Mark Brownd6652ef2011-12-03 20:14:31 +0000775
Liam Girdwoodddee6272011-06-09 14:45:53 +0100776 return ret;
777}
778
Curtis Malainey4bf2e382019-12-03 09:30:07 -0800779static void codec2codec_close_delayed_work(struct snd_soc_pcm_runtime *rtd)
Jerome Bruneta3420312019-07-25 18:59:47 +0200780{
781 /*
782 * Currently nothing to do for c2c links
783 * Since c2c links are internal nodes in the DAPM graph and
784 * don't interface with the outside world or application layer
785 * we don't have to do any special handling on close.
786 */
787}
788
Liam Girdwoodddee6272011-06-09 14:45:53 +0100789/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100790 * Called by ALSA when the PCM substream is prepared, can set format, sample
791 * rate, etc. This function is non atomic and can be called multiple times,
792 * it can refer to the runtime info.
793 */
794static int soc_pcm_prepare(struct snd_pcm_substream *substream)
795{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900796 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900797 struct snd_soc_dai *dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200798 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100799
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300800 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100801
Kuninori Morimoto7cf3c5b2020-05-25 09:57:31 +0900802 ret = snd_soc_link_prepare(substream);
Kuninori Morimotoa5e6c102020-05-25 09:57:19 +0900803 if (ret < 0)
Kuninori Morimoto44c1a752020-01-22 09:44:44 +0900804 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100805
Kuninori Morimoto4f395142020-06-04 17:06:58 +0900806 ret = snd_soc_pcm_component_prepare(substream);
807 if (ret < 0)
808 goto out;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000809
Kuninori Morimotod108c7f2020-04-24 08:14:53 +0900810 ret = snd_soc_pcm_dai_prepare(substream);
811 if (ret < 0) {
812 dev_err(rtd->dev, "ASoC: DAI prepare error: %d\n", ret);
813 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100814 }
815
816 /* cancel any delayed stream shutdown that is pending */
817 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600818 rtd->pop_wait) {
819 rtd->pop_wait = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100820 cancel_delayed_work(&rtd->delayed_work);
821 }
822
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000823 snd_soc_dapm_stream_event(rtd, substream->stream,
824 SND_SOC_DAPM_STREAM_START);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100825
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900826 for_each_rtd_dais(rtd, i, dai)
827 snd_soc_dai_digital_mute(dai, 0, substream->stream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100828
829out:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300830 mutex_unlock(&rtd->card->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100831 return ret;
832}
833
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200834static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params,
835 unsigned int mask)
836{
837 struct snd_interval *interval;
838 int channels = hweight_long(mask);
839
840 interval = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
841 interval->min = channels;
842 interval->max = channels;
843}
844
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900845static int soc_pcm_hw_clean(struct snd_pcm_substream *substream, int rollback)
Kuninori Morimotoab494362020-09-29 13:31:19 +0900846{
847 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
848 struct snd_soc_dai *dai;
849 int i;
850
851 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
852
853 /* clear the corresponding DAIs parameters when going to be inactive */
854 for_each_rtd_dais(rtd, i, dai) {
855 int active = snd_soc_dai_stream_active(dai, substream->stream);
856
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900857 if (snd_soc_dai_active(dai) == 1)
858 soc_pcm_set_dai_params(dai, NULL);
Kuninori Morimotoab494362020-09-29 13:31:19 +0900859
860 if (active == 1)
861 snd_soc_dai_digital_mute(dai, 1, substream->stream);
862 }
863
Ranjani Sridharana27b4212020-11-17 13:50:01 -0800864 /* run the stream event */
865 snd_soc_dapm_stream_stop(rtd, substream->stream);
866
Kuninori Morimotoab494362020-09-29 13:31:19 +0900867 /* free any machine hw params */
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900868 snd_soc_link_hw_free(substream, rollback);
Kuninori Morimotoab494362020-09-29 13:31:19 +0900869
870 /* free any component resources */
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900871 snd_soc_pcm_component_hw_free(substream, rollback);
Kuninori Morimotoab494362020-09-29 13:31:19 +0900872
873 /* now free hw params for the DAIs */
874 for_each_rtd_dais(rtd, i, dai) {
875 if (!snd_soc_dai_stream_valid(dai, substream->stream))
876 continue;
877
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900878 snd_soc_dai_hw_free(dai, substream, rollback);
Kuninori Morimotoab494362020-09-29 13:31:19 +0900879 }
880
881 mutex_unlock(&rtd->card->pcm_mutex);
882 return 0;
883}
884
885/*
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900886 * Frees resources allocated by hw_params, can be called multiple times
887 */
888static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
889{
890 return soc_pcm_hw_clean(substream, 0);
891}
892
893/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100894 * Called by ALSA when the hardware params are set by application. This
895 * function can also be called multiple times and can allocate buffers
896 * (using snd_pcm_lib_* ). It's non-atomic.
897 */
898static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
899 struct snd_pcm_hw_params *params)
900{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900901 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800902 struct snd_soc_dai *cpu_dai;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000903 struct snd_soc_dai *codec_dai;
Charles Keepax244e2932018-06-19 16:22:09 +0100904 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100905
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300906 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Shengjiu Wang5cca5952019-11-12 18:46:42 +0800907
908 ret = soc_pcm_params_symmetry(substream, params);
909 if (ret)
910 goto out;
911
Kuninori Morimoto7cf3c5b2020-05-25 09:57:31 +0900912 ret = snd_soc_link_hw_params(substream, params);
Kuninori Morimotoa5e6c102020-05-25 09:57:19 +0900913 if (ret < 0)
Kuninori Morimotode9ad992020-01-22 09:44:48 +0900914 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100915
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900916 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200917 struct snd_pcm_hw_params codec_params;
918
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200919 /*
920 * Skip CODECs which don't support the current stream type,
921 * the idea being that if a CODEC is not used for the currently
922 * set up transfer direction, it should not need to be
923 * configured, especially since the configuration used might
924 * not even be supported by that CODEC. There may be cases
925 * however where a CODEC needs to be set up although it is
926 * actually not being used for the transfer, e.g. if a
927 * capture-only CODEC is acting as an LRCLK and/or BCLK master
928 * for the DAI link including a playback-only CODEC.
929 * If this becomes necessary, we will have to augment the
930 * machine driver setup with information on how to act, so
931 * we can do the right thing here.
932 */
933 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
934 continue;
935
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200936 /* copy params for each codec */
937 codec_params = *params;
938
939 /* fixup params based on TDM slot masks */
Rander Wang570f18b2019-03-08 16:38:57 +0800940 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
941 codec_dai->tx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200942 soc_pcm_codec_params_fixup(&codec_params,
943 codec_dai->tx_mask);
Rander Wang570f18b2019-03-08 16:38:57 +0800944
945 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
946 codec_dai->rx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200947 soc_pcm_codec_params_fixup(&codec_params,
948 codec_dai->rx_mask);
949
Kuninori Morimotoaa6166c2019-07-22 10:33:04 +0900950 ret = snd_soc_dai_hw_params(codec_dai, substream,
951 &codec_params);
Benoit Cousson93e69582014-07-08 23:19:38 +0200952 if(ret < 0)
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900953 goto out;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200954
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900955 soc_pcm_set_dai_params(codec_dai, &codec_params);
Charles Keepax078a85f2019-01-31 13:30:18 +0000956 snd_soc_dapm_update_dai(substream, &codec_params, codec_dai);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100957 }
958
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900959 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800960 /*
961 * Skip CPUs which don't support the current stream
962 * type. See soc_pcm_init_runtime_hw() for more details
963 */
964 if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream))
965 continue;
966
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800967 ret = snd_soc_dai_hw_params(cpu_dai, substream, params);
968 if (ret < 0)
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900969 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100970
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800971 /* store the parameters for each DAI */
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900972 soc_pcm_set_dai_params(cpu_dai, params);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800973 snd_soc_dapm_update_dai(substream, params, cpu_dai);
974 }
Kuninori Morimotoca58221d2019-05-13 16:07:43 +0900975
Kuninori Morimoto3a36a642020-09-29 13:31:41 +0900976 ret = snd_soc_pcm_component_hw_params(substream, params);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100977out:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300978 mutex_unlock(&rtd->card->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100979
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900980 if (ret < 0)
981 soc_pcm_hw_clean(substream, 1);
Kuninori Morimotob8135862017-10-11 01:37:23 +0000982
Liam Girdwoodddee6272011-06-09 14:45:53 +0100983 return ret;
984}
985
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +0300986static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
987{
Kuninori Morimoto6374f492020-12-01 08:51:33 +0900988 int ret = -EINVAL, _ret = 0;
989 int rollback = 0;
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +0300990
991 switch (cmd) {
992 case SNDRV_PCM_TRIGGER_START:
993 case SNDRV_PCM_TRIGGER_RESUME:
994 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Kuninori Morimoto6374f492020-12-01 08:51:33 +0900995 ret = snd_soc_link_trigger(substream, cmd, 0);
Kuninori Morimoto836367b2020-06-04 17:08:12 +0900996 if (ret < 0)
Kuninori Morimoto6374f492020-12-01 08:51:33 +0900997 goto start_err;
Kuninori Morimoto836367b2020-06-04 17:08:12 +0900998
Kuninori Morimoto6374f492020-12-01 08:51:33 +0900999 ret = snd_soc_pcm_component_trigger(substream, cmd, 0);
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001000 if (ret < 0)
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001001 goto start_err;
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001002
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001003 ret = snd_soc_pcm_dai_trigger(substream, cmd, 0);
1004start_err:
1005 if (ret < 0)
1006 rollback = 1;
1007 }
1008
1009 if (rollback) {
1010 _ret = ret;
1011 switch (cmd) {
1012 case SNDRV_PCM_TRIGGER_START:
1013 cmd = SNDRV_PCM_TRIGGER_STOP;
1014 break;
1015 case SNDRV_PCM_TRIGGER_RESUME:
1016 cmd = SNDRV_PCM_TRIGGER_SUSPEND;
1017 break;
1018 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1019 cmd = SNDRV_PCM_TRIGGER_PAUSE_PUSH;
1020 break;
1021 }
1022 }
1023
1024 switch (cmd) {
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001025 case SNDRV_PCM_TRIGGER_STOP:
1026 case SNDRV_PCM_TRIGGER_SUSPEND:
1027 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001028 ret = snd_soc_pcm_dai_trigger(substream, cmd, rollback);
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001029 if (ret < 0)
1030 break;
1031
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001032 ret = snd_soc_pcm_component_trigger(substream, cmd, rollback);
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001033 if (ret < 0)
1034 break;
1035
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001036 ret = snd_soc_link_trigger(substream, cmd, rollback);
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001037 break;
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001038 }
1039
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001040 if (_ret)
1041 ret = _ret;
1042
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001043 return ret;
1044}
1045
Liam Girdwoodddee6272011-06-09 14:45:53 +01001046/*
1047 * soc level wrapper for pointer callback
Charles Keepaxef050be2018-04-24 16:39:02 +01001048 * If cpu_dai, codec_dai, component driver has the delay callback, then
Liam Girdwoodddee6272011-06-09 14:45:53 +01001049 * the runtime->delay will be updated accordingly.
1050 */
1051static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
1052{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001053 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001054 struct snd_soc_dai *cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001055 struct snd_soc_dai *codec_dai;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001056 struct snd_pcm_runtime *runtime = substream->runtime;
1057 snd_pcm_uframes_t offset = 0;
1058 snd_pcm_sframes_t delay = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001059 snd_pcm_sframes_t codec_delay = 0;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001060 snd_pcm_sframes_t cpu_delay = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001061 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001062
Akshu Agrawal9fb4c2bf2018-08-01 15:37:33 +05301063 /* clearing the previous total delay */
1064 runtime->delay = 0;
1065
Kuninori Morimoto0035e252019-07-26 13:51:47 +09001066 offset = snd_soc_pcm_component_pointer(substream);
Kuninori Morimotob8135862017-10-11 01:37:23 +00001067
Akshu Agrawal9fb4c2bf2018-08-01 15:37:33 +05301068 /* base delay if assigned in pointer callback */
1069 delay = runtime->delay;
Kuninori Morimotob8135862017-10-11 01:37:23 +00001070
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001071 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001072 cpu_delay = max(cpu_delay,
1073 snd_soc_dai_delay(cpu_dai, substream));
1074 }
1075 delay += cpu_delay;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001076
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001077 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Kuninori Morimoto1dea80d2019-07-22 10:34:09 +09001078 codec_delay = max(codec_delay,
1079 snd_soc_dai_delay(codec_dai, substream));
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001080 }
1081 delay += codec_delay;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001082
Liam Girdwoodddee6272011-06-09 14:45:53 +01001083 runtime->delay = delay;
1084
1085 return offset;
1086}
1087
Liam Girdwood01d75842012-04-25 12:12:49 +01001088/* connect a FE and BE */
1089static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
1090 struct snd_soc_pcm_runtime *be, int stream)
1091{
1092 struct snd_soc_dpcm *dpcm;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001093 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001094
1095 /* only add new dpcms */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001096 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001097 if (dpcm->be == be && dpcm->fe == fe)
1098 return 0;
1099 }
1100
1101 dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_KERNEL);
1102 if (!dpcm)
1103 return -ENOMEM;
1104
1105 dpcm->be = be;
1106 dpcm->fe = fe;
1107 be->dpcm[stream].runtime = fe->dpcm[stream].runtime;
1108 dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001109 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001110 list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients);
1111 list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001112 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001113
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001114 dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001115 stream ? "capture" : "playback", fe->dai_link->name,
1116 stream ? "<-" : "->", be->dai_link->name);
1117
Kuninori Morimoto154dae82020-02-19 15:57:06 +09001118 dpcm_create_debugfs_state(dpcm, stream);
1119
Liam Girdwood01d75842012-04-25 12:12:49 +01001120 return 1;
1121}
1122
1123/* reparent a BE onto another FE */
1124static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
1125 struct snd_soc_pcm_runtime *be, int stream)
1126{
1127 struct snd_soc_dpcm *dpcm;
1128 struct snd_pcm_substream *fe_substream, *be_substream;
1129
1130 /* reparent if BE is connected to other FEs */
1131 if (!be->dpcm[stream].users)
1132 return;
1133
1134 be_substream = snd_soc_dpcm_get_substream(be, stream);
1135
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00001136 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001137 if (dpcm->fe == fe)
1138 continue;
1139
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001140 dev_dbg(fe->dev, "reparent %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001141 stream ? "capture" : "playback",
1142 dpcm->fe->dai_link->name,
1143 stream ? "<-" : "->", dpcm->be->dai_link->name);
1144
1145 fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, stream);
1146 be_substream->runtime = fe_substream->runtime;
1147 break;
1148 }
1149}
1150
1151/* disconnect a BE and FE */
Liam Girdwood23607022014-01-17 17:03:55 +00001152void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001153{
1154 struct snd_soc_dpcm *dpcm, *d;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001155 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001156
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001157 for_each_dpcm_be_safe(fe, stream, dpcm, d) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001158 dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001159 stream ? "capture" : "playback",
1160 dpcm->be->dai_link->name);
1161
1162 if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE)
1163 continue;
1164
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001165 dev_dbg(fe->dev, "freed DSP %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001166 stream ? "capture" : "playback", fe->dai_link->name,
1167 stream ? "<-" : "->", dpcm->be->dai_link->name);
1168
1169 /* BEs still alive need new FE */
1170 dpcm_be_reparent(fe, dpcm->be, stream);
1171
Kuninori Morimoto154dae82020-02-19 15:57:06 +09001172 dpcm_remove_debugfs_state(dpcm);
1173
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001174 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001175 list_del(&dpcm->list_be);
1176 list_del(&dpcm->list_fe);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001177 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001178 kfree(dpcm);
1179 }
1180}
1181
1182/* get BE for DAI widget and stream */
1183static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
1184 struct snd_soc_dapm_widget *widget, int stream)
1185{
1186 struct snd_soc_pcm_runtime *be;
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001187 struct snd_soc_dapm_widget *w;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001188 struct snd_soc_dai *dai;
Mengdong Lin1a497982015-11-18 02:34:11 -05001189 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01001190
Liam Girdwood3c146462018-03-14 20:43:51 +00001191 dev_dbg(card->dev, "ASoC: find BE for widget %s\n", widget->name);
1192
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001193 for_each_card_rtds(card, be) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001194
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001195 if (!be->dai_link->no_pcm)
1196 continue;
Liam Girdwood35ea0652012-06-05 19:26:59 +01001197
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001198 for_each_rtd_dais(be, i, dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001199 w = snd_soc_dai_get_widget(dai, stream);
Liam Girdwood3c146462018-03-14 20:43:51 +00001200
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001201 dev_dbg(card->dev, "ASoC: try BE : %s\n",
1202 w ? w->name : "(not set)");
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001203
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001204 if (w == widget)
1205 return be;
1206 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001207 }
1208
Jerome Brunet9d6ee362020-02-19 12:50:48 +01001209 /* Widget provided is not a BE */
Liam Girdwood01d75842012-04-25 12:12:49 +01001210 return NULL;
1211}
1212
Liam Girdwood01d75842012-04-25 12:12:49 +01001213static int widget_in_list(struct snd_soc_dapm_widget_list *list,
1214 struct snd_soc_dapm_widget *widget)
1215{
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001216 struct snd_soc_dapm_widget *w;
Liam Girdwood01d75842012-04-25 12:12:49 +01001217 int i;
1218
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001219 for_each_dapm_widgets(list, i, w)
1220 if (widget == w)
Liam Girdwood01d75842012-04-25 12:12:49 +01001221 return 1;
Liam Girdwood01d75842012-04-25 12:12:49 +01001222
1223 return 0;
1224}
1225
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001226static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget,
1227 enum snd_soc_dapm_direction dir)
1228{
1229 struct snd_soc_card *card = widget->dapm->card;
1230 struct snd_soc_pcm_runtime *rtd;
Kuninori Morimotoc2cd8212020-02-17 17:27:48 +09001231 int stream;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001232
Kuninori Morimotoc2cd8212020-02-17 17:27:48 +09001233 /* adjust dir to stream */
1234 if (dir == SND_SOC_DAPM_DIR_OUT)
1235 stream = SNDRV_PCM_STREAM_PLAYBACK;
1236 else
1237 stream = SNDRV_PCM_STREAM_CAPTURE;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001238
Kuninori Morimoto027a4832020-02-17 17:27:53 +09001239 rtd = dpcm_get_be(card, widget, stream);
1240 if (rtd)
1241 return true;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001242
1243 return false;
1244}
1245
Liam Girdwood23607022014-01-17 17:03:55 +00001246int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001247 int stream, struct snd_soc_dapm_widget_list **list)
Liam Girdwood01d75842012-04-25 12:12:49 +01001248{
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09001249 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
Liam Girdwood01d75842012-04-25 12:12:49 +01001250 int paths;
1251
Bard Liao6e1276a2020-02-25 21:39:16 +08001252 if (fe->num_cpus > 1) {
1253 dev_err(fe->dev,
1254 "%s doesn't support Multi CPU yet\n", __func__);
1255 return -EINVAL;
1256 }
1257
Liam Girdwood01d75842012-04-25 12:12:49 +01001258 /* get number of valid DAI paths and their widgets */
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001259 paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list,
Sameer Pujaraa293772020-11-02 20:40:09 +05301260 fe->card->component_chaining ?
1261 NULL : dpcm_end_walk_at_be);
Liam Girdwood01d75842012-04-25 12:12:49 +01001262
Liam Girdwood103d84a2012-11-19 14:39:15 +00001263 dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths,
Liam Girdwood01d75842012-04-25 12:12:49 +01001264 stream ? "capture" : "playback");
1265
Liam Girdwood01d75842012-04-25 12:12:49 +01001266 return paths;
1267}
1268
Kuninori Morimoto52645e332020-02-19 15:56:52 +09001269void dpcm_path_put(struct snd_soc_dapm_widget_list **list)
1270{
1271 snd_soc_dapm_dai_free_widgets(list);
1272}
1273
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001274static bool dpcm_be_is_active(struct snd_soc_dpcm *dpcm, int stream,
1275 struct snd_soc_dapm_widget_list *list)
Liam Girdwood01d75842012-04-25 12:12:49 +01001276{
Liam Girdwood01d75842012-04-25 12:12:49 +01001277 struct snd_soc_dapm_widget *widget;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001278 struct snd_soc_dai *dai;
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001279 unsigned int i;
1280
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001281 /* is there a valid DAI widget for this BE */
1282 for_each_rtd_dais(dpcm->be, i, dai) {
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001283 widget = snd_soc_dai_get_widget(dai, stream);
1284
1285 /*
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001286 * The BE is pruned only if none of the dai
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001287 * widgets are in the active list.
1288 */
1289 if (widget && widget_in_list(list, widget))
1290 return true;
1291 }
1292
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001293 return false;
1294}
1295
1296static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
1297 struct snd_soc_dapm_widget_list **list_)
1298{
1299 struct snd_soc_dpcm *dpcm;
Liam Girdwood01d75842012-04-25 12:12:49 +01001300 int prune = 0;
1301
1302 /* Destroy any old FE <--> BE connections */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001303 for_each_dpcm_be(fe, stream, dpcm) {
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001304 if (dpcm_be_is_active(dpcm, stream, *list_))
Kuninori Morimotobed646d2019-10-15 12:59:38 +09001305 continue;
Liam Girdwood01d75842012-04-25 12:12:49 +01001306
Liam Girdwood103d84a2012-11-19 14:39:15 +00001307 dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001308 stream ? "capture" : "playback",
1309 dpcm->be->dai_link->name, fe->dai_link->name);
1310 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
Kuninori Morimotoa7e204442020-12-11 14:55:22 +09001311 dpcm_set_be_update_state(dpcm->be, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001312 prune++;
1313 }
1314
Liam Girdwood103d84a2012-11-19 14:39:15 +00001315 dev_dbg(fe->dev, "ASoC: found %d old BE paths for pruning\n", prune);
Liam Girdwood01d75842012-04-25 12:12:49 +01001316 return prune;
1317}
1318
1319static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
1320 struct snd_soc_dapm_widget_list **list_)
1321{
1322 struct snd_soc_card *card = fe->card;
1323 struct snd_soc_dapm_widget_list *list = *list_;
1324 struct snd_soc_pcm_runtime *be;
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001325 struct snd_soc_dapm_widget *widget;
Liam Girdwood01d75842012-04-25 12:12:49 +01001326 int i, new = 0, err;
1327
1328 /* Create any new FE <--> BE connections */
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001329 for_each_dapm_widgets(list, i, widget) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001330
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001331 switch (widget->id) {
Mark Brown46162742013-06-05 19:36:11 +01001332 case snd_soc_dapm_dai_in:
Koro Chenc5b85402015-07-06 10:02:10 +08001333 if (stream != SNDRV_PCM_STREAM_PLAYBACK)
1334 continue;
1335 break;
Mark Brown46162742013-06-05 19:36:11 +01001336 case snd_soc_dapm_dai_out:
Koro Chenc5b85402015-07-06 10:02:10 +08001337 if (stream != SNDRV_PCM_STREAM_CAPTURE)
1338 continue;
Mark Brown46162742013-06-05 19:36:11 +01001339 break;
1340 default:
Liam Girdwood01d75842012-04-25 12:12:49 +01001341 continue;
Mark Brown46162742013-06-05 19:36:11 +01001342 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001343
1344 /* is there a valid BE rtd for this widget */
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001345 be = dpcm_get_be(card, widget, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001346 if (!be) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001347 dev_err(fe->dev, "ASoC: no BE found for %s\n",
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001348 widget->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001349 continue;
1350 }
1351
Liam Girdwood01d75842012-04-25 12:12:49 +01001352 /* don't connect if FE is not running */
Liam Girdwood23607022014-01-17 17:03:55 +00001353 if (!fe->dpcm[stream].runtime && !fe->fe_compr)
Liam Girdwood01d75842012-04-25 12:12:49 +01001354 continue;
1355
1356 /* newly connected FE and BE */
1357 err = dpcm_be_connect(fe, be, stream);
1358 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001359 dev_err(fe->dev, "ASoC: can't connect %s\n",
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001360 widget->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001361 break;
1362 } else if (err == 0) /* already connected */
1363 continue;
1364
1365 /* new */
Kuninori Morimotoa7e204442020-12-11 14:55:22 +09001366 dpcm_set_be_update_state(be, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001367 new++;
1368 }
1369
Liam Girdwood103d84a2012-11-19 14:39:15 +00001370 dev_dbg(fe->dev, "ASoC: found %d new BE paths\n", new);
Liam Girdwood01d75842012-04-25 12:12:49 +01001371 return new;
1372}
1373
1374/*
1375 * Find the corresponding BE DAIs that source or sink audio to this
1376 * FE substream.
1377 */
Liam Girdwood23607022014-01-17 17:03:55 +00001378int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
Liam Girdwood01d75842012-04-25 12:12:49 +01001379 int stream, struct snd_soc_dapm_widget_list **list, int new)
1380{
1381 if (new)
1382 return dpcm_add_paths(fe, stream, list);
1383 else
1384 return dpcm_prune_paths(fe, stream, list);
1385}
1386
Liam Girdwood23607022014-01-17 17:03:55 +00001387void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001388{
1389 struct snd_soc_dpcm *dpcm;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001390 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001391
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001392 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001393 for_each_dpcm_be(fe, stream, dpcm)
Kuninori Morimotoa7e204442020-12-11 14:55:22 +09001394 dpcm_set_be_update_state(dpcm->be, stream, SND_SOC_DPCM_UPDATE_NO);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001395 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001396}
1397
1398static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe,
1399 int stream)
1400{
1401 struct snd_soc_dpcm *dpcm;
1402
1403 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001404 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001405
1406 struct snd_soc_pcm_runtime *be = dpcm->be;
1407 struct snd_pcm_substream *be_substream =
1408 snd_soc_dpcm_get_substream(be, stream);
1409
1410 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001411 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001412 stream ? "capture" : "playback",
1413 be->dpcm[stream].state);
1414
1415 if (--be->dpcm[stream].users != 0)
1416 continue;
1417
1418 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1419 continue;
1420
1421 soc_pcm_close(be_substream);
1422 be_substream->runtime = NULL;
1423 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1424 }
1425}
1426
Liam Girdwood23607022014-01-17 17:03:55 +00001427int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001428{
1429 struct snd_soc_dpcm *dpcm;
1430 int err, count = 0;
1431
1432 /* only startup BE DAIs that are either sinks or sources to this FE DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001433 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001434
1435 struct snd_soc_pcm_runtime *be = dpcm->be;
1436 struct snd_pcm_substream *be_substream =
1437 snd_soc_dpcm_get_substream(be, stream);
1438
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001439 if (!be_substream) {
1440 dev_err(be->dev, "ASoC: no backend %s stream\n",
1441 stream ? "capture" : "playback");
1442 continue;
1443 }
1444
Liam Girdwood01d75842012-04-25 12:12:49 +01001445 /* is this op for this BE ? */
1446 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1447 continue;
1448
1449 /* first time the dpcm is open ? */
1450 if (be->dpcm[stream].users == DPCM_MAX_BE_USERS)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001451 dev_err(be->dev, "ASoC: too many users %s at open %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001452 stream ? "capture" : "playback",
1453 be->dpcm[stream].state);
1454
1455 if (be->dpcm[stream].users++ != 0)
1456 continue;
1457
1458 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
1459 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
1460 continue;
1461
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001462 dev_dbg(be->dev, "ASoC: open %s BE %s\n",
1463 stream ? "capture" : "playback", be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001464
1465 be_substream->runtime = be->dpcm[stream].runtime;
1466 err = soc_pcm_open(be_substream);
1467 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001468 dev_err(be->dev, "ASoC: BE open failed %d\n", err);
Liam Girdwood01d75842012-04-25 12:12:49 +01001469 be->dpcm[stream].users--;
1470 if (be->dpcm[stream].users < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001471 dev_err(be->dev, "ASoC: no users %s at unwind %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001472 stream ? "capture" : "playback",
1473 be->dpcm[stream].state);
1474
1475 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1476 goto unwind;
1477 }
1478
1479 be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1480 count++;
1481 }
1482
1483 return count;
1484
1485unwind:
1486 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001487 for_each_dpcm_be_rollback(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001488 struct snd_soc_pcm_runtime *be = dpcm->be;
1489 struct snd_pcm_substream *be_substream =
1490 snd_soc_dpcm_get_substream(be, stream);
1491
1492 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1493 continue;
1494
1495 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001496 dev_err(be->dev, "ASoC: no users %s at close %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001497 stream ? "capture" : "playback",
1498 be->dpcm[stream].state);
1499
1500 if (--be->dpcm[stream].users != 0)
1501 continue;
1502
1503 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1504 continue;
1505
1506 soc_pcm_close(be_substream);
1507 be_substream->runtime = NULL;
1508 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1509 }
1510
1511 return err;
1512}
1513
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001514static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
Jerome Brunet435ffb72018-07-05 12:13:48 +02001515 struct snd_soc_pcm_stream *stream)
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001516{
Kuninori Morimotodd5abc72021-01-22 10:13:53 +09001517 runtime->hw.rates = stream->rates;
1518
1519 snd_pcm_limit_hw_rates(runtime);
1520
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001521 runtime->hw.rate_min = stream->rate_min;
Charles Keepaxe33ffbd9c2018-08-27 14:26:47 +01001522 runtime->hw.rate_max = min_not_zero(stream->rate_max, UINT_MAX);
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001523 runtime->hw.channels_min = stream->channels_min;
1524 runtime->hw.channels_max = stream->channels_max;
Lars-Peter Clausen002220a2014-01-06 14:19:07 +01001525 if (runtime->hw.formats)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001526 runtime->hw.formats &= stream->formats;
Lars-Peter Clausen002220a2014-01-06 14:19:07 +01001527 else
Jerome Brunet435ffb72018-07-05 12:13:48 +02001528 runtime->hw.formats = stream->formats;
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001529}
1530
Jerome Brunet435ffb72018-07-05 12:13:48 +02001531static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream,
Kuninori Morimoto4b260f42021-01-22 10:13:48 +09001532 struct snd_pcm_runtime *runtime)
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001533{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001534 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Kuninori Morimoto4b260f42021-01-22 10:13:48 +09001535 struct snd_pcm_hardware *hw = &runtime->hw;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001536 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001537 struct snd_soc_dai *dai;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001538 int stream = substream->stream;
1539
1540 if (!fe->dai_link->dpcm_merged_format)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001541 return;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001542
1543 /*
1544 * It returns merged BE codec format
1545 * if FE want to use it (= dpcm_merged_format)
1546 */
1547
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001548 for_each_dpcm_be(fe, stream, dpcm) {
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001549 struct snd_soc_pcm_runtime *be = dpcm->be;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001550 struct snd_soc_pcm_stream *codec_stream;
1551 int i;
1552
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001553 for_each_rtd_codec_dais(be, i, dai) {
Jerome Brunet4febced2018-06-27 17:36:38 +02001554 /*
1555 * Skip CODECs which don't support the current stream
1556 * type. See soc_pcm_init_runtime_hw() for more details
1557 */
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001558 if (!snd_soc_dai_stream_valid(dai, stream))
Jerome Brunet4febced2018-06-27 17:36:38 +02001559 continue;
1560
Kuninori Morimotoacf253c2020-02-19 15:56:30 +09001561 codec_stream = snd_soc_dai_get_pcm_stream(dai, stream);
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001562
Kuninori Morimoto4b260f42021-01-22 10:13:48 +09001563 hw->formats &= codec_stream->formats;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001564 }
1565 }
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001566}
1567
Jerome Brunet435ffb72018-07-05 12:13:48 +02001568static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream,
Kuninori Morimoto4b260f42021-01-22 10:13:48 +09001569 struct snd_pcm_runtime *runtime)
Jiada Wangf4c277b2018-06-20 18:25:20 +09001570{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001571 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Kuninori Morimoto4b260f42021-01-22 10:13:48 +09001572 struct snd_pcm_hardware *hw = &runtime->hw;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001573 struct snd_soc_dpcm *dpcm;
1574 int stream = substream->stream;
1575
1576 if (!fe->dai_link->dpcm_merged_chan)
1577 return;
1578
Jiada Wangf4c277b2018-06-20 18:25:20 +09001579 /*
1580 * It returns merged BE codec channel;
1581 * if FE want to use it (= dpcm_merged_chan)
1582 */
1583
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001584 for_each_dpcm_be(fe, stream, dpcm) {
Jiada Wangf4c277b2018-06-20 18:25:20 +09001585 struct snd_soc_pcm_runtime *be = dpcm->be;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001586 struct snd_soc_pcm_stream *codec_stream;
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001587 struct snd_soc_pcm_stream *cpu_stream;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001588 struct snd_soc_dai *dai;
1589 int i;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001590
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001591 for_each_rtd_cpu_dais(be, i, dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001592 /*
1593 * Skip CPUs which don't support the current stream
1594 * type. See soc_pcm_init_runtime_hw() for more details
1595 */
1596 if (!snd_soc_dai_stream_valid(dai, stream))
1597 continue;
1598
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001599 cpu_stream = snd_soc_dai_get_pcm_stream(dai, stream);
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001600
Kuninori Morimoto4b260f42021-01-22 10:13:48 +09001601 hw->channels_min = max(hw->channels_min,
1602 cpu_stream->channels_min);
1603 hw->channels_max = min(hw->channels_max,
1604 cpu_stream->channels_max);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001605 }
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001606
1607 /*
1608 * chan min/max cannot be enforced if there are multiple CODEC
1609 * DAIs connected to a single CPU DAI, use CPU DAI's directly
1610 */
1611 if (be->num_codecs == 1) {
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09001612 codec_stream = snd_soc_dai_get_pcm_stream(asoc_rtd_to_codec(be, 0), stream);
Jiada Wangf4c277b2018-06-20 18:25:20 +09001613
Kuninori Morimoto4b260f42021-01-22 10:13:48 +09001614 hw->channels_min = max(hw->channels_min,
1615 codec_stream->channels_min);
1616 hw->channels_max = min(hw->channels_max,
1617 codec_stream->channels_max);
Jiada Wangf4c277b2018-06-20 18:25:20 +09001618 }
1619 }
1620}
1621
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001622static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream,
Kuninori Morimoto4b260f42021-01-22 10:13:48 +09001623 struct snd_pcm_runtime *runtime)
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001624{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001625 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Kuninori Morimoto4b260f42021-01-22 10:13:48 +09001626 struct snd_pcm_hardware *hw = &runtime->hw;
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001627 struct snd_soc_dpcm *dpcm;
1628 int stream = substream->stream;
1629
1630 if (!fe->dai_link->dpcm_merged_rate)
1631 return;
1632
1633 /*
1634 * It returns merged BE codec channel;
1635 * if FE want to use it (= dpcm_merged_chan)
1636 */
1637
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001638 for_each_dpcm_be(fe, stream, dpcm) {
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001639 struct snd_soc_pcm_runtime *be = dpcm->be;
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001640 struct snd_soc_pcm_stream *pcm;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001641 struct snd_soc_dai *dai;
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001642 int i;
1643
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001644 for_each_rtd_dais(be, i, dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001645 /*
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001646 * Skip DAIs which don't support the current stream
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001647 * type. See soc_pcm_init_runtime_hw() for more details
1648 */
1649 if (!snd_soc_dai_stream_valid(dai, stream))
1650 continue;
1651
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001652 pcm = snd_soc_dai_get_pcm_stream(dai, stream);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001653
Kuninori Morimotodd5abc72021-01-22 10:13:53 +09001654 hw->rates = snd_pcm_rate_mask_intersect(hw->rates, pcm->rates);
1655
1656 snd_pcm_limit_hw_rates(runtime);
1657
Kuninori Morimoto4b260f42021-01-22 10:13:48 +09001658 hw->rate_min = max(hw->rate_min, pcm->rate_min);
1659 hw->rate_max = min_not_zero(hw->rate_max, pcm->rate_max);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001660 }
1661 }
1662}
1663
Mark Brown45c0a182012-05-09 21:46:27 +01001664static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001665{
1666 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001667 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001668 struct snd_soc_dai *cpu_dai;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001669 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01001670
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001671 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001672 /*
1673 * Skip CPUs which don't support the current stream
1674 * type. See soc_pcm_init_runtime_hw() for more details
1675 */
1676 if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream))
1677 continue;
1678
Kuninori Morimoto0c9ba722020-03-06 10:09:54 +09001679 dpcm_init_runtime_hw(runtime,
1680 snd_soc_dai_get_pcm_stream(cpu_dai,
1681 substream->stream));
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001682 }
Jiada Wangf4c277b2018-06-20 18:25:20 +09001683
Kuninori Morimoto4b260f42021-01-22 10:13:48 +09001684 dpcm_runtime_merge_format(substream, runtime);
1685 dpcm_runtime_merge_chan(substream, runtime);
1686 dpcm_runtime_merge_rate(substream, runtime);
Liam Girdwood01d75842012-04-25 12:12:49 +01001687}
1688
PC Liao906c7d62015-12-11 11:33:51 +08001689static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
1690 int stream)
1691{
1692 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001693 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001694 struct snd_soc_dai *fe_cpu_dai;
PC Liao906c7d62015-12-11 11:33:51 +08001695 int err;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001696 int i;
PC Liao906c7d62015-12-11 11:33:51 +08001697
1698 /* apply symmetry for FE */
1699 if (soc_pcm_has_symmetry(fe_substream))
1700 fe_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1701
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001702 for_each_rtd_cpu_dais (fe, i, fe_cpu_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001703 /* Symmetry only applies if we've got an active stream. */
Kuninori Morimotob3dea622020-05-15 09:46:51 +09001704 if (snd_soc_dai_active(fe_cpu_dai)) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001705 err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai);
1706 if (err < 0)
1707 return err;
1708 }
PC Liao906c7d62015-12-11 11:33:51 +08001709 }
1710
1711 /* apply symmetry for BE */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001712 for_each_dpcm_be(fe, stream, dpcm) {
PC Liao906c7d62015-12-11 11:33:51 +08001713 struct snd_soc_pcm_runtime *be = dpcm->be;
1714 struct snd_pcm_substream *be_substream =
1715 snd_soc_dpcm_get_substream(be, stream);
Jerome Brunet6246f282019-04-01 15:03:54 +02001716 struct snd_soc_pcm_runtime *rtd;
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001717 struct snd_soc_dai *dai;
PC Liao906c7d62015-12-11 11:33:51 +08001718 int i;
1719
Jerome Brunet6246f282019-04-01 15:03:54 +02001720 /* A backend may not have the requested substream */
1721 if (!be_substream)
1722 continue;
1723
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001724 rtd = asoc_substream_to_rtd(be_substream);
Jeeja KPf1176612016-09-06 14:17:55 +05301725 if (rtd->dai_link->be_hw_params_fixup)
1726 continue;
1727
PC Liao906c7d62015-12-11 11:33:51 +08001728 if (soc_pcm_has_symmetry(be_substream))
1729 be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1730
1731 /* Symmetry only applies if we've got an active stream. */
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001732 for_each_rtd_dais(rtd, i, dai) {
Kuninori Morimotob3dea622020-05-15 09:46:51 +09001733 if (snd_soc_dai_active(dai)) {
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001734 err = soc_pcm_apply_symmetry(fe_substream, dai);
PC Liao906c7d62015-12-11 11:33:51 +08001735 if (err < 0)
1736 return err;
1737 }
1738 }
1739 }
1740
1741 return 0;
1742}
1743
Liam Girdwood01d75842012-04-25 12:12:49 +01001744static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
1745{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001746 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001747 int stream = fe_substream->stream, ret = 0;
1748
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001749 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001750
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09001751 ret = dpcm_be_dai_startup(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001752 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001753 dev_err(fe->dev,"ASoC: failed to start some BEs %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001754 goto be_err;
1755 }
1756
Liam Girdwood103d84a2012-11-19 14:39:15 +00001757 dev_dbg(fe->dev, "ASoC: open FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001758
1759 /* start the DAI frontend */
1760 ret = soc_pcm_open(fe_substream);
1761 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001762 dev_err(fe->dev,"ASoC: failed to start FE %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001763 goto unwind;
1764 }
1765
1766 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1767
1768 dpcm_set_fe_runtime(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001769
PC Liao906c7d62015-12-11 11:33:51 +08001770 ret = dpcm_apply_symmetry(fe_substream, stream);
Kuninori Morimoto8a01fbf2020-03-06 10:09:59 +09001771 if (ret < 0)
PC Liao906c7d62015-12-11 11:33:51 +08001772 dev_err(fe->dev, "ASoC: failed to apply dpcm symmetry %d\n",
1773 ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001774
1775unwind:
Kuninori Morimoto8a01fbf2020-03-06 10:09:59 +09001776 if (ret < 0)
1777 dpcm_be_dai_startup_unwind(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001778be_err:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001779 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001780 return ret;
1781}
1782
Liam Girdwood23607022014-01-17 17:03:55 +00001783int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001784{
1785 struct snd_soc_dpcm *dpcm;
1786
1787 /* only shutdown BEs that are either sinks or sources to this FE DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001788 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001789
1790 struct snd_soc_pcm_runtime *be = dpcm->be;
1791 struct snd_pcm_substream *be_substream =
1792 snd_soc_dpcm_get_substream(be, stream);
1793
1794 /* is this op for this BE ? */
1795 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1796 continue;
1797
1798 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001799 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001800 stream ? "capture" : "playback",
1801 be->dpcm[stream].state);
1802
1803 if (--be->dpcm[stream].users != 0)
1804 continue;
1805
1806 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Kai Chieh Chuang9c0ac702018-05-28 10:18:18 +08001807 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) {
1808 soc_pcm_hw_free(be_substream);
1809 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1810 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001811
Liam Girdwood103d84a2012-11-19 14:39:15 +00001812 dev_dbg(be->dev, "ASoC: close BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001813 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001814
1815 soc_pcm_close(be_substream);
1816 be_substream->runtime = NULL;
1817
1818 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1819 }
1820 return 0;
1821}
1822
1823static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
1824{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001825 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001826 int stream = substream->stream;
1827
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001828 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001829
1830 /* shutdown the BEs */
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09001831 dpcm_be_dai_shutdown(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001832
Liam Girdwood103d84a2012-11-19 14:39:15 +00001833 dev_dbg(fe->dev, "ASoC: close FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001834
1835 /* now shutdown the frontend */
1836 soc_pcm_close(substream);
1837
Ranjani Sridharanbb9dd3c2020-12-02 11:33:43 -08001838 /* run the stream stop event */
1839 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
1840
Liam Girdwood01d75842012-04-25 12:12:49 +01001841 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001842 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001843 return 0;
1844}
1845
Liam Girdwood23607022014-01-17 17:03:55 +00001846int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001847{
1848 struct snd_soc_dpcm *dpcm;
1849
1850 /* only hw_params backends that are either sinks or sources
1851 * to this frontend DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001852 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001853
1854 struct snd_soc_pcm_runtime *be = dpcm->be;
1855 struct snd_pcm_substream *be_substream =
1856 snd_soc_dpcm_get_substream(be, stream);
1857
1858 /* is this op for this BE ? */
1859 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1860 continue;
1861
1862 /* only free hw when no longer used - check all FEs */
1863 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1864 continue;
1865
Qiao Zhou36fba622014-12-03 10:13:43 +08001866 /* do not free hw if this BE is used by other FE */
1867 if (be->dpcm[stream].users > 1)
1868 continue;
1869
Liam Girdwood01d75842012-04-25 12:12:49 +01001870 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1871 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
1872 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Patrick Lai08b27842012-12-19 19:36:02 -08001873 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
Vinod Koul5e82d2b2016-02-01 22:26:40 +05301874 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
1875 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
Liam Girdwood01d75842012-04-25 12:12:49 +01001876 continue;
1877
Liam Girdwood103d84a2012-11-19 14:39:15 +00001878 dev_dbg(be->dev, "ASoC: hw_free BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001879 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001880
1881 soc_pcm_hw_free(be_substream);
1882
1883 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1884 }
1885
1886 return 0;
1887}
1888
Mark Brown45c0a182012-05-09 21:46:27 +01001889static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001890{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001891 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001892 int err, stream = substream->stream;
1893
1894 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001895 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001896
Liam Girdwood103d84a2012-11-19 14:39:15 +00001897 dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001898
1899 /* call hw_free on the frontend */
1900 err = soc_pcm_hw_free(substream);
1901 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001902 dev_err(fe->dev,"ASoC: hw_free FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001903 fe->dai_link->name);
1904
1905 /* only hw_params backends that are either sinks or sources
1906 * to this frontend DAI */
1907 err = dpcm_be_dai_hw_free(fe, stream);
1908
1909 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001910 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001911
1912 mutex_unlock(&fe->card->mutex);
1913 return 0;
1914}
1915
Liam Girdwood23607022014-01-17 17:03:55 +00001916int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001917{
1918 struct snd_soc_dpcm *dpcm;
1919 int ret;
1920
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001921 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001922
1923 struct snd_soc_pcm_runtime *be = dpcm->be;
1924 struct snd_pcm_substream *be_substream =
1925 snd_soc_dpcm_get_substream(be, stream);
1926
1927 /* is this op for this BE ? */
1928 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1929 continue;
1930
Liam Girdwood01d75842012-04-25 12:12:49 +01001931 /* copy params for each dpcm */
1932 memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params,
1933 sizeof(struct snd_pcm_hw_params));
1934
1935 /* perform any hw_params fixups */
Kuninori Morimoto0cbbf8a2020-05-25 09:57:36 +09001936 ret = snd_soc_link_be_hw_params_fixup(be, &dpcm->hw_params);
1937 if (ret < 0)
1938 goto unwind;
Liam Girdwood01d75842012-04-25 12:12:49 +01001939
Libin Yangae061d22019-04-19 09:53:12 +08001940 /* copy the fixed-up hw params for BE dai */
1941 memcpy(&be->dpcm[stream].hw_params, &dpcm->hw_params,
1942 sizeof(struct snd_pcm_hw_params));
1943
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00001944 /* only allow hw_params() if no connected FEs are running */
1945 if (!snd_soc_dpcm_can_be_params(fe, be, stream))
1946 continue;
1947
1948 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
1949 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1950 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE))
1951 continue;
1952
1953 dev_dbg(be->dev, "ASoC: hw_params BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001954 be->dai_link->name);
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00001955
Liam Girdwood01d75842012-04-25 12:12:49 +01001956 ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params);
1957 if (ret < 0) {
1958 dev_err(dpcm->be->dev,
Liam Girdwood103d84a2012-11-19 14:39:15 +00001959 "ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001960 goto unwind;
1961 }
1962
1963 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
1964 }
1965 return 0;
1966
1967unwind:
1968 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001969 for_each_dpcm_be_rollback(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001970 struct snd_soc_pcm_runtime *be = dpcm->be;
1971 struct snd_pcm_substream *be_substream =
1972 snd_soc_dpcm_get_substream(be, stream);
1973
1974 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1975 continue;
1976
1977 /* only allow hw_free() if no connected FEs are running */
1978 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1979 continue;
1980
1981 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
1982 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1983 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
1984 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
1985 continue;
1986
1987 soc_pcm_hw_free(be_substream);
1988 }
1989
1990 return ret;
1991}
1992
Mark Brown45c0a182012-05-09 21:46:27 +01001993static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
1994 struct snd_pcm_hw_params *params)
Liam Girdwood01d75842012-04-25 12:12:49 +01001995{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001996 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001997 int ret, stream = substream->stream;
1998
1999 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002000 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002001
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09002002 memcpy(&fe->dpcm[stream].hw_params, params,
Liam Girdwood01d75842012-04-25 12:12:49 +01002003 sizeof(struct snd_pcm_hw_params));
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09002004 ret = dpcm_be_dai_hw_params(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002005 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002006 dev_err(fe->dev,"ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002007 goto out;
2008 }
2009
Liam Girdwood103d84a2012-11-19 14:39:15 +00002010 dev_dbg(fe->dev, "ASoC: hw_params FE %s rate %d chan %x fmt %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002011 fe->dai_link->name, params_rate(params),
2012 params_channels(params), params_format(params));
2013
2014 /* call hw_params on the frontend */
2015 ret = soc_pcm_hw_params(substream, params);
2016 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002017 dev_err(fe->dev,"ASoC: hw_params FE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002018 dpcm_be_dai_hw_free(fe, stream);
2019 } else
2020 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2021
2022out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002023 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002024 mutex_unlock(&fe->card->mutex);
2025 return ret;
2026}
2027
Liam Girdwood23607022014-01-17 17:03:55 +00002028int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
Mark Brown45c0a182012-05-09 21:46:27 +01002029 int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002030{
2031 struct snd_soc_dpcm *dpcm;
2032 int ret = 0;
2033
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002034 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002035
2036 struct snd_soc_pcm_runtime *be = dpcm->be;
2037 struct snd_pcm_substream *be_substream =
2038 snd_soc_dpcm_get_substream(be, stream);
2039
2040 /* is this op for this BE ? */
2041 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2042 continue;
2043
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002044 dev_dbg(be->dev, "ASoC: trigger BE %s cmd %d\n",
2045 be->dai_link->name, cmd);
2046
Liam Girdwood01d75842012-04-25 12:12:49 +01002047 switch (cmd) {
2048 case SNDRV_PCM_TRIGGER_START:
2049 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
이경택21fca8b2020-04-01 10:04:21 +09002050 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
2051 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Liam Girdwood01d75842012-04-25 12:12:49 +01002052 continue;
2053
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002054 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002055 if (ret)
2056 return ret;
2057
2058 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2059 break;
2060 case SNDRV_PCM_TRIGGER_RESUME:
2061 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
2062 continue;
2063
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002064 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002065 if (ret)
2066 return ret;
2067
2068 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2069 break;
2070 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2071 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
2072 continue;
2073
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002074 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002075 if (ret)
2076 return ret;
2077
2078 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2079 break;
2080 case SNDRV_PCM_TRIGGER_STOP:
이경택21fca8b2020-04-01 10:04:21 +09002081 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) &&
2082 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Liam Girdwood01d75842012-04-25 12:12:49 +01002083 continue;
2084
2085 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2086 continue;
2087
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002088 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002089 if (ret)
2090 return ret;
2091
2092 be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2093 break;
2094 case SNDRV_PCM_TRIGGER_SUSPEND:
Nicolin Chen868a6ca2014-05-12 20:12:05 +08002095 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
Liam Girdwood01d75842012-04-25 12:12:49 +01002096 continue;
2097
2098 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2099 continue;
2100
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002101 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002102 if (ret)
2103 return ret;
2104
2105 be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND;
2106 break;
2107 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2108 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2109 continue;
2110
2111 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2112 continue;
2113
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002114 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002115 if (ret)
2116 return ret;
2117
2118 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2119 break;
2120 }
2121 }
2122
2123 return ret;
2124}
2125EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
2126
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002127static int dpcm_dai_trigger_fe_be(struct snd_pcm_substream *substream,
2128 int cmd, bool fe_first)
2129{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002130 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002131 int ret;
2132
2133 /* call trigger on the frontend before the backend. */
2134 if (fe_first) {
2135 dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n",
2136 fe->dai_link->name, cmd);
2137
2138 ret = soc_pcm_trigger(substream, cmd);
2139 if (ret < 0)
2140 return ret;
2141
2142 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2143 return ret;
2144 }
2145
2146 /* call trigger on the frontend after the backend. */
2147 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2148 if (ret < 0)
2149 return ret;
2150
2151 dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n",
2152 fe->dai_link->name, cmd);
2153
2154 ret = soc_pcm_trigger(substream, cmd);
2155
2156 return ret;
2157}
2158
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002159static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002160{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002161 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002162 int stream = substream->stream;
2163 int ret = 0;
Liam Girdwood01d75842012-04-25 12:12:49 +01002164 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
2165
2166 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
2167
2168 switch (trigger) {
2169 case SND_SOC_DPCM_TRIGGER_PRE:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002170 switch (cmd) {
2171 case SNDRV_PCM_TRIGGER_START:
2172 case SNDRV_PCM_TRIGGER_RESUME:
2173 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Cezary Rojewski4c22b802020-10-26 11:01:29 +01002174 case SNDRV_PCM_TRIGGER_DRAIN:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002175 ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
2176 break;
2177 case SNDRV_PCM_TRIGGER_STOP:
2178 case SNDRV_PCM_TRIGGER_SUSPEND:
2179 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2180 ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
2181 break;
2182 default:
2183 ret = -EINVAL;
2184 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002185 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002186 break;
2187 case SND_SOC_DPCM_TRIGGER_POST:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002188 switch (cmd) {
2189 case SNDRV_PCM_TRIGGER_START:
2190 case SNDRV_PCM_TRIGGER_RESUME:
2191 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Cezary Rojewski4c22b802020-10-26 11:01:29 +01002192 case SNDRV_PCM_TRIGGER_DRAIN:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002193 ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
2194 break;
2195 case SNDRV_PCM_TRIGGER_STOP:
2196 case SNDRV_PCM_TRIGGER_SUSPEND:
2197 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2198 ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
2199 break;
2200 default:
2201 ret = -EINVAL;
2202 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002203 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002204 break;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002205 case SND_SOC_DPCM_TRIGGER_BESPOKE:
2206 /* bespoke trigger() - handles both FE and BEs */
2207
Liam Girdwood103d84a2012-11-19 14:39:15 +00002208 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd %d\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002209 fe->dai_link->name, cmd);
2210
Kuninori Morimoto308193582020-04-24 08:15:09 +09002211 ret = snd_soc_pcm_dai_bespoke_trigger(substream, cmd);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002212 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002213 default:
Liam Girdwood103d84a2012-11-19 14:39:15 +00002214 dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd,
Liam Girdwood01d75842012-04-25 12:12:49 +01002215 fe->dai_link->name);
2216 ret = -EINVAL;
2217 goto out;
2218 }
2219
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002220 if (ret < 0) {
2221 dev_err(fe->dev, "ASoC: trigger FE cmd: %d failed: %d\n",
2222 cmd, ret);
2223 goto out;
2224 }
2225
Liam Girdwood01d75842012-04-25 12:12:49 +01002226 switch (cmd) {
2227 case SNDRV_PCM_TRIGGER_START:
2228 case SNDRV_PCM_TRIGGER_RESUME:
2229 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2230 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2231 break;
2232 case SNDRV_PCM_TRIGGER_STOP:
2233 case SNDRV_PCM_TRIGGER_SUSPEND:
Liam Girdwood01d75842012-04-25 12:12:49 +01002234 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2235 break;
Patrick Lai9f169b92016-12-31 22:44:39 -08002236 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2237 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2238 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002239 }
2240
2241out:
2242 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
2243 return ret;
2244}
2245
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002246static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
2247{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002248 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002249 int stream = substream->stream;
2250
2251 /* if FE's runtime_update is already set, we're in race;
2252 * process this trigger later at exit
2253 */
2254 if (fe->dpcm[stream].runtime_update != SND_SOC_DPCM_UPDATE_NO) {
2255 fe->dpcm[stream].trigger_pending = cmd + 1;
2256 return 0; /* delayed, assuming it's successful */
2257 }
2258
2259 /* we're alone, let's trigger */
2260 return dpcm_fe_dai_do_trigger(substream, cmd);
2261}
2262
Liam Girdwood23607022014-01-17 17:03:55 +00002263int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002264{
2265 struct snd_soc_dpcm *dpcm;
2266 int ret = 0;
2267
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002268 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002269
2270 struct snd_soc_pcm_runtime *be = dpcm->be;
2271 struct snd_pcm_substream *be_substream =
2272 snd_soc_dpcm_get_substream(be, stream);
2273
2274 /* is this op for this BE ? */
2275 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2276 continue;
2277
2278 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
Koro Chen95f444d2015-10-28 10:15:34 +08002279 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
Libin Yang5087a8f2019-05-08 10:32:41 +08002280 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND) &&
2281 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Liam Girdwood01d75842012-04-25 12:12:49 +01002282 continue;
2283
Liam Girdwood103d84a2012-11-19 14:39:15 +00002284 dev_dbg(be->dev, "ASoC: prepare BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002285 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002286
2287 ret = soc_pcm_prepare(be_substream);
2288 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002289 dev_err(be->dev, "ASoC: backend prepare failed %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002290 ret);
2291 break;
2292 }
2293
2294 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2295 }
2296 return ret;
2297}
2298
Mark Brown45c0a182012-05-09 21:46:27 +01002299static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002300{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002301 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002302 int stream = substream->stream, ret = 0;
2303
2304 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2305
Liam Girdwood103d84a2012-11-19 14:39:15 +00002306 dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002307
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002308 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002309
2310 /* there is no point preparing this FE if there are no BEs */
2311 if (list_empty(&fe->dpcm[stream].be_clients)) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002312 dev_err(fe->dev, "ASoC: no backend DAIs enabled for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002313 fe->dai_link->name);
2314 ret = -EINVAL;
2315 goto out;
2316 }
2317
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09002318 ret = dpcm_be_dai_prepare(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002319 if (ret < 0)
2320 goto out;
2321
2322 /* call prepare on the frontend */
2323 ret = soc_pcm_prepare(substream);
2324 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002325 dev_err(fe->dev,"ASoC: prepare FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002326 fe->dai_link->name);
2327 goto out;
2328 }
2329
Liam Girdwood01d75842012-04-25 12:12:49 +01002330 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2331
2332out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002333 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002334 mutex_unlock(&fe->card->mutex);
2335
2336 return ret;
2337}
2338
Liam Girdwood618dae12012-04-25 12:12:51 +01002339static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
2340{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002341 struct snd_pcm_substream *substream =
2342 snd_soc_dpcm_get_substream(fe, stream);
2343 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01002344 int err;
Liam Girdwood01d75842012-04-25 12:12:49 +01002345
Liam Girdwood103d84a2012-11-19 14:39:15 +00002346 dev_dbg(fe->dev, "ASoC: runtime %s close on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002347 stream ? "capture" : "playback", fe->dai_link->name);
2348
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002349 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2350 /* call bespoke trigger - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002351 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002352 fe->dai_link->name);
2353
Kuninori Morimoto308193582020-04-24 08:15:09 +09002354 err = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002355 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002356 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002357 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002358 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002359 fe->dai_link->name);
2360
2361 err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
2362 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002363 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002364 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002365
2366 err = dpcm_be_dai_hw_free(fe, stream);
2367 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002368 dev_err(fe->dev,"ASoC: hw_free FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002369
2370 err = dpcm_be_dai_shutdown(fe, stream);
2371 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002372 dev_err(fe->dev,"ASoC: shutdown FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002373
2374 /* run the stream event for each BE */
2375 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2376
2377 return 0;
2378}
2379
2380static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
2381{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002382 struct snd_pcm_substream *substream =
2383 snd_soc_dpcm_get_substream(fe, stream);
Liam Girdwood618dae12012-04-25 12:12:51 +01002384 struct snd_soc_dpcm *dpcm;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002385 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Souptick Joarder4eeed5f2021-01-09 09:15:01 +05302386 int ret = 0;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002387 unsigned long flags;
Liam Girdwood618dae12012-04-25 12:12:51 +01002388
Liam Girdwood103d84a2012-11-19 14:39:15 +00002389 dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002390 stream ? "capture" : "playback", fe->dai_link->name);
2391
2392 /* Only start the BE if the FE is ready */
2393 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
朱灿灿2c138282020-12-25 16:42:46 +08002394 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE) {
Souptick Joarder4eeed5f2021-01-09 09:15:01 +05302395 ret = -EINVAL;
朱灿灿2c138282020-12-25 16:42:46 +08002396 dev_err(fe->dev, "ASoC: FE %s is not ready %d\n",
2397 fe->dai_link->name, fe->dpcm[stream].state);
Dan Carpentere91b65b2021-01-11 12:50:21 +03002398 ret = -EINVAL;
朱灿灿2c138282020-12-25 16:42:46 +08002399 goto disconnect;
2400 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002401
2402 /* startup must always be called for new BEs */
2403 ret = dpcm_be_dai_startup(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002404 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002405 goto disconnect;
Liam Girdwood618dae12012-04-25 12:12:51 +01002406
2407 /* keep going if FE state is > open */
2408 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN)
2409 return 0;
2410
2411 ret = dpcm_be_dai_hw_params(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002412 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002413 goto close;
Liam Girdwood618dae12012-04-25 12:12:51 +01002414
2415 /* keep going if FE state is > hw_params */
2416 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS)
2417 return 0;
2418
2419
2420 ret = dpcm_be_dai_prepare(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002421 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002422 goto hw_free;
Liam Girdwood618dae12012-04-25 12:12:51 +01002423
2424 /* run the stream event for each BE */
2425 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2426
2427 /* keep going if FE state is > prepare */
2428 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE ||
2429 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP)
2430 return 0;
2431
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002432 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2433 /* call trigger on the frontend - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002434 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002435 fe->dai_link->name);
Liam Girdwood618dae12012-04-25 12:12:51 +01002436
Kuninori Morimoto308193582020-04-24 08:15:09 +09002437 ret = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002438 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002439 dev_err(fe->dev,"ASoC: bespoke trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002440 goto hw_free;
2441 }
2442 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002443 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002444 fe->dai_link->name);
2445
2446 ret = dpcm_be_dai_trigger(fe, stream,
2447 SNDRV_PCM_TRIGGER_START);
2448 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002449 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002450 goto hw_free;
2451 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002452 }
2453
2454 return 0;
2455
2456hw_free:
2457 dpcm_be_dai_hw_free(fe, stream);
2458close:
2459 dpcm_be_dai_shutdown(fe, stream);
2460disconnect:
朱灿灿2c138282020-12-25 16:42:46 +08002461 /* disconnect any pending BEs */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002462 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002463 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood618dae12012-04-25 12:12:51 +01002464 struct snd_soc_pcm_runtime *be = dpcm->be;
朱灿灿2c138282020-12-25 16:42:46 +08002465
2466 /* is this op for this BE ? */
2467 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2468 continue;
2469
2470 if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE ||
2471 be->dpcm[stream].state == SND_SOC_DPCM_STATE_NEW)
2472 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
Liam Girdwood618dae12012-04-25 12:12:51 +01002473 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002474 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood618dae12012-04-25 12:12:51 +01002475
2476 return ret;
2477}
2478
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002479static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
2480{
2481 struct snd_soc_dapm_widget_list *list;
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002482 int stream;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002483 int count, paths;
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002484 int ret;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002485
Pierre-Louis Bossart96bf62f2020-06-12 15:35:07 -05002486 if (!fe->dai_link->dynamic)
2487 return 0;
2488
Bard Liao6e1276a2020-02-25 21:39:16 +08002489 if (fe->num_cpus > 1) {
2490 dev_err(fe->dev,
2491 "%s doesn't support Multi CPU yet\n", __func__);
2492 return -EINVAL;
2493 }
2494
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002495 /* only check active links */
Kuninori Morimotob3dea622020-05-15 09:46:51 +09002496 if (!snd_soc_dai_active(asoc_rtd_to_cpu(fe, 0)))
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002497 return 0;
2498
2499 /* DAPM sync will call this to update DSP paths */
2500 dev_dbg(fe->dev, "ASoC: DPCM %s runtime update for FE %s\n",
2501 new ? "new" : "old", fe->dai_link->name);
2502
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002503 for_each_pcm_streams(stream) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002504
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002505 /* skip if FE doesn't have playback/capture capability */
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002506 if (!snd_soc_dai_stream_valid(asoc_rtd_to_cpu(fe, 0), stream) ||
2507 !snd_soc_dai_stream_valid(asoc_rtd_to_codec(fe, 0), stream))
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002508 continue;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002509
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002510 /* skip if FE isn't currently playing/capturing */
Kuninori Morimotob3dea622020-05-15 09:46:51 +09002511 if (!snd_soc_dai_stream_active(asoc_rtd_to_cpu(fe, 0), stream) ||
2512 !snd_soc_dai_stream_active(asoc_rtd_to_codec(fe, 0), stream))
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002513 continue;
2514
2515 paths = dpcm_path_get(fe, stream, &list);
2516 if (paths < 0) {
2517 dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
2518 fe->dai_link->name,
2519 stream == SNDRV_PCM_STREAM_PLAYBACK ?
2520 "playback" : "capture");
2521 return paths;
2522 }
2523
2524 /* update any playback/capture paths */
2525 count = dpcm_process_paths(fe, stream, &list, new);
2526 if (count) {
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002527 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002528 if (new)
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002529 ret = dpcm_run_update_startup(fe, stream);
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002530 else
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002531 ret = dpcm_run_update_shutdown(fe, stream);
2532 if (ret < 0)
2533 dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n");
2534 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002535
2536 dpcm_clear_pending_state(fe, stream);
2537 dpcm_be_disconnect(fe, stream);
2538 }
2539
2540 dpcm_path_put(&list);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002541 }
2542
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002543 return 0;
2544}
2545
Liam Girdwood618dae12012-04-25 12:12:51 +01002546/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
2547 * any DAI links.
2548 */
Guennadi Liakhovetskif17a1472020-03-12 10:52:14 +01002549int snd_soc_dpcm_runtime_update(struct snd_soc_card *card)
Liam Girdwood618dae12012-04-25 12:12:51 +01002550{
Mengdong Lin1a497982015-11-18 02:34:11 -05002551 struct snd_soc_pcm_runtime *fe;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002552 int ret = 0;
Liam Girdwood618dae12012-04-25 12:12:51 +01002553
Liam Girdwood618dae12012-04-25 12:12:51 +01002554 mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002555 /* shutdown all old paths first */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002556 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002557 ret = soc_dpcm_fe_runtime_update(fe, 0);
2558 if (ret)
2559 goto out;
Liam Girdwood618dae12012-04-25 12:12:51 +01002560 }
2561
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002562 /* bring new paths up */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002563 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002564 ret = soc_dpcm_fe_runtime_update(fe, 1);
2565 if (ret)
2566 goto out;
2567 }
2568
2569out:
Liam Girdwood618dae12012-04-25 12:12:51 +01002570 mutex_unlock(&card->mutex);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002571 return ret;
Liam Girdwood618dae12012-04-25 12:12:51 +01002572}
Guennadi Liakhovetskif17a1472020-03-12 10:52:14 +01002573EXPORT_SYMBOL_GPL(snd_soc_dpcm_runtime_update);
Liam Girdwood01d75842012-04-25 12:12:49 +01002574
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002575static void dpcm_fe_dai_cleanup(struct snd_pcm_substream *fe_substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002576{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002577 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002578 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002579 int stream = fe_substream->stream;
Kuninori Morimoto30fca262020-03-06 10:09:44 +09002580
2581 /* mark FE's links ready to prune */
2582 for_each_dpcm_be(fe, stream, dpcm)
2583 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2584
2585 dpcm_be_disconnect(fe, stream);
2586
2587 fe->dpcm[stream].runtime = NULL;
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002588}
2589
2590static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
2591{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002592 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002593 int ret;
2594
2595 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2596 ret = dpcm_fe_dai_shutdown(fe_substream);
2597
2598 dpcm_fe_dai_cleanup(fe_substream);
2599
Kuninori Morimoto30fca262020-03-06 10:09:44 +09002600 mutex_unlock(&fe->card->mutex);
2601 return ret;
2602}
2603
Liam Girdwood01d75842012-04-25 12:12:49 +01002604static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
2605{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002606 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002607 struct snd_soc_dapm_widget_list *list;
2608 int ret;
2609 int stream = fe_substream->stream;
2610
2611 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2612 fe->dpcm[stream].runtime = fe_substream->runtime;
2613
Qiao Zhou8f70e512014-09-10 17:54:07 +08002614 ret = dpcm_path_get(fe, stream, &list);
2615 if (ret < 0) {
Kuninori Morimotocae06eb2020-02-17 17:28:11 +09002616 goto open_end;
Qiao Zhou8f70e512014-09-10 17:54:07 +08002617 } else if (ret == 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002618 dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002619 fe->dai_link->name, stream ? "capture" : "playback");
Liam Girdwood01d75842012-04-25 12:12:49 +01002620 }
2621
2622 /* calculate valid and active FE <-> BE dpcms */
2623 dpcm_process_paths(fe, stream, &list, 1);
2624
2625 ret = dpcm_fe_dai_startup(fe_substream);
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002626 if (ret < 0)
2627 dpcm_fe_dai_cleanup(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002628
2629 dpcm_clear_pending_state(fe, stream);
2630 dpcm_path_put(&list);
Kuninori Morimotocae06eb2020-02-17 17:28:11 +09002631open_end:
Liam Girdwood01d75842012-04-25 12:12:49 +01002632 mutex_unlock(&fe->card->mutex);
2633 return ret;
2634}
2635
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002636static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd,
2637 int *playback, int *capture)
Liam Girdwoodddee6272011-06-09 14:45:53 +01002638{
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002639 struct snd_soc_dai *codec_dai;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002640 struct snd_soc_dai *cpu_dai;
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002641 int stream;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002642 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002643
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002644 if (rtd->dai_link->dynamic && rtd->num_cpus > 1) {
2645 dev_err(rtd->dev,
2646 "DPCM doesn't support Multi CPU for Front-Ends yet\n");
2647 return -EINVAL;
2648 }
Stephan Gerhold9b5db052020-04-15 12:49:28 +02002649
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002650 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
2651 if (rtd->dai_link->dpcm_playback) {
2652 stream = SNDRV_PCM_STREAM_PLAYBACK;
2653
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002654 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
2655 if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002656 *playback = 1;
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002657 break;
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002658 }
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002659 }
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002660 if (!*playback) {
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002661 dev_err(rtd->card->dev,
2662 "No CPU DAIs support playback for stream %s\n",
2663 rtd->dai_link->stream_name);
2664 return -EINVAL;
2665 }
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002666 }
2667 if (rtd->dai_link->dpcm_capture) {
2668 stream = SNDRV_PCM_STREAM_CAPTURE;
2669
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002670 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
2671 if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002672 *capture = 1;
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002673 break;
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002674 }
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002675 }
2676
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002677 if (!*capture) {
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002678 dev_err(rtd->card->dev,
2679 "No CPU DAIs support capture for stream %s\n",
2680 rtd->dai_link->stream_name);
2681 return -EINVAL;
2682 }
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002683 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002684 } else {
Jerome Bruneta3420312019-07-25 18:59:47 +02002685 /* Adapt stream for codec2codec links */
Stephan Gerholda4877a62020-02-18 11:38:24 +01002686 int cpu_capture = rtd->dai_link->params ?
2687 SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
2688 int cpu_playback = rtd->dai_link->params ?
2689 SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
Jerome Bruneta3420312019-07-25 18:59:47 +02002690
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09002691 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002692 if (rtd->num_cpus == 1) {
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002693 cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002694 } else if (rtd->num_cpus == rtd->num_codecs) {
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002695 cpu_dai = asoc_rtd_to_cpu(rtd, i);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002696 } else {
2697 dev_err(rtd->card->dev,
2698 "N cpus to M codecs link is not supported yet\n");
2699 return -EINVAL;
2700 }
2701
Kuninori Morimoto467fece2019-07-22 10:36:16 +09002702 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
Stephan Gerholda4877a62020-02-18 11:38:24 +01002703 snd_soc_dai_stream_valid(cpu_dai, cpu_playback))
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002704 *playback = 1;
Kuninori Morimoto467fece2019-07-22 10:36:16 +09002705 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
Stephan Gerholda4877a62020-02-18 11:38:24 +01002706 snd_soc_dai_stream_valid(cpu_dai, cpu_capture))
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002707 *capture = 1;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002708 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002709 }
Sangsu Parka5002312012-01-02 17:15:10 +09002710
Fabio Estevamd6bead02013-08-29 10:32:13 -03002711 if (rtd->dai_link->playback_only) {
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002712 *playback = 1;
2713 *capture = 0;
Fabio Estevamd6bead02013-08-29 10:32:13 -03002714 }
2715
2716 if (rtd->dai_link->capture_only) {
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002717 *playback = 0;
2718 *capture = 1;
Fabio Estevamd6bead02013-08-29 10:32:13 -03002719 }
2720
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002721 return 0;
2722}
2723
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002724static int soc_create_pcm(struct snd_pcm **pcm,
2725 struct snd_soc_pcm_runtime *rtd,
2726 int playback, int capture, int num)
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002727{
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002728 char new_name[64];
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002729 int ret;
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002730
Liam Girdwood01d75842012-04-25 12:12:49 +01002731 /* create the PCM */
Jerome Bruneta3420312019-07-25 18:59:47 +02002732 if (rtd->dai_link->params) {
2733 snprintf(new_name, sizeof(new_name), "codec2codec(%s)",
2734 rtd->dai_link->stream_name);
2735
2736 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002737 playback, capture, pcm);
Jerome Bruneta3420312019-07-25 18:59:47 +02002738 } else if (rtd->dai_link->no_pcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002739 snprintf(new_name, sizeof(new_name), "(%s)",
2740 rtd->dai_link->stream_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002741
Liam Girdwood01d75842012-04-25 12:12:49 +01002742 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002743 playback, capture, pcm);
Liam Girdwood01d75842012-04-25 12:12:49 +01002744 } else {
2745 if (rtd->dai_link->dynamic)
2746 snprintf(new_name, sizeof(new_name), "%s (*)",
2747 rtd->dai_link->stream_name);
2748 else
2749 snprintf(new_name, sizeof(new_name), "%s %s-%d",
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002750 rtd->dai_link->stream_name,
2751 (rtd->num_codecs > 1) ?
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002752 "multicodec" : asoc_rtd_to_codec(rtd, 0)->name, num);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002753
Liam Girdwood01d75842012-04-25 12:12:49 +01002754 ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002755 capture, pcm);
Liam Girdwood01d75842012-04-25 12:12:49 +01002756 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01002757 if (ret < 0) {
Pierre-Louis Bossart799827a2020-06-12 15:40:49 -05002758 dev_err(rtd->card->dev, "ASoC: can't create pcm %s for dailink %s: %d\n",
2759 new_name, rtd->dai_link->name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002760 return ret;
2761 }
Liam Girdwood103d84a2012-11-19 14:39:15 +00002762 dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002763
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002764 return 0;
2765}
2766
2767/* create a new pcm */
2768int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
2769{
2770 struct snd_soc_component *component;
2771 struct snd_pcm *pcm;
2772 int ret = 0, playback = 0, capture = 0;
2773 int i;
2774
2775 ret = soc_get_playback_capture(rtd, &playback, &capture);
2776 if (ret < 0)
2777 return ret;
2778
2779 ret = soc_create_pcm(&pcm, rtd, playback, capture, num);
2780 if (ret < 0)
2781 return ret;
2782
Liam Girdwoodddee6272011-06-09 14:45:53 +01002783 /* DAPM dai link stream work */
Jerome Bruneta3420312019-07-25 18:59:47 +02002784 if (rtd->dai_link->params)
Curtis Malainey4bf2e382019-12-03 09:30:07 -08002785 rtd->close_delayed_work_func = codec2codec_close_delayed_work;
Jerome Bruneta3420312019-07-25 18:59:47 +02002786 else
Kuninori Morimoto83f94a22020-01-10 11:36:17 +09002787 rtd->close_delayed_work_func = snd_soc_close_delayed_work;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002788
2789 rtd->pcm = pcm;
Kuninori Morimotoe04e7b82021-01-22 10:13:32 +09002790 pcm->nonatomic = rtd->dai_link->nonatomic;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002791 pcm->private_data = rtd;
Liam Girdwood01d75842012-04-25 12:12:49 +01002792
Jerome Bruneta3420312019-07-25 18:59:47 +02002793 if (rtd->dai_link->no_pcm || rtd->dai_link->params) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002794 if (playback)
2795 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
2796 if (capture)
2797 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
2798 goto out;
2799 }
2800
2801 /* ASoC PCM operations */
2802 if (rtd->dai_link->dynamic) {
2803 rtd->ops.open = dpcm_fe_dai_open;
2804 rtd->ops.hw_params = dpcm_fe_dai_hw_params;
2805 rtd->ops.prepare = dpcm_fe_dai_prepare;
2806 rtd->ops.trigger = dpcm_fe_dai_trigger;
2807 rtd->ops.hw_free = dpcm_fe_dai_hw_free;
2808 rtd->ops.close = dpcm_fe_dai_close;
2809 rtd->ops.pointer = soc_pcm_pointer;
2810 } else {
2811 rtd->ops.open = soc_pcm_open;
2812 rtd->ops.hw_params = soc_pcm_hw_params;
2813 rtd->ops.prepare = soc_pcm_prepare;
2814 rtd->ops.trigger = soc_pcm_trigger;
2815 rtd->ops.hw_free = soc_pcm_hw_free;
2816 rtd->ops.close = soc_pcm_close;
2817 rtd->ops.pointer = soc_pcm_pointer;
2818 }
2819
Kuninori Morimoto613fb502020-01-10 11:35:21 +09002820 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto2b544dd2019-10-15 12:59:31 +09002821 const struct snd_soc_component_driver *drv = component->driver;
Kuninori Morimotob8135862017-10-11 01:37:23 +00002822
Takashi Iwai3b1c9522019-11-21 20:07:08 +01002823 if (drv->ioctl)
2824 rtd->ops.ioctl = snd_soc_pcm_component_ioctl;
Takashi Iwai1e5ddb62019-11-21 20:07:09 +01002825 if (drv->sync_stop)
2826 rtd->ops.sync_stop = snd_soc_pcm_component_sync_stop;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002827 if (drv->copy_user)
Kuninori Morimoto82d81f52019-07-26 13:51:56 +09002828 rtd->ops.copy_user = snd_soc_pcm_component_copy_user;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002829 if (drv->page)
Kuninori Morimoto9c712e42019-07-26 13:52:00 +09002830 rtd->ops.page = snd_soc_pcm_component_page;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002831 if (drv->mmap)
Kuninori Morimoto205875e2019-07-26 13:52:04 +09002832 rtd->ops.mmap = snd_soc_pcm_component_mmap;
Kuninori Morimotob8135862017-10-11 01:37:23 +00002833 }
2834
Liam Girdwoodddee6272011-06-09 14:45:53 +01002835 if (playback)
Liam Girdwood01d75842012-04-25 12:12:49 +01002836 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002837
2838 if (capture)
Liam Girdwood01d75842012-04-25 12:12:49 +01002839 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002840
Kuninori Morimotob2b2afb2019-11-18 10:50:32 +09002841 ret = snd_soc_pcm_component_new(rtd);
Kuninori Morimoto74842912019-07-26 13:52:08 +09002842 if (ret < 0) {
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002843 dev_err(rtd->dev, "ASoC: pcm constructor failed for dailink %s: %d\n",
2844 rtd->dai_link->name, ret);
Kuninori Morimoto74842912019-07-26 13:52:08 +09002845 return ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002846 }
Johan Hovoldc641e5b2017-07-12 17:55:29 +02002847
Takashi Iwai3d21ef02019-01-11 15:58:39 +01002848 pcm->no_device_suspend = true;
Liam Girdwood01d75842012-04-25 12:12:49 +01002849out:
Pierre-Louis Bossart1d5cd522020-06-12 15:40:50 -05002850 dev_dbg(rtd->card->dev, "%s <-> %s mapping ok\n",
2851 (rtd->num_codecs > 1) ? "multicodec" : asoc_rtd_to_codec(rtd, 0)->name,
2852 (rtd->num_cpus > 1) ? "multicpu" : asoc_rtd_to_cpu(rtd, 0)->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002853 return ret;
2854}
Liam Girdwood01d75842012-04-25 12:12:49 +01002855
2856/* is the current PCM operation for this FE ? */
2857int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream)
2858{
2859 if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE)
2860 return 1;
2861 return 0;
2862}
2863EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update);
2864
2865/* is the current PCM operation for this BE ? */
2866int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
2867 struct snd_soc_pcm_runtime *be, int stream)
2868{
2869 if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) ||
2870 ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) &&
2871 be->dpcm[stream].runtime_update))
2872 return 1;
2873 return 0;
2874}
2875EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update);
2876
2877/* get the substream for this BE */
2878struct snd_pcm_substream *
2879 snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream)
2880{
2881 return be->pcm->streams[stream].substream;
2882}
2883EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream);
2884
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002885static int snd_soc_dpcm_check_state(struct snd_soc_pcm_runtime *fe,
2886 struct snd_soc_pcm_runtime *be,
2887 int stream,
2888 const enum snd_soc_dpcm_state *states,
2889 int num_states)
Liam Girdwood01d75842012-04-25 12:12:49 +01002890{
2891 struct snd_soc_dpcm *dpcm;
2892 int state;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002893 int ret = 1;
2894 unsigned long flags;
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002895 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01002896
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002897 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00002898 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002899
2900 if (dpcm->fe == fe)
2901 continue;
2902
2903 state = dpcm->fe->dpcm[stream].state;
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002904 for (i = 0; i < num_states; i++) {
2905 if (state == states[i]) {
2906 ret = 0;
2907 break;
2908 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002909 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002910 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002911 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01002912
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002913 /* it's safe to do this BE DAI */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002914 return ret;
Liam Girdwood01d75842012-04-25 12:12:49 +01002915}
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002916
2917/*
2918 * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE
2919 * are not running, paused or suspended for the specified stream direction.
2920 */
2921int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
2922 struct snd_soc_pcm_runtime *be, int stream)
2923{
2924 const enum snd_soc_dpcm_state state[] = {
2925 SND_SOC_DPCM_STATE_START,
2926 SND_SOC_DPCM_STATE_PAUSED,
2927 SND_SOC_DPCM_STATE_SUSPEND,
2928 };
2929
2930 return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
2931}
Liam Girdwood01d75842012-04-25 12:12:49 +01002932EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop);
2933
2934/*
2935 * We can only change hw params a BE DAI if any of it's FE are not prepared,
2936 * running, paused or suspended for the specified stream direction.
2937 */
2938int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
2939 struct snd_soc_pcm_runtime *be, int stream)
2940{
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002941 const enum snd_soc_dpcm_state state[] = {
2942 SND_SOC_DPCM_STATE_START,
2943 SND_SOC_DPCM_STATE_PAUSED,
2944 SND_SOC_DPCM_STATE_SUSPEND,
2945 SND_SOC_DPCM_STATE_PREPARE,
2946 };
Liam Girdwood01d75842012-04-25 12:12:49 +01002947
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002948 return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
Liam Girdwood01d75842012-04-25 12:12:49 +01002949}
2950EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);