blob: a956d1852ade2096d0dd906ca8b7a0488d9e3969 [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 Morimoto6fb89442021-03-09 10:07:48 +090032static inline const char *soc_cpu_dai_name(struct snd_soc_pcm_runtime *rtd)
33{
34 return (rtd)->num_cpus == 1 ? asoc_rtd_to_cpu(rtd, 0)->name : "multicpu";
35}
36static inline const char *soc_codec_dai_name(struct snd_soc_pcm_runtime *rtd)
37{
38 return (rtd)->num_codecs == 1 ? asoc_rtd_to_codec(rtd, 0)->name : "multicodec";
39}
40
Kuninori Morimotoc3212822020-02-19 15:56:57 +090041#ifdef CONFIG_DEBUG_FS
42static const char *dpcm_state_string(enum snd_soc_dpcm_state state)
43{
44 switch (state) {
45 case SND_SOC_DPCM_STATE_NEW:
46 return "new";
47 case SND_SOC_DPCM_STATE_OPEN:
48 return "open";
49 case SND_SOC_DPCM_STATE_HW_PARAMS:
50 return "hw_params";
51 case SND_SOC_DPCM_STATE_PREPARE:
52 return "prepare";
53 case SND_SOC_DPCM_STATE_START:
54 return "start";
55 case SND_SOC_DPCM_STATE_STOP:
56 return "stop";
57 case SND_SOC_DPCM_STATE_SUSPEND:
58 return "suspend";
59 case SND_SOC_DPCM_STATE_PAUSED:
60 return "paused";
61 case SND_SOC_DPCM_STATE_HW_FREE:
62 return "hw_free";
63 case SND_SOC_DPCM_STATE_CLOSE:
64 return "close";
65 }
66
67 return "unknown";
68}
69
70static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
71 int stream, char *buf, size_t size)
72{
73 struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params;
74 struct snd_soc_dpcm *dpcm;
75 ssize_t offset = 0;
76 unsigned long flags;
77
78 /* FE state */
Takashi Iwaid0c9abb2020-03-10 17:36:25 +010079 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +090080 "[%s - %s]\n", fe->dai_link->name,
81 stream ? "Capture" : "Playback");
82
Takashi Iwaid0c9abb2020-03-10 17:36:25 +010083 offset += scnprintf(buf + offset, size - offset, "State: %s\n",
Kuninori Morimotoc3212822020-02-19 15:56:57 +090084 dpcm_state_string(fe->dpcm[stream].state));
85
86 if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
87 (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
Takashi Iwaid0c9abb2020-03-10 17:36:25 +010088 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +090089 "Hardware Params: "
90 "Format = %s, Channels = %d, Rate = %d\n",
91 snd_pcm_format_name(params_format(params)),
92 params_channels(params),
93 params_rate(params));
94
95 /* BEs state */
Takashi Iwaid0c9abb2020-03-10 17:36:25 +010096 offset += scnprintf(buf + offset, size - offset, "Backends:\n");
Kuninori Morimotoc3212822020-02-19 15:56:57 +090097
98 if (list_empty(&fe->dpcm[stream].be_clients)) {
Takashi Iwaid0c9abb2020-03-10 17:36:25 +010099 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900100 " No active DSP links\n");
101 goto out;
102 }
103
104 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
105 for_each_dpcm_be(fe, stream, dpcm) {
106 struct snd_soc_pcm_runtime *be = dpcm->be;
107 params = &dpcm->hw_params;
108
Takashi Iwaid0c9abb2020-03-10 17:36:25 +0100109 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900110 "- %s\n", be->dai_link->name);
111
Takashi Iwaid0c9abb2020-03-10 17:36:25 +0100112 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900113 " State: %s\n",
114 dpcm_state_string(be->dpcm[stream].state));
115
116 if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
117 (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
Takashi Iwaid0c9abb2020-03-10 17:36:25 +0100118 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900119 " Hardware Params: "
120 "Format = %s, Channels = %d, Rate = %d\n",
121 snd_pcm_format_name(params_format(params)),
122 params_channels(params),
123 params_rate(params));
124 }
125 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
126out:
127 return offset;
128}
129
130static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf,
131 size_t count, loff_t *ppos)
132{
133 struct snd_soc_pcm_runtime *fe = file->private_data;
134 ssize_t out_count = PAGE_SIZE, offset = 0, ret = 0;
135 int stream;
136 char *buf;
137
Bard Liao6e1276a2020-02-25 21:39:16 +0800138 if (fe->num_cpus > 1) {
139 dev_err(fe->dev,
140 "%s doesn't support Multi CPU yet\n", __func__);
141 return -EINVAL;
142 }
143
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900144 buf = kmalloc(out_count, GFP_KERNEL);
145 if (!buf)
146 return -ENOMEM;
147
148 for_each_pcm_streams(stream)
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900149 if (snd_soc_dai_stream_valid(asoc_rtd_to_cpu(fe, 0), stream))
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900150 offset += dpcm_show_state(fe, stream,
151 buf + offset,
152 out_count - offset);
153
154 ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
155
156 kfree(buf);
157 return ret;
158}
159
160static const struct file_operations dpcm_state_fops = {
161 .open = simple_open,
162 .read = dpcm_state_read_file,
163 .llseek = default_llseek,
164};
165
166void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
167{
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900168 if (!rtd->dai_link->dynamic)
169 return;
170
171 if (!rtd->card->debugfs_card_root)
172 return;
173
174 rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name,
175 rtd->card->debugfs_card_root);
176
177 debugfs_create_file("state", 0444, rtd->debugfs_dpcm_root,
178 rtd, &dpcm_state_fops);
179}
Kuninori Morimoto154dae82020-02-19 15:57:06 +0900180
181static void dpcm_create_debugfs_state(struct snd_soc_dpcm *dpcm, int stream)
182{
183 char *name;
184
185 name = kasprintf(GFP_KERNEL, "%s:%s", dpcm->be->dai_link->name,
186 stream ? "capture" : "playback");
187 if (name) {
188 dpcm->debugfs_state = debugfs_create_dir(
189 name, dpcm->fe->debugfs_dpcm_root);
190 debugfs_create_u32("state", 0644, dpcm->debugfs_state,
191 &dpcm->state);
192 kfree(name);
193 }
194}
195
196static void dpcm_remove_debugfs_state(struct snd_soc_dpcm *dpcm)
197{
198 debugfs_remove_recursive(dpcm->debugfs_state);
199}
200
201#else
202static inline void dpcm_create_debugfs_state(struct snd_soc_dpcm *dpcm,
203 int stream)
204{
205}
206
207static inline void dpcm_remove_debugfs_state(struct snd_soc_dpcm *dpcm)
208{
209}
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900210#endif
211
Kuninori Morimoto9c6d7f92020-12-11 14:55:16 +0900212/* Set FE's runtime_update state; the state is protected via PCM stream lock
213 * for avoiding the race with trigger callback.
214 * If the state is unset and a trigger is pending while the previous operation,
215 * process the pending trigger action here.
216 */
217static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
218static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
219 int stream, enum snd_soc_dpcm_update state)
220{
221 struct snd_pcm_substream *substream =
222 snd_soc_dpcm_get_substream(fe, stream);
223
224 snd_pcm_stream_lock_irq(substream);
225 if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) {
226 dpcm_fe_dai_do_trigger(substream,
227 fe->dpcm[stream].trigger_pending - 1);
228 fe->dpcm[stream].trigger_pending = 0;
229 }
230 fe->dpcm[stream].runtime_update = state;
231 snd_pcm_stream_unlock_irq(substream);
232}
233
Kuninori Morimotoa7e204442020-12-11 14:55:22 +0900234static void dpcm_set_be_update_state(struct snd_soc_pcm_runtime *be,
235 int stream, enum snd_soc_dpcm_update state)
236{
237 be->dpcm[stream].runtime_update = state;
238}
239
Kuninori Morimotod9051d82020-05-15 09:46:21 +0900240/**
241 * snd_soc_runtime_action() - Increment/Decrement active count for
242 * PCM runtime components
243 * @rtd: ASoC PCM runtime that is activated
244 * @stream: Direction of the PCM stream
Colton Lewisb6d6e9e2020-06-26 05:40:24 +0000245 * @action: Activate stream if 1. Deactivate if -1.
Kuninori Morimotod9051d82020-05-15 09:46:21 +0900246 *
247 * Increments/Decrements the active count for all the DAIs and components
248 * attached to a PCM runtime.
249 * Should typically be called when a stream is opened.
250 *
251 * Must be called with the rtd->card->pcm_mutex being held
252 */
253void snd_soc_runtime_action(struct snd_soc_pcm_runtime *rtd,
254 int stream, int action)
Kuninori Morimoto7a5aaba2020-02-10 12:14:12 +0900255{
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900256 struct snd_soc_dai *dai;
Kuninori Morimoto7a5aaba2020-02-10 12:14:12 +0900257 int i;
258
259 lockdep_assert_held(&rtd->card->pcm_mutex);
260
Kuninori Morimotodc829102020-05-15 09:46:27 +0900261 for_each_rtd_dais(rtd, i, dai)
262 snd_soc_dai_action(dai, stream, action);
Kuninori Morimoto7a5aaba2020-02-10 12:14:12 +0900263}
Kuninori Morimotod9051d82020-05-15 09:46:21 +0900264EXPORT_SYMBOL_GPL(snd_soc_runtime_action);
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100265
266/**
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100267 * snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay
268 * @rtd: The ASoC PCM runtime that should be checked.
269 *
270 * This function checks whether the power down delay should be ignored for a
271 * specific PCM runtime. Returns true if the delay is 0, if it the DAI link has
272 * been configured to ignore the delay, or if none of the components benefits
273 * from having the delay.
274 */
275bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
276{
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000277 struct snd_soc_component *component;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200278 bool ignore = true;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900279 int i;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200280
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100281 if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
282 return true;
283
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900284 for_each_rtd_components(rtd, i, component)
Kuninori Morimoto72c38182018-01-19 05:21:19 +0000285 ignore &= !component->driver->use_pmdown_time;
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000286
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000287 return ignore;
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100288}
289
290/**
Lars-Peter Clausen90996f42013-05-14 11:05:30 +0200291 * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
292 * @substream: the pcm substream
293 * @hw: the hardware parameters
294 *
295 * Sets the substream runtime hardware parameters.
296 */
297int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
298 const struct snd_pcm_hardware *hw)
299{
Kuninori Morimoto56e749b2021-03-09 10:07:53 +0900300 substream->runtime->hw = *hw;
301
Lars-Peter Clausen90996f42013-05-14 11:05:30 +0200302 return 0;
303}
304EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
305
Liam Girdwood01d75842012-04-25 12:12:49 +0100306/* DPCM stream event, send event to FE and all active BEs. */
Liam Girdwood23607022014-01-17 17:03:55 +0000307int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
Liam Girdwood01d75842012-04-25 12:12:49 +0100308 int event)
309{
310 struct snd_soc_dpcm *dpcm;
311
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +0000312 for_each_dpcm_be(fe, dir, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +0100313
314 struct snd_soc_pcm_runtime *be = dpcm->be;
315
Liam Girdwood103d84a2012-11-19 14:39:15 +0000316 dev_dbg(be->dev, "ASoC: BE %s event %d dir %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +0100317 be->dai_link->name, event, dir);
318
Banajit Goswamib1cd2e32017-07-14 23:15:05 -0700319 if ((event == SND_SOC_DAPM_STREAM_STOP) &&
320 (be->dpcm[dir].users >= 1))
321 continue;
322
Liam Girdwood01d75842012-04-25 12:12:49 +0100323 snd_soc_dapm_stream_event(be, dir, event);
324 }
325
326 snd_soc_dapm_stream_event(fe, dir, event);
327
328 return 0;
329}
330
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900331static void soc_pcm_set_dai_params(struct snd_soc_dai *dai,
332 struct snd_pcm_hw_params *params)
333{
334 if (params) {
335 dai->rate = params_rate(params);
336 dai->channels = params_channels(params);
337 dai->sample_bits = snd_pcm_format_physical_width(params_format(params));
338 } else {
339 dai->rate = 0;
340 dai->channels = 0;
341 dai->sample_bits = 0;
342 }
343}
344
Dong Aisheng17841022011-08-29 17:15:14 +0800345static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
346 struct snd_soc_dai *soc_dai)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100347{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900348 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100349 int ret;
350
Kuninori Morimotof8fc9ec2021-03-09 10:07:42 +0900351 if (!snd_soc_dai_active(soc_dai))
352 return 0;
353
Kuninori Morimotofac110c2021-01-15 13:56:35 +0900354#define __soc_pcm_apply_symmetry(name, NAME) \
355 if (soc_dai->name && (soc_dai->driver->symmetric_##name || \
356 rtd->dai_link->symmetric_##name)) { \
357 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %s to %d\n",\
358 #name, soc_dai->name); \
359 \
360 ret = snd_pcm_hw_constraint_single(substream->runtime, \
361 SNDRV_PCM_HW_PARAM_##NAME,\
362 soc_dai->name); \
363 if (ret < 0) { \
364 dev_err(soc_dai->dev, \
365 "ASoC: Unable to apply %s constraint: %d\n",\
366 #name, ret); \
367 return ret; \
368 } \
Liam Girdwoodddee6272011-06-09 14:45:53 +0100369 }
370
Kuninori Morimotofac110c2021-01-15 13:56:35 +0900371 __soc_pcm_apply_symmetry(rate, RATE);
372 __soc_pcm_apply_symmetry(channels, CHANNELS);
373 __soc_pcm_apply_symmetry(sample_bits, SAMPLE_BITS);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100374
375 return 0;
376}
377
Nicolin Chen3635bf02013-11-13 18:56:24 +0800378static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
379 struct snd_pcm_hw_params *params)
380{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900381 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900382 struct snd_soc_dai d;
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900383 struct snd_soc_dai *dai;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800384 struct snd_soc_dai *cpu_dai;
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900385 unsigned int symmetry, i;
Nicolin Chen3635bf02013-11-13 18:56:24 +0800386
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900387 soc_pcm_set_dai_params(&d, params);
Nicolin Chen3635bf02013-11-13 18:56:24 +0800388
Kuninori Morimoto3a906722021-01-15 13:56:39 +0900389#define __soc_pcm_params_symmetry(name) \
390 symmetry = rtd->dai_link->symmetric_##name; \
391 for_each_rtd_dais(rtd, i, dai) \
392 symmetry |= dai->driver->symmetric_##name; \
393 \
394 if (symmetry) \
395 for_each_rtd_cpu_dais(rtd, i, cpu_dai) \
396 if (cpu_dai->name && cpu_dai->name != d.name) { \
397 dev_err(rtd->dev, "ASoC: unmatched %s symmetry: %d - %d\n", \
398 #name, cpu_dai->name, d.name); \
399 return -EINVAL; \
400 }
401
Nicolin Chen3635bf02013-11-13 18:56:24 +0800402 /* reject unmatched parameters when applying symmetry */
Kuninori Morimoto3a906722021-01-15 13:56:39 +0900403 __soc_pcm_params_symmetry(rate);
404 __soc_pcm_params_symmetry(channels);
405 __soc_pcm_params_symmetry(sample_bits);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100406
407 return 0;
408}
409
Kuninori Morimoto68cbc552021-03-09 10:07:57 +0900410static void soc_pcm_update_symmetry(struct snd_pcm_substream *substream)
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100411{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900412 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100413 struct snd_soc_dai_link *link = rtd->dai_link;
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900414 struct snd_soc_dai *dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200415 unsigned int symmetry, i;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100416
Kuninori Morimotof14654d2021-01-15 13:52:54 +0900417 symmetry = link->symmetric_rate ||
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800418 link->symmetric_channels ||
Kuninori Morimotof14654d2021-01-15 13:52:54 +0900419 link->symmetric_sample_bits;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800420
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900421 for_each_rtd_dais(rtd, i, dai)
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800422 symmetry = symmetry ||
Kuninori Morimotof14654d2021-01-15 13:52:54 +0900423 dai->driver->symmetric_rate ||
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900424 dai->driver->symmetric_channels ||
Kuninori Morimotof14654d2021-01-15 13:52:54 +0900425 dai->driver->symmetric_sample_bits;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200426
Kuninori Morimoto68cbc552021-03-09 10:07:57 +0900427 if (symmetry)
428 substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100429}
430
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200431static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits)
Mark Brown58ba9b22012-01-16 18:38:51 +0000432{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900433 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Takashi Iwaic6068d32014-12-31 17:10:34 +0100434 int ret;
Mark Brown58ba9b22012-01-16 18:38:51 +0000435
436 if (!bits)
437 return;
438
Lars-Peter Clausen0e2a3752014-12-29 18:43:38 +0100439 ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 0, bits);
440 if (ret != 0)
441 dev_warn(rtd->dev, "ASoC: Failed to set MSB %d: %d\n",
442 bits, ret);
Mark Brown58ba9b22012-01-16 18:38:51 +0000443}
444
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200445static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200446{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900447 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800448 struct snd_soc_dai *cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200449 struct snd_soc_dai *codec_dai;
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900450 struct snd_soc_pcm_stream *pcm_codec, *pcm_cpu;
451 int stream = substream->stream;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200452 int i;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800453 unsigned int bits = 0, cpu_bits = 0;
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200454
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900455 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900456 pcm_codec = snd_soc_dai_get_pcm_stream(codec_dai, stream);
457
458 if (pcm_codec->sig_bits == 0) {
459 bits = 0;
460 break;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200461 }
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900462 bits = max(pcm_codec->sig_bits, bits);
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200463 }
464
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900465 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800466 pcm_cpu = snd_soc_dai_get_pcm_stream(cpu_dai, stream);
467
468 if (pcm_cpu->sig_bits == 0) {
469 cpu_bits = 0;
470 break;
471 }
472 cpu_bits = max(pcm_cpu->sig_bits, cpu_bits);
473 }
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900474
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200475 soc_pcm_set_msb(substream, bits);
476 soc_pcm_set_msb(substream, cpu_bits);
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200477}
478
Kuninori Morimotof6c04af2021-02-04 08:50:31 +0900479static void soc_pcm_hw_init(struct snd_pcm_hardware *hw)
480{
481 hw->rates = UINT_MAX;
482 hw->rate_min = 0;
483 hw->rate_max = UINT_MAX;
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900484 hw->channels_min = 0;
485 hw->channels_max = UINT_MAX;
Kuninori Morimotodebc71f2021-02-04 08:52:04 +0900486 hw->formats = ULLONG_MAX;
Kuninori Morimotof6c04af2021-02-04 08:50:31 +0900487}
488
489static void soc_pcm_hw_update_rate(struct snd_pcm_hardware *hw,
490 struct snd_soc_pcm_stream *p)
491{
492 hw->rates = snd_pcm_rate_mask_intersect(hw->rates, p->rates);
493
494 /* setup hw->rate_min/max via hw->rates first */
495 snd_pcm_hw_limit_rates(hw);
496
497 /* update hw->rate_min/max by snd_soc_pcm_stream */
498 hw->rate_min = max(hw->rate_min, p->rate_min);
499 hw->rate_max = min_not_zero(hw->rate_max, p->rate_max);
500}
501
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900502static void soc_pcm_hw_update_chan(struct snd_pcm_hardware *hw,
503 struct snd_soc_pcm_stream *p)
504{
505 hw->channels_min = max(hw->channels_min, p->channels_min);
506 hw->channels_max = min(hw->channels_max, p->channels_max);
507}
508
Kuninori Morimotodebc71f2021-02-04 08:52:04 +0900509static void soc_pcm_hw_update_format(struct snd_pcm_hardware *hw,
510 struct snd_soc_pcm_stream *p)
511{
512 hw->formats &= p->formats;
513}
514
Samuel Holland5854a462020-03-04 23:11:42 -0600515/**
516 * snd_soc_runtime_calc_hw() - Calculate hw limits for a PCM stream
517 * @rtd: ASoC PCM runtime
518 * @hw: PCM hardware parameters (output)
519 * @stream: Direction of the PCM stream
520 *
521 * Calculates the subset of stream parameters supported by all DAIs
522 * associated with the PCM stream.
523 */
524int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd,
525 struct snd_pcm_hardware *hw, int stream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200526{
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000527 struct snd_soc_dai *codec_dai;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800528 struct snd_soc_dai *cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200529 struct snd_soc_pcm_stream *codec_stream;
530 struct snd_soc_pcm_stream *cpu_stream;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800531 unsigned int cpu_chan_min = 0, cpu_chan_max = UINT_MAX;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200532 int i;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100533
Kuninori Morimotof6c04af2021-02-04 08:50:31 +0900534 soc_pcm_hw_init(hw);
535
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800536 /* first calculate min/max only for CPUs in the DAI link */
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900537 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800538
539 /*
540 * Skip CPUs which don't support the current stream type.
541 * Otherwise, since the rate, channel, and format values will
542 * zero in that case, we would have no usable settings left,
543 * causing the resulting setup to fail.
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800544 */
Samuel Holland5854a462020-03-04 23:11:42 -0600545 if (!snd_soc_dai_stream_valid(cpu_dai, stream))
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800546 continue;
547
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800548 cpu_stream = snd_soc_dai_get_pcm_stream(cpu_dai, stream);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100549
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900550 soc_pcm_hw_update_chan(hw, cpu_stream);
Kuninori Morimotof6c04af2021-02-04 08:50:31 +0900551 soc_pcm_hw_update_rate(hw, cpu_stream);
Kuninori Morimotodebc71f2021-02-04 08:52:04 +0900552 soc_pcm_hw_update_format(hw, cpu_stream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800553 }
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900554 cpu_chan_min = hw->channels_min;
555 cpu_chan_max = hw->channels_max;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800556
557 /* second calculate min/max only for CODECs in the DAI link */
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900558 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200559
560 /*
561 * Skip CODECs which don't support the current stream type.
562 * Otherwise, since the rate, channel, and format values will
563 * zero in that case, we would have no usable settings left,
564 * causing the resulting setup to fail.
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200565 */
Kuninori Morimoto25c2f512020-02-27 10:54:38 +0900566 if (!snd_soc_dai_stream_valid(codec_dai, stream))
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200567 continue;
568
Kuninori Morimotoacf253c2020-02-19 15:56:30 +0900569 codec_stream = snd_soc_dai_get_pcm_stream(codec_dai, stream);
570
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900571 soc_pcm_hw_update_chan(hw, codec_stream);
Kuninori Morimotof6c04af2021-02-04 08:50:31 +0900572 soc_pcm_hw_update_rate(hw, codec_stream);
Kuninori Morimotodebc71f2021-02-04 08:52:04 +0900573 soc_pcm_hw_update_format(hw, codec_stream);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200574 }
575
Samuel Holland5854a462020-03-04 23:11:42 -0600576 /* Verify both a valid CPU DAI and a valid CODEC DAI were found */
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900577 if (!hw->channels_min)
Samuel Holland5854a462020-03-04 23:11:42 -0600578 return -EINVAL;
579
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200580 /*
581 * chan min/max cannot be enforced if there are multiple CODEC DAIs
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800582 * connected to CPU DAI(s), use CPU DAI's directly and let
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200583 * channel allocation be fixed up later
584 */
585 if (rtd->num_codecs > 1) {
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900586 hw->channels_min = cpu_chan_min;
587 hw->channels_max = cpu_chan_max;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200588 }
589
Samuel Holland5854a462020-03-04 23:11:42 -0600590 return 0;
591}
592EXPORT_SYMBOL_GPL(snd_soc_runtime_calc_hw);
593
594static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
595{
596 struct snd_pcm_hardware *hw = &substream->runtime->hw;
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900597 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Samuel Holland5854a462020-03-04 23:11:42 -0600598 u64 formats = hw->formats;
599
600 /*
601 * At least one CPU and one CODEC should match. Otherwise, we should
602 * have bailed out on a higher level, since there would be no CPU or
603 * CODEC to support the transfer direction in that case.
604 */
605 snd_soc_runtime_calc_hw(rtd, hw, substream->stream);
606
607 if (formats)
608 hw->formats &= formats;
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200609}
610
Kuninori Morimotodd039072020-02-10 12:14:37 +0900611static int soc_pcm_components_open(struct snd_pcm_substream *substream)
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900612{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900613 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900614 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900615 int i, ret = 0;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900616
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900617 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto51aff912020-09-28 09:01:04 +0900618 ret = snd_soc_component_module_get_when_open(component, substream);
Kuninori Morimotobcae16312020-09-28 09:01:36 +0900619 if (ret < 0)
Kai Vehmanend2aaa8d2020-02-20 11:49:55 +0200620 break;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900621
Kuninori Morimotoae2f4842019-07-26 13:50:01 +0900622 ret = snd_soc_component_open(component, substream);
Kuninori Morimotobcae16312020-09-28 09:01:36 +0900623 if (ret < 0)
Kai Vehmanend2aaa8d2020-02-20 11:49:55 +0200624 break;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900625 }
Kuninori Morimotodd039072020-02-10 12:14:37 +0900626
Kai Vehmanend2aaa8d2020-02-20 11:49:55 +0200627 return ret;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900628}
629
Kuninori Morimoto51aff912020-09-28 09:01:04 +0900630static int soc_pcm_components_close(struct snd_pcm_substream *substream,
631 int rollback)
Charles Keepax244e2932018-06-19 16:22:09 +0100632{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900633 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Charles Keepax244e2932018-06-19 16:22:09 +0100634 struct snd_soc_component *component;
Kuninori Morimotoe82ebff2020-02-10 12:14:26 +0900635 int i, r, ret = 0;
Charles Keepax244e2932018-06-19 16:22:09 +0100636
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900637 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto51aff912020-09-28 09:01:04 +0900638 r = snd_soc_component_close(component, substream, rollback);
Kuninori Morimotoe82ebff2020-02-10 12:14:26 +0900639 if (r < 0)
640 ret = r; /* use last ret */
641
Kuninori Morimoto51aff912020-09-28 09:01:04 +0900642 snd_soc_component_module_put_when_close(component, substream, rollback);
Charles Keepax244e2932018-06-19 16:22:09 +0100643 }
644
Kuninori Morimoto3672beb2019-07-26 13:50:07 +0900645 return ret;
Charles Keepax244e2932018-06-19 16:22:09 +0100646}
647
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900648static int soc_pcm_clean(struct snd_pcm_substream *substream, int rollback)
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900649{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900650 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900651 struct snd_soc_component *component;
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900652 struct snd_soc_dai *dai;
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900653 int i;
654
655 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
656
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900657 if (!rollback)
658 snd_soc_runtime_deactivate(rtd, substream->stream);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900659
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900660 for_each_rtd_dais(rtd, i, dai)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900661 snd_soc_dai_shutdown(dai, substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900662
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900663 snd_soc_link_shutdown(substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900664
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900665 soc_pcm_components_close(substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900666
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900667
668 mutex_unlock(&rtd->card->pcm_mutex);
669
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900670 snd_soc_pcm_component_pm_runtime_put(rtd, substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900671
672 for_each_rtd_components(rtd, i, component)
Kuninori Morimotob3dea622020-05-15 09:46:51 +0900673 if (!snd_soc_component_active(component))
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900674 pinctrl_pm_select_sleep_state(component->dev);
675
676 return 0;
677}
678
679/*
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900680 * Called by ALSA when a PCM substream is closed. Private data can be
681 * freed here. The cpu DAI, codec DAI, machine and components are also
682 * shutdown.
683 */
684static int soc_pcm_close(struct snd_pcm_substream *substream)
685{
686 return soc_pcm_clean(substream, 0);
687}
688
Kuninori Morimotoc3932812021-03-09 10:08:02 +0900689static int soc_hw_sanity_check(struct snd_pcm_substream *substream)
690{
691 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
692 struct snd_pcm_hardware *hw = &substream->runtime->hw;
693 const char *name_cpu = soc_cpu_dai_name(rtd);
694 const char *name_codec = soc_codec_dai_name(rtd);
695 const char *err_msg;
696 struct device *dev = rtd->dev;
697
698 err_msg = "rates";
699 if (!hw->rates)
700 goto config_err;
701
702 err_msg = "formats";
703 if (!hw->formats)
704 goto config_err;
705
706 err_msg = "channels";
707 if (!hw->channels_min || !hw->channels_max ||
708 hw->channels_min > hw->channels_max)
709 goto config_err;
710
711 dev_dbg(dev, "ASoC: %s <-> %s info:\n", name_codec,
712 name_cpu);
713 dev_dbg(dev, "ASoC: rate mask 0x%x\n", hw->rates);
714 dev_dbg(dev, "ASoC: ch min %d max %d\n", hw->channels_min,
715 hw->channels_max);
716 dev_dbg(dev, "ASoC: rate min %d max %d\n", hw->rate_min,
717 hw->rate_max);
718
719 return 0;
720
721config_err:
722 dev_err(dev, "ASoC: %s <-> %s No matching %s\n",
723 name_codec, name_cpu, err_msg);
724 return -EINVAL;
725}
726
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900727/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100728 * Called by ALSA when a PCM substream is opened, the runtime->hw record is
729 * then initialized and any private data can be allocated. This also calls
Charles Keepaxef050be2018-04-24 16:39:02 +0100730 * startup for the cpu DAI, component, machine and codec DAI.
Liam Girdwoodddee6272011-06-09 14:45:53 +0100731 */
732static int soc_pcm_open(struct snd_pcm_substream *substream)
733{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900734 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000735 struct snd_soc_component *component;
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900736 struct snd_soc_dai *dai;
Charles Keepax244e2932018-06-19 16:22:09 +0100737 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100738
Kuninori Morimoto76c39e82020-01-10 11:36:13 +0900739 for_each_rtd_components(rtd, i, component)
740 pinctrl_pm_select_default_state(component->dev);
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000741
Kuninori Morimoto939a5cf2020-09-28 09:01:17 +0900742 ret = snd_soc_pcm_component_pm_runtime_get(rtd, substream);
743 if (ret < 0)
Kuninori Morimotocb2fce92020-10-01 10:32:48 +0900744 goto pm_err;
Mark Brownd6652ef2011-12-03 20:14:31 +0000745
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300746 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100747
Kuninori Morimoto5d9fa032020-02-10 12:14:45 +0900748 ret = soc_pcm_components_open(substream);
749 if (ret < 0)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900750 goto err;
Kuninori Morimoto5d9fa032020-02-10 12:14:45 +0900751
Kuninori Morimoto7cf3c5b2020-05-25 09:57:31 +0900752 ret = snd_soc_link_startup(substream);
Kuninori Morimotoa5e6c102020-05-25 09:57:19 +0900753 if (ret < 0)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900754 goto err;
Kuninori Morimoto5d9fa032020-02-10 12:14:45 +0900755
Liam Girdwoodddee6272011-06-09 14:45:53 +0100756 /* startup the audio subsystem */
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900757 for_each_rtd_dais(rtd, i, dai) {
758 ret = snd_soc_dai_startup(dai, substream);
Kuninori Morimotoce820142020-09-28 09:01:29 +0900759 if (ret < 0)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900760 goto err;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200761
762 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900763 dai->tx_mask = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200764 else
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900765 dai->rx_mask = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100766 }
767
Liam Girdwood01d75842012-04-25 12:12:49 +0100768 /* Dynamic PCM DAI links compat checks use dynamic capabilities */
769 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm)
770 goto dynamic;
771
Liam Girdwoodddee6272011-06-09 14:45:53 +0100772 /* Check that the codec and cpu DAIs are compatible */
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200773 soc_pcm_init_runtime_hw(substream);
774
Kuninori Morimoto68cbc552021-03-09 10:07:57 +0900775 soc_pcm_update_symmetry(substream);
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100776
Kuninori Morimotoc3932812021-03-09 10:08:02 +0900777 ret = soc_hw_sanity_check(substream);
778 if (ret < 0)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900779 goto err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100780
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200781 soc_pcm_apply_msb(substream);
Mark Brown58ba9b22012-01-16 18:38:51 +0000782
Liam Girdwoodddee6272011-06-09 14:45:53 +0100783 /* Symmetry only applies if we've already got an active stream. */
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900784 for_each_rtd_dais(rtd, i, dai) {
Kuninori Morimotof8fc9ec2021-03-09 10:07:42 +0900785 ret = soc_pcm_apply_symmetry(substream, dai);
786 if (ret != 0)
787 goto err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100788 }
Liam Girdwood01d75842012-04-25 12:12:49 +0100789dynamic:
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100790 snd_soc_runtime_activate(rtd, substream->stream);
Kuninori Morimoto8e7875a2020-10-01 14:07:41 +0900791 ret = 0;
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900792err:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300793 mutex_unlock(&rtd->card->pcm_mutex);
Kuninori Morimotocb2fce92020-10-01 10:32:48 +0900794pm_err:
Kuninori Morimotoe4b044f2021-03-15 09:57:37 +0900795 if (ret < 0) {
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900796 soc_pcm_clean(substream, 1);
Kuninori Morimotoe4b044f2021-03-15 09:57:37 +0900797 dev_err(rtd->dev, "%s() failed (%d)", __func__, ret);
798 }
Mark Brownd6652ef2011-12-03 20:14:31 +0000799
Liam Girdwoodddee6272011-06-09 14:45:53 +0100800 return ret;
801}
802
Curtis Malainey4bf2e382019-12-03 09:30:07 -0800803static void codec2codec_close_delayed_work(struct snd_soc_pcm_runtime *rtd)
Jerome Bruneta3420312019-07-25 18:59:47 +0200804{
805 /*
806 * Currently nothing to do for c2c links
807 * Since c2c links are internal nodes in the DAPM graph and
808 * don't interface with the outside world or application layer
809 * we don't have to do any special handling on close.
810 */
811}
812
Liam Girdwoodddee6272011-06-09 14:45:53 +0100813/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100814 * Called by ALSA when the PCM substream is prepared, can set format, sample
815 * rate, etc. This function is non atomic and can be called multiple times,
816 * it can refer to the runtime info.
817 */
818static int soc_pcm_prepare(struct snd_pcm_substream *substream)
819{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900820 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900821 struct snd_soc_dai *dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200822 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100823
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300824 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100825
Kuninori Morimoto7cf3c5b2020-05-25 09:57:31 +0900826 ret = snd_soc_link_prepare(substream);
Kuninori Morimotoa5e6c102020-05-25 09:57:19 +0900827 if (ret < 0)
Kuninori Morimoto44c1a752020-01-22 09:44:44 +0900828 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100829
Kuninori Morimoto4f395142020-06-04 17:06:58 +0900830 ret = snd_soc_pcm_component_prepare(substream);
831 if (ret < 0)
832 goto out;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000833
Kuninori Morimotod108c7f2020-04-24 08:14:53 +0900834 ret = snd_soc_pcm_dai_prepare(substream);
835 if (ret < 0) {
836 dev_err(rtd->dev, "ASoC: DAI prepare error: %d\n", ret);
837 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100838 }
839
840 /* cancel any delayed stream shutdown that is pending */
841 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600842 rtd->pop_wait) {
843 rtd->pop_wait = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100844 cancel_delayed_work(&rtd->delayed_work);
845 }
846
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000847 snd_soc_dapm_stream_event(rtd, substream->stream,
848 SND_SOC_DAPM_STREAM_START);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100849
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900850 for_each_rtd_dais(rtd, i, dai)
851 snd_soc_dai_digital_mute(dai, 0, substream->stream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100852
853out:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300854 mutex_unlock(&rtd->card->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100855 return ret;
856}
857
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200858static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params,
859 unsigned int mask)
860{
861 struct snd_interval *interval;
862 int channels = hweight_long(mask);
863
864 interval = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
865 interval->min = channels;
866 interval->max = channels;
867}
868
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900869static int soc_pcm_hw_clean(struct snd_pcm_substream *substream, int rollback)
Kuninori Morimotoab494362020-09-29 13:31:19 +0900870{
871 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
872 struct snd_soc_dai *dai;
873 int i;
874
875 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
876
877 /* clear the corresponding DAIs parameters when going to be inactive */
878 for_each_rtd_dais(rtd, i, dai) {
879 int active = snd_soc_dai_stream_active(dai, substream->stream);
880
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900881 if (snd_soc_dai_active(dai) == 1)
882 soc_pcm_set_dai_params(dai, NULL);
Kuninori Morimotoab494362020-09-29 13:31:19 +0900883
884 if (active == 1)
885 snd_soc_dai_digital_mute(dai, 1, substream->stream);
886 }
887
Ranjani Sridharana27b4212020-11-17 13:50:01 -0800888 /* run the stream event */
889 snd_soc_dapm_stream_stop(rtd, substream->stream);
890
Kuninori Morimotoab494362020-09-29 13:31:19 +0900891 /* free any machine hw params */
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900892 snd_soc_link_hw_free(substream, rollback);
Kuninori Morimotoab494362020-09-29 13:31:19 +0900893
894 /* free any component resources */
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900895 snd_soc_pcm_component_hw_free(substream, rollback);
Kuninori Morimotoab494362020-09-29 13:31:19 +0900896
897 /* now free hw params for the DAIs */
898 for_each_rtd_dais(rtd, i, dai) {
899 if (!snd_soc_dai_stream_valid(dai, substream->stream))
900 continue;
901
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900902 snd_soc_dai_hw_free(dai, substream, rollback);
Kuninori Morimotoab494362020-09-29 13:31:19 +0900903 }
904
905 mutex_unlock(&rtd->card->pcm_mutex);
906 return 0;
907}
908
909/*
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900910 * Frees resources allocated by hw_params, can be called multiple times
911 */
912static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
913{
914 return soc_pcm_hw_clean(substream, 0);
915}
916
917/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100918 * Called by ALSA when the hardware params are set by application. This
919 * function can also be called multiple times and can allocate buffers
920 * (using snd_pcm_lib_* ). It's non-atomic.
921 */
922static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
923 struct snd_pcm_hw_params *params)
924{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900925 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800926 struct snd_soc_dai *cpu_dai;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000927 struct snd_soc_dai *codec_dai;
Charles Keepax244e2932018-06-19 16:22:09 +0100928 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100929
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300930 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Shengjiu Wang5cca5952019-11-12 18:46:42 +0800931
932 ret = soc_pcm_params_symmetry(substream, params);
933 if (ret)
934 goto out;
935
Kuninori Morimoto7cf3c5b2020-05-25 09:57:31 +0900936 ret = snd_soc_link_hw_params(substream, params);
Kuninori Morimotoa5e6c102020-05-25 09:57:19 +0900937 if (ret < 0)
Kuninori Morimotode9ad992020-01-22 09:44:48 +0900938 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100939
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900940 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200941 struct snd_pcm_hw_params codec_params;
942
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200943 /*
944 * Skip CODECs which don't support the current stream type,
945 * the idea being that if a CODEC is not used for the currently
946 * set up transfer direction, it should not need to be
947 * configured, especially since the configuration used might
948 * not even be supported by that CODEC. There may be cases
949 * however where a CODEC needs to be set up although it is
950 * actually not being used for the transfer, e.g. if a
951 * capture-only CODEC is acting as an LRCLK and/or BCLK master
952 * for the DAI link including a playback-only CODEC.
953 * If this becomes necessary, we will have to augment the
954 * machine driver setup with information on how to act, so
955 * we can do the right thing here.
956 */
957 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
958 continue;
959
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200960 /* copy params for each codec */
961 codec_params = *params;
962
963 /* fixup params based on TDM slot masks */
Rander Wang570f18b2019-03-08 16:38:57 +0800964 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
965 codec_dai->tx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200966 soc_pcm_codec_params_fixup(&codec_params,
967 codec_dai->tx_mask);
Rander Wang570f18b2019-03-08 16:38:57 +0800968
969 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
970 codec_dai->rx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200971 soc_pcm_codec_params_fixup(&codec_params,
972 codec_dai->rx_mask);
973
Kuninori Morimotoaa6166c2019-07-22 10:33:04 +0900974 ret = snd_soc_dai_hw_params(codec_dai, substream,
975 &codec_params);
Benoit Cousson93e69582014-07-08 23:19:38 +0200976 if(ret < 0)
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900977 goto out;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200978
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900979 soc_pcm_set_dai_params(codec_dai, &codec_params);
Charles Keepax078a85f2019-01-31 13:30:18 +0000980 snd_soc_dapm_update_dai(substream, &codec_params, codec_dai);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100981 }
982
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900983 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800984 /*
985 * Skip CPUs which don't support the current stream
986 * type. See soc_pcm_init_runtime_hw() for more details
987 */
988 if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream))
989 continue;
990
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800991 ret = snd_soc_dai_hw_params(cpu_dai, substream, params);
992 if (ret < 0)
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900993 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100994
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800995 /* store the parameters for each DAI */
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900996 soc_pcm_set_dai_params(cpu_dai, params);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800997 snd_soc_dapm_update_dai(substream, params, cpu_dai);
998 }
Kuninori Morimotoca58221d2019-05-13 16:07:43 +0900999
Kuninori Morimoto3a36a642020-09-29 13:31:41 +09001000 ret = snd_soc_pcm_component_hw_params(substream, params);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001001out:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +03001002 mutex_unlock(&rtd->card->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001003
Kuninori Morimotocb11f792021-03-15 09:57:42 +09001004 if (ret < 0) {
Kuninori Morimoto4662c592020-09-29 13:32:01 +09001005 soc_pcm_hw_clean(substream, 1);
Kuninori Morimotocb11f792021-03-15 09:57:42 +09001006 dev_err(rtd->dev, "ASoC: %s() failed (%d)\n", __func__, ret);
1007 }
Kuninori Morimotob8135862017-10-11 01:37:23 +00001008
Liam Girdwoodddee6272011-06-09 14:45:53 +01001009 return ret;
1010}
1011
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001012static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1013{
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001014 int ret = -EINVAL, _ret = 0;
1015 int rollback = 0;
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001016
1017 switch (cmd) {
1018 case SNDRV_PCM_TRIGGER_START:
1019 case SNDRV_PCM_TRIGGER_RESUME:
1020 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001021 ret = snd_soc_link_trigger(substream, cmd, 0);
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001022 if (ret < 0)
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001023 goto start_err;
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001024
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001025 ret = snd_soc_pcm_component_trigger(substream, cmd, 0);
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001026 if (ret < 0)
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001027 goto start_err;
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001028
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001029 ret = snd_soc_pcm_dai_trigger(substream, cmd, 0);
1030start_err:
1031 if (ret < 0)
1032 rollback = 1;
1033 }
1034
1035 if (rollback) {
1036 _ret = ret;
1037 switch (cmd) {
1038 case SNDRV_PCM_TRIGGER_START:
1039 cmd = SNDRV_PCM_TRIGGER_STOP;
1040 break;
1041 case SNDRV_PCM_TRIGGER_RESUME:
1042 cmd = SNDRV_PCM_TRIGGER_SUSPEND;
1043 break;
1044 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1045 cmd = SNDRV_PCM_TRIGGER_PAUSE_PUSH;
1046 break;
1047 }
1048 }
1049
1050 switch (cmd) {
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001051 case SNDRV_PCM_TRIGGER_STOP:
1052 case SNDRV_PCM_TRIGGER_SUSPEND:
1053 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001054 ret = snd_soc_pcm_dai_trigger(substream, cmd, rollback);
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001055 if (ret < 0)
1056 break;
1057
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001058 ret = snd_soc_pcm_component_trigger(substream, cmd, rollback);
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001059 if (ret < 0)
1060 break;
1061
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001062 ret = snd_soc_link_trigger(substream, cmd, rollback);
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001063 break;
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001064 }
1065
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001066 if (_ret)
1067 ret = _ret;
1068
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001069 return ret;
1070}
1071
Liam Girdwoodddee6272011-06-09 14:45:53 +01001072/*
1073 * soc level wrapper for pointer callback
Charles Keepaxef050be2018-04-24 16:39:02 +01001074 * If cpu_dai, codec_dai, component driver has the delay callback, then
Liam Girdwoodddee6272011-06-09 14:45:53 +01001075 * the runtime->delay will be updated accordingly.
1076 */
1077static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
1078{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001079 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001080 struct snd_soc_dai *cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001081 struct snd_soc_dai *codec_dai;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001082 struct snd_pcm_runtime *runtime = substream->runtime;
1083 snd_pcm_uframes_t offset = 0;
1084 snd_pcm_sframes_t delay = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001085 snd_pcm_sframes_t codec_delay = 0;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001086 snd_pcm_sframes_t cpu_delay = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001087 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001088
Akshu Agrawal9fb4c2bf2018-08-01 15:37:33 +05301089 /* clearing the previous total delay */
1090 runtime->delay = 0;
1091
Kuninori Morimoto0035e252019-07-26 13:51:47 +09001092 offset = snd_soc_pcm_component_pointer(substream);
Kuninori Morimotob8135862017-10-11 01:37:23 +00001093
Akshu Agrawal9fb4c2bf2018-08-01 15:37:33 +05301094 /* base delay if assigned in pointer callback */
1095 delay = runtime->delay;
Kuninori Morimotob8135862017-10-11 01:37:23 +00001096
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001097 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001098 cpu_delay = max(cpu_delay,
1099 snd_soc_dai_delay(cpu_dai, substream));
1100 }
1101 delay += cpu_delay;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001102
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001103 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Kuninori Morimoto1dea80d2019-07-22 10:34:09 +09001104 codec_delay = max(codec_delay,
1105 snd_soc_dai_delay(codec_dai, substream));
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001106 }
1107 delay += codec_delay;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001108
Liam Girdwoodddee6272011-06-09 14:45:53 +01001109 runtime->delay = delay;
1110
1111 return offset;
1112}
1113
Liam Girdwood01d75842012-04-25 12:12:49 +01001114/* connect a FE and BE */
1115static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
1116 struct snd_soc_pcm_runtime *be, int stream)
1117{
1118 struct snd_soc_dpcm *dpcm;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001119 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001120
1121 /* only add new dpcms */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001122 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001123 if (dpcm->be == be && dpcm->fe == fe)
1124 return 0;
1125 }
1126
1127 dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_KERNEL);
1128 if (!dpcm)
1129 return -ENOMEM;
1130
1131 dpcm->be = be;
1132 dpcm->fe = fe;
1133 be->dpcm[stream].runtime = fe->dpcm[stream].runtime;
1134 dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001135 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001136 list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients);
1137 list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001138 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001139
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001140 dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001141 stream ? "capture" : "playback", fe->dai_link->name,
1142 stream ? "<-" : "->", be->dai_link->name);
1143
Kuninori Morimoto154dae82020-02-19 15:57:06 +09001144 dpcm_create_debugfs_state(dpcm, stream);
1145
Liam Girdwood01d75842012-04-25 12:12:49 +01001146 return 1;
1147}
1148
1149/* reparent a BE onto another FE */
1150static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
1151 struct snd_soc_pcm_runtime *be, int stream)
1152{
1153 struct snd_soc_dpcm *dpcm;
1154 struct snd_pcm_substream *fe_substream, *be_substream;
1155
1156 /* reparent if BE is connected to other FEs */
1157 if (!be->dpcm[stream].users)
1158 return;
1159
1160 be_substream = snd_soc_dpcm_get_substream(be, stream);
1161
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00001162 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001163 if (dpcm->fe == fe)
1164 continue;
1165
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001166 dev_dbg(fe->dev, "reparent %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001167 stream ? "capture" : "playback",
1168 dpcm->fe->dai_link->name,
1169 stream ? "<-" : "->", dpcm->be->dai_link->name);
1170
1171 fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, stream);
1172 be_substream->runtime = fe_substream->runtime;
1173 break;
1174 }
1175}
1176
1177/* disconnect a BE and FE */
Liam Girdwood23607022014-01-17 17:03:55 +00001178void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001179{
1180 struct snd_soc_dpcm *dpcm, *d;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001181 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001182
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001183 for_each_dpcm_be_safe(fe, stream, dpcm, d) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001184 dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001185 stream ? "capture" : "playback",
1186 dpcm->be->dai_link->name);
1187
1188 if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE)
1189 continue;
1190
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001191 dev_dbg(fe->dev, "freed DSP %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001192 stream ? "capture" : "playback", fe->dai_link->name,
1193 stream ? "<-" : "->", dpcm->be->dai_link->name);
1194
1195 /* BEs still alive need new FE */
1196 dpcm_be_reparent(fe, dpcm->be, stream);
1197
Kuninori Morimoto154dae82020-02-19 15:57:06 +09001198 dpcm_remove_debugfs_state(dpcm);
1199
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001200 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001201 list_del(&dpcm->list_be);
1202 list_del(&dpcm->list_fe);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001203 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001204 kfree(dpcm);
1205 }
1206}
1207
1208/* get BE for DAI widget and stream */
1209static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
1210 struct snd_soc_dapm_widget *widget, int stream)
1211{
1212 struct snd_soc_pcm_runtime *be;
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001213 struct snd_soc_dapm_widget *w;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001214 struct snd_soc_dai *dai;
Mengdong Lin1a497982015-11-18 02:34:11 -05001215 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01001216
Liam Girdwood3c146462018-03-14 20:43:51 +00001217 dev_dbg(card->dev, "ASoC: find BE for widget %s\n", widget->name);
1218
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001219 for_each_card_rtds(card, be) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001220
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001221 if (!be->dai_link->no_pcm)
1222 continue;
Liam Girdwood35ea0652012-06-05 19:26:59 +01001223
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001224 for_each_rtd_dais(be, i, dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001225 w = snd_soc_dai_get_widget(dai, stream);
Liam Girdwood3c146462018-03-14 20:43:51 +00001226
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001227 dev_dbg(card->dev, "ASoC: try BE : %s\n",
1228 w ? w->name : "(not set)");
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001229
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001230 if (w == widget)
1231 return be;
1232 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001233 }
1234
Jerome Brunet9d6ee362020-02-19 12:50:48 +01001235 /* Widget provided is not a BE */
Liam Girdwood01d75842012-04-25 12:12:49 +01001236 return NULL;
1237}
1238
Liam Girdwood01d75842012-04-25 12:12:49 +01001239static int widget_in_list(struct snd_soc_dapm_widget_list *list,
1240 struct snd_soc_dapm_widget *widget)
1241{
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001242 struct snd_soc_dapm_widget *w;
Liam Girdwood01d75842012-04-25 12:12:49 +01001243 int i;
1244
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001245 for_each_dapm_widgets(list, i, w)
1246 if (widget == w)
Liam Girdwood01d75842012-04-25 12:12:49 +01001247 return 1;
Liam Girdwood01d75842012-04-25 12:12:49 +01001248
1249 return 0;
1250}
1251
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001252static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget,
1253 enum snd_soc_dapm_direction dir)
1254{
1255 struct snd_soc_card *card = widget->dapm->card;
1256 struct snd_soc_pcm_runtime *rtd;
Kuninori Morimotoc2cd8212020-02-17 17:27:48 +09001257 int stream;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001258
Kuninori Morimotoc2cd8212020-02-17 17:27:48 +09001259 /* adjust dir to stream */
1260 if (dir == SND_SOC_DAPM_DIR_OUT)
1261 stream = SNDRV_PCM_STREAM_PLAYBACK;
1262 else
1263 stream = SNDRV_PCM_STREAM_CAPTURE;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001264
Kuninori Morimoto027a4832020-02-17 17:27:53 +09001265 rtd = dpcm_get_be(card, widget, stream);
1266 if (rtd)
1267 return true;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001268
1269 return false;
1270}
1271
Liam Girdwood23607022014-01-17 17:03:55 +00001272int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001273 int stream, struct snd_soc_dapm_widget_list **list)
Liam Girdwood01d75842012-04-25 12:12:49 +01001274{
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09001275 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
Liam Girdwood01d75842012-04-25 12:12:49 +01001276 int paths;
1277
Bard Liao6e1276a2020-02-25 21:39:16 +08001278 if (fe->num_cpus > 1) {
1279 dev_err(fe->dev,
1280 "%s doesn't support Multi CPU yet\n", __func__);
1281 return -EINVAL;
1282 }
1283
Liam Girdwood01d75842012-04-25 12:12:49 +01001284 /* get number of valid DAI paths and their widgets */
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001285 paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list,
Sameer Pujaraa293772020-11-02 20:40:09 +05301286 fe->card->component_chaining ?
1287 NULL : dpcm_end_walk_at_be);
Liam Girdwood01d75842012-04-25 12:12:49 +01001288
Liam Girdwood103d84a2012-11-19 14:39:15 +00001289 dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths,
Liam Girdwood01d75842012-04-25 12:12:49 +01001290 stream ? "capture" : "playback");
1291
Liam Girdwood01d75842012-04-25 12:12:49 +01001292 return paths;
1293}
1294
Kuninori Morimoto52645e332020-02-19 15:56:52 +09001295void dpcm_path_put(struct snd_soc_dapm_widget_list **list)
1296{
1297 snd_soc_dapm_dai_free_widgets(list);
1298}
1299
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001300static bool dpcm_be_is_active(struct snd_soc_dpcm *dpcm, int stream,
1301 struct snd_soc_dapm_widget_list *list)
Liam Girdwood01d75842012-04-25 12:12:49 +01001302{
Liam Girdwood01d75842012-04-25 12:12:49 +01001303 struct snd_soc_dapm_widget *widget;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001304 struct snd_soc_dai *dai;
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001305 unsigned int i;
1306
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001307 /* is there a valid DAI widget for this BE */
1308 for_each_rtd_dais(dpcm->be, i, dai) {
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001309 widget = snd_soc_dai_get_widget(dai, stream);
1310
1311 /*
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001312 * The BE is pruned only if none of the dai
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001313 * widgets are in the active list.
1314 */
1315 if (widget && widget_in_list(list, widget))
1316 return true;
1317 }
1318
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001319 return false;
1320}
1321
1322static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
1323 struct snd_soc_dapm_widget_list **list_)
1324{
1325 struct snd_soc_dpcm *dpcm;
Liam Girdwood01d75842012-04-25 12:12:49 +01001326 int prune = 0;
1327
1328 /* Destroy any old FE <--> BE connections */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001329 for_each_dpcm_be(fe, stream, dpcm) {
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001330 if (dpcm_be_is_active(dpcm, stream, *list_))
Kuninori Morimotobed646d2019-10-15 12:59:38 +09001331 continue;
Liam Girdwood01d75842012-04-25 12:12:49 +01001332
Liam Girdwood103d84a2012-11-19 14:39:15 +00001333 dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001334 stream ? "capture" : "playback",
1335 dpcm->be->dai_link->name, fe->dai_link->name);
1336 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
Kuninori Morimotoa7e204442020-12-11 14:55:22 +09001337 dpcm_set_be_update_state(dpcm->be, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001338 prune++;
1339 }
1340
Liam Girdwood103d84a2012-11-19 14:39:15 +00001341 dev_dbg(fe->dev, "ASoC: found %d old BE paths for pruning\n", prune);
Liam Girdwood01d75842012-04-25 12:12:49 +01001342 return prune;
1343}
1344
1345static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
1346 struct snd_soc_dapm_widget_list **list_)
1347{
1348 struct snd_soc_card *card = fe->card;
1349 struct snd_soc_dapm_widget_list *list = *list_;
1350 struct snd_soc_pcm_runtime *be;
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001351 struct snd_soc_dapm_widget *widget;
Liam Girdwood01d75842012-04-25 12:12:49 +01001352 int i, new = 0, err;
1353
1354 /* Create any new FE <--> BE connections */
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001355 for_each_dapm_widgets(list, i, widget) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001356
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001357 switch (widget->id) {
Mark Brown46162742013-06-05 19:36:11 +01001358 case snd_soc_dapm_dai_in:
Koro Chenc5b85402015-07-06 10:02:10 +08001359 if (stream != SNDRV_PCM_STREAM_PLAYBACK)
1360 continue;
1361 break;
Mark Brown46162742013-06-05 19:36:11 +01001362 case snd_soc_dapm_dai_out:
Koro Chenc5b85402015-07-06 10:02:10 +08001363 if (stream != SNDRV_PCM_STREAM_CAPTURE)
1364 continue;
Mark Brown46162742013-06-05 19:36:11 +01001365 break;
1366 default:
Liam Girdwood01d75842012-04-25 12:12:49 +01001367 continue;
Mark Brown46162742013-06-05 19:36:11 +01001368 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001369
1370 /* is there a valid BE rtd for this widget */
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001371 be = dpcm_get_be(card, widget, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001372 if (!be) {
Shengjiu Wangb6eabd22021-02-08 16:12:45 +08001373 dev_dbg(fe->dev, "ASoC: no BE found for %s\n",
1374 widget->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001375 continue;
1376 }
1377
Liam Girdwood01d75842012-04-25 12:12:49 +01001378 /* don't connect if FE is not running */
Liam Girdwood23607022014-01-17 17:03:55 +00001379 if (!fe->dpcm[stream].runtime && !fe->fe_compr)
Liam Girdwood01d75842012-04-25 12:12:49 +01001380 continue;
1381
1382 /* newly connected FE and BE */
1383 err = dpcm_be_connect(fe, be, stream);
1384 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001385 dev_err(fe->dev, "ASoC: can't connect %s\n",
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001386 widget->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001387 break;
1388 } else if (err == 0) /* already connected */
1389 continue;
1390
1391 /* new */
Kuninori Morimotoa7e204442020-12-11 14:55:22 +09001392 dpcm_set_be_update_state(be, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001393 new++;
1394 }
1395
Liam Girdwood103d84a2012-11-19 14:39:15 +00001396 dev_dbg(fe->dev, "ASoC: found %d new BE paths\n", new);
Liam Girdwood01d75842012-04-25 12:12:49 +01001397 return new;
1398}
1399
1400/*
1401 * Find the corresponding BE DAIs that source or sink audio to this
1402 * FE substream.
1403 */
Liam Girdwood23607022014-01-17 17:03:55 +00001404int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
Liam Girdwood01d75842012-04-25 12:12:49 +01001405 int stream, struct snd_soc_dapm_widget_list **list, int new)
1406{
1407 if (new)
1408 return dpcm_add_paths(fe, stream, list);
1409 else
1410 return dpcm_prune_paths(fe, stream, list);
1411}
1412
Liam Girdwood23607022014-01-17 17:03:55 +00001413void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001414{
1415 struct snd_soc_dpcm *dpcm;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001416 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001417
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001418 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001419 for_each_dpcm_be(fe, stream, dpcm)
Kuninori Morimotoa7e204442020-12-11 14:55:22 +09001420 dpcm_set_be_update_state(dpcm->be, stream, SND_SOC_DPCM_UPDATE_NO);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001421 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001422}
1423
Kuninori Morimoto531590b2021-03-09 10:08:17 +09001424void dpcm_be_dai_stop(struct snd_soc_pcm_runtime *fe, int stream,
1425 int do_hw_free, struct snd_soc_dpcm *last)
Liam Girdwood01d75842012-04-25 12:12:49 +01001426{
1427 struct snd_soc_dpcm *dpcm;
1428
1429 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001430 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001431 struct snd_soc_pcm_runtime *be = dpcm->be;
1432 struct snd_pcm_substream *be_substream =
1433 snd_soc_dpcm_get_substream(be, stream);
1434
Kuninori Morimoto531590b2021-03-09 10:08:17 +09001435 if (dpcm == last)
1436 return;
1437
1438 /* is this op for this BE ? */
1439 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1440 continue;
1441
Kuninori Morimoto1db19c12021-03-09 10:08:08 +09001442 if (be->dpcm[stream].users == 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001443 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001444 stream ? "capture" : "playback",
1445 be->dpcm[stream].state);
Kuninori Morimoto1db19c12021-03-09 10:08:08 +09001446 continue;
1447 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001448
1449 if (--be->dpcm[stream].users != 0)
1450 continue;
1451
Kuninori Morimoto531590b2021-03-09 10:08:17 +09001452 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) {
1453 if (!do_hw_free)
1454 continue;
1455
1456 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) {
1457 soc_pcm_hw_free(be_substream);
1458 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1459 }
1460 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001461
1462 soc_pcm_close(be_substream);
1463 be_substream->runtime = NULL;
1464 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1465 }
1466}
1467
Liam Girdwood23607022014-01-17 17:03:55 +00001468int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001469{
1470 struct snd_soc_dpcm *dpcm;
1471 int err, count = 0;
1472
1473 /* only startup BE DAIs that are either sinks or sources to this FE DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001474 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001475
1476 struct snd_soc_pcm_runtime *be = dpcm->be;
1477 struct snd_pcm_substream *be_substream =
1478 snd_soc_dpcm_get_substream(be, stream);
1479
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001480 if (!be_substream) {
1481 dev_err(be->dev, "ASoC: no backend %s stream\n",
1482 stream ? "capture" : "playback");
1483 continue;
1484 }
1485
Liam Girdwood01d75842012-04-25 12:12:49 +01001486 /* is this op for this BE ? */
1487 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1488 continue;
1489
1490 /* first time the dpcm is open ? */
Kuninori Morimoto1db19c12021-03-09 10:08:08 +09001491 if (be->dpcm[stream].users == DPCM_MAX_BE_USERS) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001492 dev_err(be->dev, "ASoC: too many users %s at open %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001493 stream ? "capture" : "playback",
1494 be->dpcm[stream].state);
Kuninori Morimoto1db19c12021-03-09 10:08:08 +09001495 continue;
1496 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001497
1498 if (be->dpcm[stream].users++ != 0)
1499 continue;
1500
1501 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
1502 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
1503 continue;
1504
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001505 dev_dbg(be->dev, "ASoC: open %s BE %s\n",
1506 stream ? "capture" : "playback", be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001507
1508 be_substream->runtime = be->dpcm[stream].runtime;
1509 err = soc_pcm_open(be_substream);
1510 if (err < 0) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001511 be->dpcm[stream].users--;
1512 if (be->dpcm[stream].users < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001513 dev_err(be->dev, "ASoC: no users %s at unwind %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001514 stream ? "capture" : "playback",
1515 be->dpcm[stream].state);
1516
1517 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1518 goto unwind;
1519 }
1520
1521 be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1522 count++;
1523 }
1524
1525 return count;
1526
1527unwind:
Kuninori Morimoto531590b2021-03-09 10:08:17 +09001528 dpcm_be_dai_startup_rollback(fe, stream, dpcm);
Liam Girdwood01d75842012-04-25 12:12:49 +01001529
1530 return err;
1531}
1532
Kuninori Morimoto5f538982021-02-22 09:47:26 +09001533static void dpcm_runtime_setup_fe(struct snd_pcm_substream *substream)
1534{
1535 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
1536 struct snd_pcm_runtime *runtime = substream->runtime;
1537 struct snd_pcm_hardware *hw = &runtime->hw;
1538 struct snd_soc_dai *dai;
1539 int stream = substream->stream;
1540 int i;
1541
1542 soc_pcm_hw_init(hw);
1543
1544 for_each_rtd_cpu_dais(fe, i, dai) {
1545 struct snd_soc_pcm_stream *cpu_stream;
1546
1547 /*
1548 * Skip CPUs which don't support the current stream
1549 * type. See soc_pcm_init_runtime_hw() for more details
1550 */
1551 if (!snd_soc_dai_stream_valid(dai, stream))
1552 continue;
1553
1554 cpu_stream = snd_soc_dai_get_pcm_stream(dai, stream);
1555
1556 soc_pcm_hw_update_rate(hw, cpu_stream);
1557 soc_pcm_hw_update_chan(hw, cpu_stream);
1558 soc_pcm_hw_update_format(hw, cpu_stream);
1559 }
1560
1561}
1562
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001563static void dpcm_runtime_setup_be_format(struct snd_pcm_substream *substream)
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001564{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001565 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001566 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto4b260f42021-01-22 10:13:48 +09001567 struct snd_pcm_hardware *hw = &runtime->hw;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001568 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001569 struct snd_soc_dai *dai;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001570 int stream = substream->stream;
1571
1572 if (!fe->dai_link->dpcm_merged_format)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001573 return;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001574
1575 /*
1576 * It returns merged BE codec format
1577 * if FE want to use it (= dpcm_merged_format)
1578 */
1579
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001580 for_each_dpcm_be(fe, stream, dpcm) {
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001581 struct snd_soc_pcm_runtime *be = dpcm->be;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001582 struct snd_soc_pcm_stream *codec_stream;
1583 int i;
1584
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001585 for_each_rtd_codec_dais(be, i, dai) {
Jerome Brunet4febced2018-06-27 17:36:38 +02001586 /*
1587 * Skip CODECs which don't support the current stream
1588 * type. See soc_pcm_init_runtime_hw() for more details
1589 */
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001590 if (!snd_soc_dai_stream_valid(dai, stream))
Jerome Brunet4febced2018-06-27 17:36:38 +02001591 continue;
1592
Kuninori Morimotoacf253c2020-02-19 15:56:30 +09001593 codec_stream = snd_soc_dai_get_pcm_stream(dai, stream);
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001594
Kuninori Morimotodebc71f2021-02-04 08:52:04 +09001595 soc_pcm_hw_update_format(hw, codec_stream);
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001596 }
1597 }
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001598}
1599
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001600static void dpcm_runtime_setup_be_chan(struct snd_pcm_substream *substream)
Jiada Wangf4c277b2018-06-20 18:25:20 +09001601{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001602 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001603 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto4b260f42021-01-22 10:13:48 +09001604 struct snd_pcm_hardware *hw = &runtime->hw;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001605 struct snd_soc_dpcm *dpcm;
1606 int stream = substream->stream;
1607
1608 if (!fe->dai_link->dpcm_merged_chan)
1609 return;
1610
Jiada Wangf4c277b2018-06-20 18:25:20 +09001611 /*
1612 * It returns merged BE codec channel;
1613 * if FE want to use it (= dpcm_merged_chan)
1614 */
1615
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001616 for_each_dpcm_be(fe, stream, dpcm) {
Jiada Wangf4c277b2018-06-20 18:25:20 +09001617 struct snd_soc_pcm_runtime *be = dpcm->be;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001618 struct snd_soc_pcm_stream *codec_stream;
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001619 struct snd_soc_pcm_stream *cpu_stream;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001620 struct snd_soc_dai *dai;
1621 int i;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001622
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001623 for_each_rtd_cpu_dais(be, i, dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001624 /*
1625 * Skip CPUs which don't support the current stream
1626 * type. See soc_pcm_init_runtime_hw() for more details
1627 */
1628 if (!snd_soc_dai_stream_valid(dai, stream))
1629 continue;
1630
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001631 cpu_stream = snd_soc_dai_get_pcm_stream(dai, stream);
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001632
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +09001633 soc_pcm_hw_update_chan(hw, cpu_stream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001634 }
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001635
1636 /*
1637 * chan min/max cannot be enforced if there are multiple CODEC
1638 * DAIs connected to a single CPU DAI, use CPU DAI's directly
1639 */
1640 if (be->num_codecs == 1) {
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09001641 codec_stream = snd_soc_dai_get_pcm_stream(asoc_rtd_to_codec(be, 0), stream);
Jiada Wangf4c277b2018-06-20 18:25:20 +09001642
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +09001643 soc_pcm_hw_update_chan(hw, codec_stream);
Jiada Wangf4c277b2018-06-20 18:25:20 +09001644 }
1645 }
1646}
1647
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001648static void dpcm_runtime_setup_be_rate(struct snd_pcm_substream *substream)
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001649{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001650 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001651 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto4b260f42021-01-22 10:13:48 +09001652 struct snd_pcm_hardware *hw = &runtime->hw;
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001653 struct snd_soc_dpcm *dpcm;
1654 int stream = substream->stream;
1655
1656 if (!fe->dai_link->dpcm_merged_rate)
1657 return;
1658
1659 /*
1660 * It returns merged BE codec channel;
1661 * if FE want to use it (= dpcm_merged_chan)
1662 */
1663
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001664 for_each_dpcm_be(fe, stream, dpcm) {
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001665 struct snd_soc_pcm_runtime *be = dpcm->be;
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001666 struct snd_soc_pcm_stream *pcm;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001667 struct snd_soc_dai *dai;
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001668 int i;
1669
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001670 for_each_rtd_dais(be, i, dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001671 /*
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001672 * Skip DAIs which don't support the current stream
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001673 * type. See soc_pcm_init_runtime_hw() for more details
1674 */
1675 if (!snd_soc_dai_stream_valid(dai, stream))
1676 continue;
1677
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001678 pcm = snd_soc_dai_get_pcm_stream(dai, stream);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001679
Kuninori Morimotof6c04af2021-02-04 08:50:31 +09001680 soc_pcm_hw_update_rate(hw, pcm);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001681 }
1682 }
1683}
1684
PC Liao906c7d62015-12-11 11:33:51 +08001685static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
1686 int stream)
1687{
1688 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001689 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001690 struct snd_soc_dai *fe_cpu_dai;
PC Liao906c7d62015-12-11 11:33:51 +08001691 int err;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001692 int i;
PC Liao906c7d62015-12-11 11:33:51 +08001693
1694 /* apply symmetry for FE */
Kuninori Morimoto68cbc552021-03-09 10:07:57 +09001695 soc_pcm_update_symmetry(fe_substream);
PC Liao906c7d62015-12-11 11:33:51 +08001696
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001697 for_each_rtd_cpu_dais (fe, i, fe_cpu_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001698 /* Symmetry only applies if we've got an active stream. */
Kuninori Morimotof8fc9ec2021-03-09 10:07:42 +09001699 err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai);
1700 if (err < 0)
1701 return err;
PC Liao906c7d62015-12-11 11:33:51 +08001702 }
1703
1704 /* apply symmetry for BE */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001705 for_each_dpcm_be(fe, stream, dpcm) {
PC Liao906c7d62015-12-11 11:33:51 +08001706 struct snd_soc_pcm_runtime *be = dpcm->be;
1707 struct snd_pcm_substream *be_substream =
1708 snd_soc_dpcm_get_substream(be, stream);
Jerome Brunet6246f282019-04-01 15:03:54 +02001709 struct snd_soc_pcm_runtime *rtd;
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001710 struct snd_soc_dai *dai;
PC Liao906c7d62015-12-11 11:33:51 +08001711
Jerome Brunet6246f282019-04-01 15:03:54 +02001712 /* A backend may not have the requested substream */
1713 if (!be_substream)
1714 continue;
1715
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001716 rtd = asoc_substream_to_rtd(be_substream);
Jeeja KPf1176612016-09-06 14:17:55 +05301717 if (rtd->dai_link->be_hw_params_fixup)
1718 continue;
1719
Kuninori Morimoto68cbc552021-03-09 10:07:57 +09001720 soc_pcm_update_symmetry(be_substream);
PC Liao906c7d62015-12-11 11:33:51 +08001721
1722 /* Symmetry only applies if we've got an active stream. */
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001723 for_each_rtd_dais(rtd, i, dai) {
Kuninori Morimotof8fc9ec2021-03-09 10:07:42 +09001724 err = soc_pcm_apply_symmetry(fe_substream, dai);
1725 if (err < 0)
1726 return err;
PC Liao906c7d62015-12-11 11:33:51 +08001727 }
1728 }
1729
1730 return 0;
1731}
1732
Liam Girdwood01d75842012-04-25 12:12:49 +01001733static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
1734{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001735 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001736 int stream = fe_substream->stream, ret = 0;
1737
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001738 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001739
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09001740 ret = dpcm_be_dai_startup(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001741 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001742 dev_err(fe->dev,"ASoC: failed to start some BEs %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001743 goto be_err;
1744 }
1745
Liam Girdwood103d84a2012-11-19 14:39:15 +00001746 dev_dbg(fe->dev, "ASoC: open FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001747
1748 /* start the DAI frontend */
1749 ret = soc_pcm_open(fe_substream);
Kuninori Morimotoe4b044f2021-03-15 09:57:37 +09001750 if (ret < 0)
Liam Girdwood01d75842012-04-25 12:12:49 +01001751 goto unwind;
Liam Girdwood01d75842012-04-25 12:12:49 +01001752
1753 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1754
Kuninori Morimoto4fe28462021-02-22 09:47:36 +09001755 dpcm_runtime_setup_fe(fe_substream);
1756
1757 dpcm_runtime_setup_be_format(fe_substream);
1758 dpcm_runtime_setup_be_chan(fe_substream);
1759 dpcm_runtime_setup_be_rate(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001760
PC Liao906c7d62015-12-11 11:33:51 +08001761 ret = dpcm_apply_symmetry(fe_substream, stream);
Kuninori Morimoto8a01fbf2020-03-06 10:09:59 +09001762 if (ret < 0)
PC Liao906c7d62015-12-11 11:33:51 +08001763 dev_err(fe->dev, "ASoC: failed to apply dpcm symmetry %d\n",
1764 ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001765
1766unwind:
Kuninori Morimoto8a01fbf2020-03-06 10:09:59 +09001767 if (ret < 0)
1768 dpcm_be_dai_startup_unwind(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001769be_err:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001770 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001771 return ret;
1772}
1773
Liam Girdwood01d75842012-04-25 12:12:49 +01001774static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
1775{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001776 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001777 int stream = substream->stream;
1778
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001779 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001780
1781 /* shutdown the BEs */
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09001782 dpcm_be_dai_shutdown(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001783
Liam Girdwood103d84a2012-11-19 14:39:15 +00001784 dev_dbg(fe->dev, "ASoC: close FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001785
1786 /* now shutdown the frontend */
1787 soc_pcm_close(substream);
1788
Ranjani Sridharanbb9dd3c2020-12-02 11:33:43 -08001789 /* run the stream stop event */
1790 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
1791
Liam Girdwood01d75842012-04-25 12:12:49 +01001792 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001793 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001794 return 0;
1795}
1796
Liam Girdwood23607022014-01-17 17:03:55 +00001797int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001798{
1799 struct snd_soc_dpcm *dpcm;
1800
1801 /* only hw_params backends that are either sinks or sources
1802 * to this frontend DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001803 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001804
1805 struct snd_soc_pcm_runtime *be = dpcm->be;
1806 struct snd_pcm_substream *be_substream =
1807 snd_soc_dpcm_get_substream(be, stream);
1808
1809 /* is this op for this BE ? */
1810 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1811 continue;
1812
1813 /* only free hw when no longer used - check all FEs */
1814 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1815 continue;
1816
Qiao Zhou36fba622014-12-03 10:13:43 +08001817 /* do not free hw if this BE is used by other FE */
1818 if (be->dpcm[stream].users > 1)
1819 continue;
1820
Liam Girdwood01d75842012-04-25 12:12:49 +01001821 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1822 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
1823 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Patrick Lai08b27842012-12-19 19:36:02 -08001824 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
Vinod Koul5e82d2b2016-02-01 22:26:40 +05301825 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
1826 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
Liam Girdwood01d75842012-04-25 12:12:49 +01001827 continue;
1828
Liam Girdwood103d84a2012-11-19 14:39:15 +00001829 dev_dbg(be->dev, "ASoC: hw_free BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001830 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001831
1832 soc_pcm_hw_free(be_substream);
1833
1834 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1835 }
1836
1837 return 0;
1838}
1839
Mark Brown45c0a182012-05-09 21:46:27 +01001840static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001841{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001842 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001843 int err, stream = substream->stream;
1844
1845 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001846 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001847
Liam Girdwood103d84a2012-11-19 14:39:15 +00001848 dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001849
1850 /* call hw_free on the frontend */
1851 err = soc_pcm_hw_free(substream);
1852 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001853 dev_err(fe->dev,"ASoC: hw_free FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001854 fe->dai_link->name);
1855
1856 /* only hw_params backends that are either sinks or sources
1857 * to this frontend DAI */
1858 err = dpcm_be_dai_hw_free(fe, stream);
Pierre-Louis Bossart61456212021-02-18 16:19:19 -06001859 if (err < 0)
1860 dev_err(fe->dev, "ASoC: hw_free BE failed %d\n", err);
Liam Girdwood01d75842012-04-25 12:12:49 +01001861
1862 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001863 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001864
1865 mutex_unlock(&fe->card->mutex);
1866 return 0;
1867}
1868
Liam Girdwood23607022014-01-17 17:03:55 +00001869int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001870{
1871 struct snd_soc_dpcm *dpcm;
1872 int ret;
1873
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001874 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001875
1876 struct snd_soc_pcm_runtime *be = dpcm->be;
1877 struct snd_pcm_substream *be_substream =
1878 snd_soc_dpcm_get_substream(be, stream);
1879
1880 /* is this op for this BE ? */
1881 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1882 continue;
1883
Liam Girdwood01d75842012-04-25 12:12:49 +01001884 /* copy params for each dpcm */
1885 memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params,
1886 sizeof(struct snd_pcm_hw_params));
1887
1888 /* perform any hw_params fixups */
Kuninori Morimoto0cbbf8a2020-05-25 09:57:36 +09001889 ret = snd_soc_link_be_hw_params_fixup(be, &dpcm->hw_params);
1890 if (ret < 0)
1891 goto unwind;
Liam Girdwood01d75842012-04-25 12:12:49 +01001892
Libin Yangae061d22019-04-19 09:53:12 +08001893 /* copy the fixed-up hw params for BE dai */
1894 memcpy(&be->dpcm[stream].hw_params, &dpcm->hw_params,
1895 sizeof(struct snd_pcm_hw_params));
1896
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00001897 /* only allow hw_params() if no connected FEs are running */
1898 if (!snd_soc_dpcm_can_be_params(fe, be, stream))
1899 continue;
1900
1901 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
1902 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1903 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE))
1904 continue;
1905
1906 dev_dbg(be->dev, "ASoC: hw_params BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001907 be->dai_link->name);
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00001908
Liam Girdwood01d75842012-04-25 12:12:49 +01001909 ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params);
Kuninori Morimotocb11f792021-03-15 09:57:42 +09001910 if (ret < 0)
Liam Girdwood01d75842012-04-25 12:12:49 +01001911 goto unwind;
Liam Girdwood01d75842012-04-25 12:12:49 +01001912
1913 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
1914 }
1915 return 0;
1916
1917unwind:
1918 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001919 for_each_dpcm_be_rollback(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001920 struct snd_soc_pcm_runtime *be = dpcm->be;
1921 struct snd_pcm_substream *be_substream =
1922 snd_soc_dpcm_get_substream(be, stream);
1923
1924 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1925 continue;
1926
1927 /* only allow hw_free() if no connected FEs are running */
1928 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1929 continue;
1930
1931 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
1932 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1933 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
1934 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
1935 continue;
1936
1937 soc_pcm_hw_free(be_substream);
1938 }
1939
1940 return ret;
1941}
1942
Mark Brown45c0a182012-05-09 21:46:27 +01001943static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
1944 struct snd_pcm_hw_params *params)
Liam Girdwood01d75842012-04-25 12:12:49 +01001945{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001946 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001947 int ret, stream = substream->stream;
1948
1949 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001950 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001951
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09001952 memcpy(&fe->dpcm[stream].hw_params, params,
Liam Girdwood01d75842012-04-25 12:12:49 +01001953 sizeof(struct snd_pcm_hw_params));
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09001954 ret = dpcm_be_dai_hw_params(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001955 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001956 dev_err(fe->dev,"ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001957 goto out;
1958 }
1959
Liam Girdwood103d84a2012-11-19 14:39:15 +00001960 dev_dbg(fe->dev, "ASoC: hw_params FE %s rate %d chan %x fmt %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001961 fe->dai_link->name, params_rate(params),
1962 params_channels(params), params_format(params));
1963
1964 /* call hw_params on the frontend */
1965 ret = soc_pcm_hw_params(substream, params);
Kuninori Morimotocb11f792021-03-15 09:57:42 +09001966 if (ret < 0)
Liam Girdwood01d75842012-04-25 12:12:49 +01001967 dpcm_be_dai_hw_free(fe, stream);
Kuninori Morimotocb11f792021-03-15 09:57:42 +09001968 else
Liam Girdwood01d75842012-04-25 12:12:49 +01001969 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
1970
1971out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001972 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001973 mutex_unlock(&fe->card->mutex);
1974 return ret;
1975}
1976
Liam Girdwood23607022014-01-17 17:03:55 +00001977int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
Mark Brown45c0a182012-05-09 21:46:27 +01001978 int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01001979{
1980 struct snd_soc_dpcm *dpcm;
1981 int ret = 0;
1982
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001983 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001984
1985 struct snd_soc_pcm_runtime *be = dpcm->be;
1986 struct snd_pcm_substream *be_substream =
1987 snd_soc_dpcm_get_substream(be, stream);
1988
1989 /* is this op for this BE ? */
1990 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1991 continue;
1992
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09001993 dev_dbg(be->dev, "ASoC: trigger BE %s cmd %d\n",
1994 be->dai_link->name, cmd);
1995
Liam Girdwood01d75842012-04-25 12:12:49 +01001996 switch (cmd) {
1997 case SNDRV_PCM_TRIGGER_START:
1998 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
이경택21fca8b2020-04-01 10:04:21 +09001999 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
2000 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Liam Girdwood01d75842012-04-25 12:12:49 +01002001 continue;
2002
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002003 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002004 if (ret)
2005 return ret;
2006
2007 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2008 break;
2009 case SNDRV_PCM_TRIGGER_RESUME:
2010 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
2011 continue;
2012
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002013 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002014 if (ret)
2015 return ret;
2016
2017 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2018 break;
2019 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2020 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
2021 continue;
2022
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002023 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002024 if (ret)
2025 return ret;
2026
2027 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2028 break;
2029 case SNDRV_PCM_TRIGGER_STOP:
이경택21fca8b2020-04-01 10:04:21 +09002030 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) &&
2031 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Liam Girdwood01d75842012-04-25 12:12:49 +01002032 continue;
2033
2034 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2035 continue;
2036
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002037 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002038 if (ret)
2039 return ret;
2040
2041 be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2042 break;
2043 case SNDRV_PCM_TRIGGER_SUSPEND:
Nicolin Chen868a6ca2014-05-12 20:12:05 +08002044 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
Liam Girdwood01d75842012-04-25 12:12:49 +01002045 continue;
2046
2047 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2048 continue;
2049
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002050 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002051 if (ret)
2052 return ret;
2053
2054 be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND;
2055 break;
2056 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2057 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2058 continue;
2059
2060 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2061 continue;
2062
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002063 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002064 if (ret)
2065 return ret;
2066
2067 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2068 break;
2069 }
2070 }
2071
2072 return ret;
2073}
2074EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
2075
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002076static int dpcm_dai_trigger_fe_be(struct snd_pcm_substream *substream,
2077 int cmd, bool fe_first)
2078{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002079 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002080 int ret;
2081
2082 /* call trigger on the frontend before the backend. */
2083 if (fe_first) {
2084 dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n",
2085 fe->dai_link->name, cmd);
2086
2087 ret = soc_pcm_trigger(substream, cmd);
2088 if (ret < 0)
2089 return ret;
2090
2091 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2092 return ret;
2093 }
2094
2095 /* call trigger on the frontend after the backend. */
2096 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2097 if (ret < 0)
2098 return ret;
2099
2100 dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n",
2101 fe->dai_link->name, cmd);
2102
2103 ret = soc_pcm_trigger(substream, cmd);
2104
2105 return ret;
2106}
2107
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002108static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002109{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002110 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002111 int stream = substream->stream;
2112 int ret = 0;
Liam Girdwood01d75842012-04-25 12:12:49 +01002113 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
2114
2115 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
2116
2117 switch (trigger) {
2118 case SND_SOC_DPCM_TRIGGER_PRE:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002119 switch (cmd) {
2120 case SNDRV_PCM_TRIGGER_START:
2121 case SNDRV_PCM_TRIGGER_RESUME:
2122 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Cezary Rojewski4c22b802020-10-26 11:01:29 +01002123 case SNDRV_PCM_TRIGGER_DRAIN:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002124 ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
2125 break;
2126 case SNDRV_PCM_TRIGGER_STOP:
2127 case SNDRV_PCM_TRIGGER_SUSPEND:
2128 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2129 ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
2130 break;
2131 default:
2132 ret = -EINVAL;
2133 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002134 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002135 break;
2136 case SND_SOC_DPCM_TRIGGER_POST:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002137 switch (cmd) {
2138 case SNDRV_PCM_TRIGGER_START:
2139 case SNDRV_PCM_TRIGGER_RESUME:
2140 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Cezary Rojewski4c22b802020-10-26 11:01:29 +01002141 case SNDRV_PCM_TRIGGER_DRAIN:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002142 ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
2143 break;
2144 case SNDRV_PCM_TRIGGER_STOP:
2145 case SNDRV_PCM_TRIGGER_SUSPEND:
2146 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2147 ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
2148 break;
2149 default:
2150 ret = -EINVAL;
2151 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002152 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002153 break;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002154 case SND_SOC_DPCM_TRIGGER_BESPOKE:
2155 /* bespoke trigger() - handles both FE and BEs */
2156
Liam Girdwood103d84a2012-11-19 14:39:15 +00002157 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd %d\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002158 fe->dai_link->name, cmd);
2159
Kuninori Morimoto308193582020-04-24 08:15:09 +09002160 ret = snd_soc_pcm_dai_bespoke_trigger(substream, cmd);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002161 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002162 default:
Liam Girdwood103d84a2012-11-19 14:39:15 +00002163 dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd,
Liam Girdwood01d75842012-04-25 12:12:49 +01002164 fe->dai_link->name);
2165 ret = -EINVAL;
2166 goto out;
2167 }
2168
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002169 if (ret < 0) {
2170 dev_err(fe->dev, "ASoC: trigger FE cmd: %d failed: %d\n",
2171 cmd, ret);
2172 goto out;
2173 }
2174
Liam Girdwood01d75842012-04-25 12:12:49 +01002175 switch (cmd) {
2176 case SNDRV_PCM_TRIGGER_START:
2177 case SNDRV_PCM_TRIGGER_RESUME:
2178 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2179 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2180 break;
2181 case SNDRV_PCM_TRIGGER_STOP:
2182 case SNDRV_PCM_TRIGGER_SUSPEND:
Liam Girdwood01d75842012-04-25 12:12:49 +01002183 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2184 break;
Patrick Lai9f169b92016-12-31 22:44:39 -08002185 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2186 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2187 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002188 }
2189
2190out:
2191 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
2192 return ret;
2193}
2194
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002195static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
2196{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002197 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002198 int stream = substream->stream;
2199
2200 /* if FE's runtime_update is already set, we're in race;
2201 * process this trigger later at exit
2202 */
2203 if (fe->dpcm[stream].runtime_update != SND_SOC_DPCM_UPDATE_NO) {
2204 fe->dpcm[stream].trigger_pending = cmd + 1;
2205 return 0; /* delayed, assuming it's successful */
2206 }
2207
2208 /* we're alone, let's trigger */
2209 return dpcm_fe_dai_do_trigger(substream, cmd);
2210}
2211
Liam Girdwood23607022014-01-17 17:03:55 +00002212int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002213{
2214 struct snd_soc_dpcm *dpcm;
2215 int ret = 0;
2216
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002217 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002218
2219 struct snd_soc_pcm_runtime *be = dpcm->be;
2220 struct snd_pcm_substream *be_substream =
2221 snd_soc_dpcm_get_substream(be, stream);
2222
2223 /* is this op for this BE ? */
2224 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2225 continue;
2226
2227 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
Koro Chen95f444d2015-10-28 10:15:34 +08002228 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
Libin Yang5087a8f2019-05-08 10:32:41 +08002229 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND) &&
2230 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Liam Girdwood01d75842012-04-25 12:12:49 +01002231 continue;
2232
Liam Girdwood103d84a2012-11-19 14:39:15 +00002233 dev_dbg(be->dev, "ASoC: prepare BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002234 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002235
2236 ret = soc_pcm_prepare(be_substream);
2237 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002238 dev_err(be->dev, "ASoC: backend prepare failed %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002239 ret);
2240 break;
2241 }
2242
2243 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2244 }
2245 return ret;
2246}
2247
Mark Brown45c0a182012-05-09 21:46:27 +01002248static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002249{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002250 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002251 int stream = substream->stream, ret = 0;
2252
2253 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2254
Liam Girdwood103d84a2012-11-19 14:39:15 +00002255 dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002256
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002257 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002258
2259 /* there is no point preparing this FE if there are no BEs */
2260 if (list_empty(&fe->dpcm[stream].be_clients)) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002261 dev_err(fe->dev, "ASoC: no backend DAIs enabled for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002262 fe->dai_link->name);
2263 ret = -EINVAL;
2264 goto out;
2265 }
2266
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09002267 ret = dpcm_be_dai_prepare(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002268 if (ret < 0)
2269 goto out;
2270
2271 /* call prepare on the frontend */
2272 ret = soc_pcm_prepare(substream);
2273 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002274 dev_err(fe->dev,"ASoC: prepare FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002275 fe->dai_link->name);
2276 goto out;
2277 }
2278
Liam Girdwood01d75842012-04-25 12:12:49 +01002279 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2280
2281out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002282 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002283 mutex_unlock(&fe->card->mutex);
2284
2285 return ret;
2286}
2287
Liam Girdwood618dae12012-04-25 12:12:51 +01002288static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
2289{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002290 struct snd_pcm_substream *substream =
2291 snd_soc_dpcm_get_substream(fe, stream);
2292 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01002293 int err;
Liam Girdwood01d75842012-04-25 12:12:49 +01002294
Liam Girdwood103d84a2012-11-19 14:39:15 +00002295 dev_dbg(fe->dev, "ASoC: runtime %s close on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002296 stream ? "capture" : "playback", fe->dai_link->name);
2297
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002298 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2299 /* call bespoke trigger - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002300 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002301 fe->dai_link->name);
2302
Kuninori Morimoto308193582020-04-24 08:15:09 +09002303 err = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002304 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002305 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002306 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002307 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002308 fe->dai_link->name);
2309
2310 err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
2311 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002312 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002313 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002314
2315 err = dpcm_be_dai_hw_free(fe, stream);
2316 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002317 dev_err(fe->dev,"ASoC: hw_free FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002318
Kuninori Morimoto531590b2021-03-09 10:08:17 +09002319 dpcm_be_dai_shutdown(fe, stream);
Liam Girdwood618dae12012-04-25 12:12:51 +01002320
2321 /* run the stream event for each BE */
2322 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2323
2324 return 0;
2325}
2326
2327static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
2328{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002329 struct snd_pcm_substream *substream =
2330 snd_soc_dpcm_get_substream(fe, stream);
Liam Girdwood618dae12012-04-25 12:12:51 +01002331 struct snd_soc_dpcm *dpcm;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002332 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Souptick Joarder4eeed5f2021-01-09 09:15:01 +05302333 int ret = 0;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002334 unsigned long flags;
Liam Girdwood618dae12012-04-25 12:12:51 +01002335
Liam Girdwood103d84a2012-11-19 14:39:15 +00002336 dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002337 stream ? "capture" : "playback", fe->dai_link->name);
2338
2339 /* Only start the BE if the FE is ready */
2340 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
朱灿灿2c138282020-12-25 16:42:46 +08002341 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE) {
2342 dev_err(fe->dev, "ASoC: FE %s is not ready %d\n",
2343 fe->dai_link->name, fe->dpcm[stream].state);
Dan Carpentere91b65b2021-01-11 12:50:21 +03002344 ret = -EINVAL;
朱灿灿2c138282020-12-25 16:42:46 +08002345 goto disconnect;
2346 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002347
2348 /* startup must always be called for new BEs */
2349 ret = dpcm_be_dai_startup(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002350 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002351 goto disconnect;
Liam Girdwood618dae12012-04-25 12:12:51 +01002352
2353 /* keep going if FE state is > open */
2354 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN)
2355 return 0;
2356
2357 ret = dpcm_be_dai_hw_params(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002358 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002359 goto close;
Liam Girdwood618dae12012-04-25 12:12:51 +01002360
2361 /* keep going if FE state is > hw_params */
2362 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS)
2363 return 0;
2364
2365
2366 ret = dpcm_be_dai_prepare(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002367 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002368 goto hw_free;
Liam Girdwood618dae12012-04-25 12:12:51 +01002369
2370 /* run the stream event for each BE */
2371 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2372
2373 /* keep going if FE state is > prepare */
2374 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE ||
2375 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP)
2376 return 0;
2377
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002378 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2379 /* call trigger on the frontend - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002380 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002381 fe->dai_link->name);
Liam Girdwood618dae12012-04-25 12:12:51 +01002382
Kuninori Morimoto308193582020-04-24 08:15:09 +09002383 ret = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002384 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002385 dev_err(fe->dev,"ASoC: bespoke trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002386 goto hw_free;
2387 }
2388 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002389 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002390 fe->dai_link->name);
2391
2392 ret = dpcm_be_dai_trigger(fe, stream,
2393 SNDRV_PCM_TRIGGER_START);
2394 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002395 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002396 goto hw_free;
2397 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002398 }
2399
2400 return 0;
2401
2402hw_free:
2403 dpcm_be_dai_hw_free(fe, stream);
2404close:
2405 dpcm_be_dai_shutdown(fe, stream);
2406disconnect:
朱灿灿2c138282020-12-25 16:42:46 +08002407 /* disconnect any pending BEs */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002408 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002409 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood618dae12012-04-25 12:12:51 +01002410 struct snd_soc_pcm_runtime *be = dpcm->be;
朱灿灿2c138282020-12-25 16:42:46 +08002411
2412 /* is this op for this BE ? */
2413 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2414 continue;
2415
2416 if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE ||
2417 be->dpcm[stream].state == SND_SOC_DPCM_STATE_NEW)
2418 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
Liam Girdwood618dae12012-04-25 12:12:51 +01002419 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002420 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood618dae12012-04-25 12:12:51 +01002421
2422 return ret;
2423}
2424
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002425static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
2426{
2427 struct snd_soc_dapm_widget_list *list;
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002428 int stream;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002429 int count, paths;
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002430 int ret;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002431
Pierre-Louis Bossart96bf62f2020-06-12 15:35:07 -05002432 if (!fe->dai_link->dynamic)
2433 return 0;
2434
Bard Liao6e1276a2020-02-25 21:39:16 +08002435 if (fe->num_cpus > 1) {
2436 dev_err(fe->dev,
2437 "%s doesn't support Multi CPU yet\n", __func__);
2438 return -EINVAL;
2439 }
2440
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002441 /* only check active links */
Kuninori Morimotob3dea622020-05-15 09:46:51 +09002442 if (!snd_soc_dai_active(asoc_rtd_to_cpu(fe, 0)))
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002443 return 0;
2444
2445 /* DAPM sync will call this to update DSP paths */
2446 dev_dbg(fe->dev, "ASoC: DPCM %s runtime update for FE %s\n",
2447 new ? "new" : "old", fe->dai_link->name);
2448
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002449 for_each_pcm_streams(stream) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002450
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002451 /* skip if FE doesn't have playback/capture capability */
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002452 if (!snd_soc_dai_stream_valid(asoc_rtd_to_cpu(fe, 0), stream) ||
2453 !snd_soc_dai_stream_valid(asoc_rtd_to_codec(fe, 0), stream))
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002454 continue;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002455
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002456 /* skip if FE isn't currently playing/capturing */
Kuninori Morimotob3dea622020-05-15 09:46:51 +09002457 if (!snd_soc_dai_stream_active(asoc_rtd_to_cpu(fe, 0), stream) ||
2458 !snd_soc_dai_stream_active(asoc_rtd_to_codec(fe, 0), stream))
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002459 continue;
2460
2461 paths = dpcm_path_get(fe, stream, &list);
2462 if (paths < 0) {
2463 dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
2464 fe->dai_link->name,
2465 stream == SNDRV_PCM_STREAM_PLAYBACK ?
2466 "playback" : "capture");
2467 return paths;
2468 }
2469
2470 /* update any playback/capture paths */
2471 count = dpcm_process_paths(fe, stream, &list, new);
2472 if (count) {
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002473 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002474 if (new)
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002475 ret = dpcm_run_update_startup(fe, stream);
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002476 else
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002477 ret = dpcm_run_update_shutdown(fe, stream);
2478 if (ret < 0)
2479 dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n");
2480 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002481
2482 dpcm_clear_pending_state(fe, stream);
2483 dpcm_be_disconnect(fe, stream);
2484 }
2485
2486 dpcm_path_put(&list);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002487 }
2488
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002489 return 0;
2490}
2491
Liam Girdwood618dae12012-04-25 12:12:51 +01002492/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
2493 * any DAI links.
2494 */
Guennadi Liakhovetskif17a1472020-03-12 10:52:14 +01002495int snd_soc_dpcm_runtime_update(struct snd_soc_card *card)
Liam Girdwood618dae12012-04-25 12:12:51 +01002496{
Mengdong Lin1a497982015-11-18 02:34:11 -05002497 struct snd_soc_pcm_runtime *fe;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002498 int ret = 0;
Liam Girdwood618dae12012-04-25 12:12:51 +01002499
Liam Girdwood618dae12012-04-25 12:12:51 +01002500 mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002501 /* shutdown all old paths first */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002502 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002503 ret = soc_dpcm_fe_runtime_update(fe, 0);
2504 if (ret)
2505 goto out;
Liam Girdwood618dae12012-04-25 12:12:51 +01002506 }
2507
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002508 /* bring new paths up */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002509 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002510 ret = soc_dpcm_fe_runtime_update(fe, 1);
2511 if (ret)
2512 goto out;
2513 }
2514
2515out:
Liam Girdwood618dae12012-04-25 12:12:51 +01002516 mutex_unlock(&card->mutex);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002517 return ret;
Liam Girdwood618dae12012-04-25 12:12:51 +01002518}
Guennadi Liakhovetskif17a1472020-03-12 10:52:14 +01002519EXPORT_SYMBOL_GPL(snd_soc_dpcm_runtime_update);
Liam Girdwood01d75842012-04-25 12:12:49 +01002520
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002521static void dpcm_fe_dai_cleanup(struct snd_pcm_substream *fe_substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002522{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002523 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002524 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002525 int stream = fe_substream->stream;
Kuninori Morimoto30fca262020-03-06 10:09:44 +09002526
2527 /* mark FE's links ready to prune */
2528 for_each_dpcm_be(fe, stream, dpcm)
2529 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2530
2531 dpcm_be_disconnect(fe, stream);
2532
2533 fe->dpcm[stream].runtime = NULL;
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002534}
2535
2536static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
2537{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002538 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002539 int ret;
2540
2541 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2542 ret = dpcm_fe_dai_shutdown(fe_substream);
2543
2544 dpcm_fe_dai_cleanup(fe_substream);
2545
Kuninori Morimoto30fca262020-03-06 10:09:44 +09002546 mutex_unlock(&fe->card->mutex);
2547 return ret;
2548}
2549
Liam Girdwood01d75842012-04-25 12:12:49 +01002550static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
2551{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002552 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002553 struct snd_soc_dapm_widget_list *list;
2554 int ret;
2555 int stream = fe_substream->stream;
2556
2557 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2558 fe->dpcm[stream].runtime = fe_substream->runtime;
2559
Qiao Zhou8f70e512014-09-10 17:54:07 +08002560 ret = dpcm_path_get(fe, stream, &list);
2561 if (ret < 0) {
Kuninori Morimotocae06eb2020-02-17 17:28:11 +09002562 goto open_end;
Qiao Zhou8f70e512014-09-10 17:54:07 +08002563 } else if (ret == 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002564 dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002565 fe->dai_link->name, stream ? "capture" : "playback");
Liam Girdwood01d75842012-04-25 12:12:49 +01002566 }
2567
2568 /* calculate valid and active FE <-> BE dpcms */
2569 dpcm_process_paths(fe, stream, &list, 1);
2570
2571 ret = dpcm_fe_dai_startup(fe_substream);
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002572 if (ret < 0)
2573 dpcm_fe_dai_cleanup(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002574
2575 dpcm_clear_pending_state(fe, stream);
2576 dpcm_path_put(&list);
Kuninori Morimotocae06eb2020-02-17 17:28:11 +09002577open_end:
Liam Girdwood01d75842012-04-25 12:12:49 +01002578 mutex_unlock(&fe->card->mutex);
2579 return ret;
2580}
2581
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002582static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd,
2583 int *playback, int *capture)
Liam Girdwoodddee6272011-06-09 14:45:53 +01002584{
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002585 struct snd_soc_dai *codec_dai;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002586 struct snd_soc_dai *cpu_dai;
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002587 int stream;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002588 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002589
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002590 if (rtd->dai_link->dynamic && rtd->num_cpus > 1) {
2591 dev_err(rtd->dev,
2592 "DPCM doesn't support Multi CPU for Front-Ends yet\n");
2593 return -EINVAL;
2594 }
Stephan Gerhold9b5db052020-04-15 12:49:28 +02002595
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002596 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
2597 if (rtd->dai_link->dpcm_playback) {
2598 stream = SNDRV_PCM_STREAM_PLAYBACK;
2599
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002600 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
2601 if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002602 *playback = 1;
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002603 break;
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002604 }
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002605 }
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002606 if (!*playback) {
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002607 dev_err(rtd->card->dev,
2608 "No CPU DAIs support playback for stream %s\n",
2609 rtd->dai_link->stream_name);
2610 return -EINVAL;
2611 }
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002612 }
2613 if (rtd->dai_link->dpcm_capture) {
2614 stream = SNDRV_PCM_STREAM_CAPTURE;
2615
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002616 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
2617 if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002618 *capture = 1;
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002619 break;
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002620 }
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002621 }
2622
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002623 if (!*capture) {
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002624 dev_err(rtd->card->dev,
2625 "No CPU DAIs support capture for stream %s\n",
2626 rtd->dai_link->stream_name);
2627 return -EINVAL;
2628 }
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002629 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002630 } else {
Jerome Bruneta3420312019-07-25 18:59:47 +02002631 /* Adapt stream for codec2codec links */
Stephan Gerholda4877a62020-02-18 11:38:24 +01002632 int cpu_capture = rtd->dai_link->params ?
2633 SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
2634 int cpu_playback = rtd->dai_link->params ?
2635 SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
Jerome Bruneta3420312019-07-25 18:59:47 +02002636
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09002637 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002638 if (rtd->num_cpus == 1) {
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002639 cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002640 } else if (rtd->num_cpus == rtd->num_codecs) {
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002641 cpu_dai = asoc_rtd_to_cpu(rtd, i);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002642 } else {
2643 dev_err(rtd->card->dev,
2644 "N cpus to M codecs link is not supported yet\n");
2645 return -EINVAL;
2646 }
2647
Kuninori Morimoto467fece2019-07-22 10:36:16 +09002648 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
Stephan Gerholda4877a62020-02-18 11:38:24 +01002649 snd_soc_dai_stream_valid(cpu_dai, cpu_playback))
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002650 *playback = 1;
Kuninori Morimoto467fece2019-07-22 10:36:16 +09002651 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
Stephan Gerholda4877a62020-02-18 11:38:24 +01002652 snd_soc_dai_stream_valid(cpu_dai, cpu_capture))
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002653 *capture = 1;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002654 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002655 }
Sangsu Parka5002312012-01-02 17:15:10 +09002656
Fabio Estevamd6bead02013-08-29 10:32:13 -03002657 if (rtd->dai_link->playback_only) {
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002658 *playback = 1;
2659 *capture = 0;
Fabio Estevamd6bead02013-08-29 10:32:13 -03002660 }
2661
2662 if (rtd->dai_link->capture_only) {
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002663 *playback = 0;
2664 *capture = 1;
Fabio Estevamd6bead02013-08-29 10:32:13 -03002665 }
2666
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002667 return 0;
2668}
2669
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002670static int soc_create_pcm(struct snd_pcm **pcm,
2671 struct snd_soc_pcm_runtime *rtd,
2672 int playback, int capture, int num)
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002673{
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002674 char new_name[64];
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002675 int ret;
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002676
Liam Girdwood01d75842012-04-25 12:12:49 +01002677 /* create the PCM */
Jerome Bruneta3420312019-07-25 18:59:47 +02002678 if (rtd->dai_link->params) {
2679 snprintf(new_name, sizeof(new_name), "codec2codec(%s)",
2680 rtd->dai_link->stream_name);
2681
2682 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002683 playback, capture, pcm);
Jerome Bruneta3420312019-07-25 18:59:47 +02002684 } else if (rtd->dai_link->no_pcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002685 snprintf(new_name, sizeof(new_name), "(%s)",
2686 rtd->dai_link->stream_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002687
Liam Girdwood01d75842012-04-25 12:12:49 +01002688 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002689 playback, capture, pcm);
Liam Girdwood01d75842012-04-25 12:12:49 +01002690 } else {
2691 if (rtd->dai_link->dynamic)
2692 snprintf(new_name, sizeof(new_name), "%s (*)",
2693 rtd->dai_link->stream_name);
2694 else
2695 snprintf(new_name, sizeof(new_name), "%s %s-%d",
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002696 rtd->dai_link->stream_name,
Kuninori Morimoto6fb89442021-03-09 10:07:48 +09002697 soc_codec_dai_name(rtd), num);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002698
Liam Girdwood01d75842012-04-25 12:12:49 +01002699 ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002700 capture, pcm);
Liam Girdwood01d75842012-04-25 12:12:49 +01002701 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01002702 if (ret < 0) {
Pierre-Louis Bossart799827a2020-06-12 15:40:49 -05002703 dev_err(rtd->card->dev, "ASoC: can't create pcm %s for dailink %s: %d\n",
2704 new_name, rtd->dai_link->name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002705 return ret;
2706 }
Liam Girdwood103d84a2012-11-19 14:39:15 +00002707 dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002708
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002709 return 0;
2710}
2711
2712/* create a new pcm */
2713int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
2714{
2715 struct snd_soc_component *component;
2716 struct snd_pcm *pcm;
2717 int ret = 0, playback = 0, capture = 0;
2718 int i;
2719
2720 ret = soc_get_playback_capture(rtd, &playback, &capture);
2721 if (ret < 0)
2722 return ret;
2723
2724 ret = soc_create_pcm(&pcm, rtd, playback, capture, num);
2725 if (ret < 0)
2726 return ret;
2727
Liam Girdwoodddee6272011-06-09 14:45:53 +01002728 /* DAPM dai link stream work */
Jerome Bruneta3420312019-07-25 18:59:47 +02002729 if (rtd->dai_link->params)
Curtis Malainey4bf2e382019-12-03 09:30:07 -08002730 rtd->close_delayed_work_func = codec2codec_close_delayed_work;
Jerome Bruneta3420312019-07-25 18:59:47 +02002731 else
Kuninori Morimoto83f94a22020-01-10 11:36:17 +09002732 rtd->close_delayed_work_func = snd_soc_close_delayed_work;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002733
2734 rtd->pcm = pcm;
Kuninori Morimotoe04e7b82021-01-22 10:13:32 +09002735 pcm->nonatomic = rtd->dai_link->nonatomic;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002736 pcm->private_data = rtd;
Liam Girdwood01d75842012-04-25 12:12:49 +01002737
Jerome Bruneta3420312019-07-25 18:59:47 +02002738 if (rtd->dai_link->no_pcm || rtd->dai_link->params) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002739 if (playback)
2740 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
2741 if (capture)
2742 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
2743 goto out;
2744 }
2745
2746 /* ASoC PCM operations */
2747 if (rtd->dai_link->dynamic) {
2748 rtd->ops.open = dpcm_fe_dai_open;
2749 rtd->ops.hw_params = dpcm_fe_dai_hw_params;
2750 rtd->ops.prepare = dpcm_fe_dai_prepare;
2751 rtd->ops.trigger = dpcm_fe_dai_trigger;
2752 rtd->ops.hw_free = dpcm_fe_dai_hw_free;
2753 rtd->ops.close = dpcm_fe_dai_close;
2754 rtd->ops.pointer = soc_pcm_pointer;
2755 } else {
2756 rtd->ops.open = soc_pcm_open;
2757 rtd->ops.hw_params = soc_pcm_hw_params;
2758 rtd->ops.prepare = soc_pcm_prepare;
2759 rtd->ops.trigger = soc_pcm_trigger;
2760 rtd->ops.hw_free = soc_pcm_hw_free;
2761 rtd->ops.close = soc_pcm_close;
2762 rtd->ops.pointer = soc_pcm_pointer;
2763 }
2764
Kuninori Morimoto613fb502020-01-10 11:35:21 +09002765 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto2b544dd2019-10-15 12:59:31 +09002766 const struct snd_soc_component_driver *drv = component->driver;
Kuninori Morimotob8135862017-10-11 01:37:23 +00002767
Takashi Iwai3b1c9522019-11-21 20:07:08 +01002768 if (drv->ioctl)
2769 rtd->ops.ioctl = snd_soc_pcm_component_ioctl;
Takashi Iwai1e5ddb62019-11-21 20:07:09 +01002770 if (drv->sync_stop)
2771 rtd->ops.sync_stop = snd_soc_pcm_component_sync_stop;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002772 if (drv->copy_user)
Kuninori Morimoto82d81f52019-07-26 13:51:56 +09002773 rtd->ops.copy_user = snd_soc_pcm_component_copy_user;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002774 if (drv->page)
Kuninori Morimoto9c712e42019-07-26 13:52:00 +09002775 rtd->ops.page = snd_soc_pcm_component_page;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002776 if (drv->mmap)
Kuninori Morimoto205875e2019-07-26 13:52:04 +09002777 rtd->ops.mmap = snd_soc_pcm_component_mmap;
Kuninori Morimotob8135862017-10-11 01:37:23 +00002778 }
2779
Liam Girdwoodddee6272011-06-09 14:45:53 +01002780 if (playback)
Liam Girdwood01d75842012-04-25 12:12:49 +01002781 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002782
2783 if (capture)
Liam Girdwood01d75842012-04-25 12:12:49 +01002784 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002785
Kuninori Morimotob2b2afb2019-11-18 10:50:32 +09002786 ret = snd_soc_pcm_component_new(rtd);
Kuninori Morimoto74842912019-07-26 13:52:08 +09002787 if (ret < 0) {
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002788 dev_err(rtd->dev, "ASoC: pcm constructor failed for dailink %s: %d\n",
2789 rtd->dai_link->name, ret);
Kuninori Morimoto74842912019-07-26 13:52:08 +09002790 return ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002791 }
Johan Hovoldc641e5b2017-07-12 17:55:29 +02002792
Takashi Iwai3d21ef02019-01-11 15:58:39 +01002793 pcm->no_device_suspend = true;
Liam Girdwood01d75842012-04-25 12:12:49 +01002794out:
Pierre-Louis Bossart1d5cd522020-06-12 15:40:50 -05002795 dev_dbg(rtd->card->dev, "%s <-> %s mapping ok\n",
Kuninori Morimoto6fb89442021-03-09 10:07:48 +09002796 soc_codec_dai_name(rtd), soc_cpu_dai_name(rtd));
Liam Girdwoodddee6272011-06-09 14:45:53 +01002797 return ret;
2798}
Liam Girdwood01d75842012-04-25 12:12:49 +01002799
2800/* is the current PCM operation for this FE ? */
2801int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream)
2802{
2803 if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE)
2804 return 1;
2805 return 0;
2806}
2807EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update);
2808
2809/* is the current PCM operation for this BE ? */
2810int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
2811 struct snd_soc_pcm_runtime *be, int stream)
2812{
2813 if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) ||
2814 ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) &&
2815 be->dpcm[stream].runtime_update))
2816 return 1;
2817 return 0;
2818}
2819EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update);
2820
2821/* get the substream for this BE */
2822struct snd_pcm_substream *
2823 snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream)
2824{
2825 return be->pcm->streams[stream].substream;
2826}
2827EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream);
2828
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002829static int snd_soc_dpcm_check_state(struct snd_soc_pcm_runtime *fe,
2830 struct snd_soc_pcm_runtime *be,
2831 int stream,
2832 const enum snd_soc_dpcm_state *states,
2833 int num_states)
Liam Girdwood01d75842012-04-25 12:12:49 +01002834{
2835 struct snd_soc_dpcm *dpcm;
2836 int state;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002837 int ret = 1;
2838 unsigned long flags;
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002839 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01002840
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002841 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00002842 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002843
2844 if (dpcm->fe == fe)
2845 continue;
2846
2847 state = dpcm->fe->dpcm[stream].state;
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002848 for (i = 0; i < num_states; i++) {
2849 if (state == states[i]) {
2850 ret = 0;
2851 break;
2852 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002853 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002854 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002855 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01002856
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002857 /* it's safe to do this BE DAI */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002858 return ret;
Liam Girdwood01d75842012-04-25 12:12:49 +01002859}
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002860
2861/*
2862 * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE
2863 * are not running, paused or suspended for the specified stream direction.
2864 */
2865int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
2866 struct snd_soc_pcm_runtime *be, int stream)
2867{
2868 const enum snd_soc_dpcm_state state[] = {
2869 SND_SOC_DPCM_STATE_START,
2870 SND_SOC_DPCM_STATE_PAUSED,
2871 SND_SOC_DPCM_STATE_SUSPEND,
2872 };
2873
2874 return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
2875}
Liam Girdwood01d75842012-04-25 12:12:49 +01002876EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop);
2877
2878/*
2879 * We can only change hw params a BE DAI if any of it's FE are not prepared,
2880 * running, paused or suspended for the specified stream direction.
2881 */
2882int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
2883 struct snd_soc_pcm_runtime *be, int stream)
2884{
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002885 const enum snd_soc_dpcm_state state[] = {
2886 SND_SOC_DPCM_STATE_START,
2887 SND_SOC_DPCM_STATE_PAUSED,
2888 SND_SOC_DPCM_STATE_SUSPEND,
2889 SND_SOC_DPCM_STATE_PREPARE,
2890 };
Liam Girdwood01d75842012-04-25 12:12:49 +01002891
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002892 return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
Liam Girdwood01d75842012-04-25 12:12:49 +01002893}
2894EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);