blob: 6f2de27cf18f1a498c23b4c526ebce7417bdaa21 [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{
168 if (!rtd->dai_link)
169 return;
170
171 if (!rtd->dai_link->dynamic)
172 return;
173
174 if (!rtd->card->debugfs_card_root)
175 return;
176
177 rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name,
178 rtd->card->debugfs_card_root);
179
180 debugfs_create_file("state", 0444, rtd->debugfs_dpcm_root,
181 rtd, &dpcm_state_fops);
182}
Kuninori Morimoto154dae82020-02-19 15:57:06 +0900183
184static void dpcm_create_debugfs_state(struct snd_soc_dpcm *dpcm, int stream)
185{
186 char *name;
187
188 name = kasprintf(GFP_KERNEL, "%s:%s", dpcm->be->dai_link->name,
189 stream ? "capture" : "playback");
190 if (name) {
191 dpcm->debugfs_state = debugfs_create_dir(
192 name, dpcm->fe->debugfs_dpcm_root);
193 debugfs_create_u32("state", 0644, dpcm->debugfs_state,
194 &dpcm->state);
195 kfree(name);
196 }
197}
198
199static void dpcm_remove_debugfs_state(struct snd_soc_dpcm *dpcm)
200{
201 debugfs_remove_recursive(dpcm->debugfs_state);
202}
203
204#else
205static inline void dpcm_create_debugfs_state(struct snd_soc_dpcm *dpcm,
206 int stream)
207{
208}
209
210static inline void dpcm_remove_debugfs_state(struct snd_soc_dpcm *dpcm)
211{
212}
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900213#endif
214
Kuninori Morimoto9c6d7f92020-12-11 14:55:16 +0900215/* Set FE's runtime_update state; the state is protected via PCM stream lock
216 * for avoiding the race with trigger callback.
217 * If the state is unset and a trigger is pending while the previous operation,
218 * process the pending trigger action here.
219 */
220static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
221static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
222 int stream, enum snd_soc_dpcm_update state)
223{
224 struct snd_pcm_substream *substream =
225 snd_soc_dpcm_get_substream(fe, stream);
226
227 snd_pcm_stream_lock_irq(substream);
228 if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) {
229 dpcm_fe_dai_do_trigger(substream,
230 fe->dpcm[stream].trigger_pending - 1);
231 fe->dpcm[stream].trigger_pending = 0;
232 }
233 fe->dpcm[stream].runtime_update = state;
234 snd_pcm_stream_unlock_irq(substream);
235}
236
Kuninori Morimotoa7e204442020-12-11 14:55:22 +0900237static void dpcm_set_be_update_state(struct snd_soc_pcm_runtime *be,
238 int stream, enum snd_soc_dpcm_update state)
239{
240 be->dpcm[stream].runtime_update = state;
241}
242
Kuninori Morimotod9051d82020-05-15 09:46:21 +0900243/**
244 * snd_soc_runtime_action() - Increment/Decrement active count for
245 * PCM runtime components
246 * @rtd: ASoC PCM runtime that is activated
247 * @stream: Direction of the PCM stream
Colton Lewisb6d6e9e2020-06-26 05:40:24 +0000248 * @action: Activate stream if 1. Deactivate if -1.
Kuninori Morimotod9051d82020-05-15 09:46:21 +0900249 *
250 * Increments/Decrements the active count for all the DAIs and components
251 * attached to a PCM runtime.
252 * Should typically be called when a stream is opened.
253 *
254 * Must be called with the rtd->card->pcm_mutex being held
255 */
256void snd_soc_runtime_action(struct snd_soc_pcm_runtime *rtd,
257 int stream, int action)
Kuninori Morimoto7a5aaba2020-02-10 12:14:12 +0900258{
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900259 struct snd_soc_dai *dai;
Kuninori Morimoto7a5aaba2020-02-10 12:14:12 +0900260 int i;
261
262 lockdep_assert_held(&rtd->card->pcm_mutex);
263
Kuninori Morimotodc829102020-05-15 09:46:27 +0900264 for_each_rtd_dais(rtd, i, dai)
265 snd_soc_dai_action(dai, stream, action);
Kuninori Morimoto7a5aaba2020-02-10 12:14:12 +0900266}
Kuninori Morimotod9051d82020-05-15 09:46:21 +0900267EXPORT_SYMBOL_GPL(snd_soc_runtime_action);
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100268
269/**
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100270 * snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay
271 * @rtd: The ASoC PCM runtime that should be checked.
272 *
273 * This function checks whether the power down delay should be ignored for a
274 * specific PCM runtime. Returns true if the delay is 0, if it the DAI link has
275 * been configured to ignore the delay, or if none of the components benefits
276 * from having the delay.
277 */
278bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
279{
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000280 struct snd_soc_component *component;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200281 bool ignore = true;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900282 int i;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200283
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100284 if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
285 return true;
286
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900287 for_each_rtd_components(rtd, i, component)
Kuninori Morimoto72c38182018-01-19 05:21:19 +0000288 ignore &= !component->driver->use_pmdown_time;
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000289
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000290 return ignore;
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100291}
292
293/**
Lars-Peter Clausen90996f42013-05-14 11:05:30 +0200294 * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
295 * @substream: the pcm substream
296 * @hw: the hardware parameters
297 *
298 * Sets the substream runtime hardware parameters.
299 */
300int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
301 const struct snd_pcm_hardware *hw)
302{
Kuninori Morimoto56e749b2021-03-09 10:07:53 +0900303 substream->runtime->hw = *hw;
304
Lars-Peter Clausen90996f42013-05-14 11:05:30 +0200305 return 0;
306}
307EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
308
Liam Girdwood01d75842012-04-25 12:12:49 +0100309/* DPCM stream event, send event to FE and all active BEs. */
Liam Girdwood23607022014-01-17 17:03:55 +0000310int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
Liam Girdwood01d75842012-04-25 12:12:49 +0100311 int event)
312{
313 struct snd_soc_dpcm *dpcm;
314
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +0000315 for_each_dpcm_be(fe, dir, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +0100316
317 struct snd_soc_pcm_runtime *be = dpcm->be;
318
Liam Girdwood103d84a2012-11-19 14:39:15 +0000319 dev_dbg(be->dev, "ASoC: BE %s event %d dir %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +0100320 be->dai_link->name, event, dir);
321
Banajit Goswamib1cd2e32017-07-14 23:15:05 -0700322 if ((event == SND_SOC_DAPM_STREAM_STOP) &&
323 (be->dpcm[dir].users >= 1))
324 continue;
325
Liam Girdwood01d75842012-04-25 12:12:49 +0100326 snd_soc_dapm_stream_event(be, dir, event);
327 }
328
329 snd_soc_dapm_stream_event(fe, dir, event);
330
331 return 0;
332}
333
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900334static void soc_pcm_set_dai_params(struct snd_soc_dai *dai,
335 struct snd_pcm_hw_params *params)
336{
337 if (params) {
338 dai->rate = params_rate(params);
339 dai->channels = params_channels(params);
340 dai->sample_bits = snd_pcm_format_physical_width(params_format(params));
341 } else {
342 dai->rate = 0;
343 dai->channels = 0;
344 dai->sample_bits = 0;
345 }
346}
347
Dong Aisheng17841022011-08-29 17:15:14 +0800348static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
349 struct snd_soc_dai *soc_dai)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100350{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900351 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100352 int ret;
353
Kuninori Morimotof8fc9ec2021-03-09 10:07:42 +0900354 if (!snd_soc_dai_active(soc_dai))
355 return 0;
356
Kuninori Morimotofac110c2021-01-15 13:56:35 +0900357#define __soc_pcm_apply_symmetry(name, NAME) \
358 if (soc_dai->name && (soc_dai->driver->symmetric_##name || \
359 rtd->dai_link->symmetric_##name)) { \
360 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %s to %d\n",\
361 #name, soc_dai->name); \
362 \
363 ret = snd_pcm_hw_constraint_single(substream->runtime, \
364 SNDRV_PCM_HW_PARAM_##NAME,\
365 soc_dai->name); \
366 if (ret < 0) { \
367 dev_err(soc_dai->dev, \
368 "ASoC: Unable to apply %s constraint: %d\n",\
369 #name, ret); \
370 return ret; \
371 } \
Liam Girdwoodddee6272011-06-09 14:45:53 +0100372 }
373
Kuninori Morimotofac110c2021-01-15 13:56:35 +0900374 __soc_pcm_apply_symmetry(rate, RATE);
375 __soc_pcm_apply_symmetry(channels, CHANNELS);
376 __soc_pcm_apply_symmetry(sample_bits, SAMPLE_BITS);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100377
378 return 0;
379}
380
Nicolin Chen3635bf02013-11-13 18:56:24 +0800381static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
382 struct snd_pcm_hw_params *params)
383{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900384 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900385 struct snd_soc_dai d;
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900386 struct snd_soc_dai *dai;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800387 struct snd_soc_dai *cpu_dai;
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900388 unsigned int symmetry, i;
Nicolin Chen3635bf02013-11-13 18:56:24 +0800389
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900390 soc_pcm_set_dai_params(&d, params);
Nicolin Chen3635bf02013-11-13 18:56:24 +0800391
Kuninori Morimoto3a906722021-01-15 13:56:39 +0900392#define __soc_pcm_params_symmetry(name) \
393 symmetry = rtd->dai_link->symmetric_##name; \
394 for_each_rtd_dais(rtd, i, dai) \
395 symmetry |= dai->driver->symmetric_##name; \
396 \
397 if (symmetry) \
398 for_each_rtd_cpu_dais(rtd, i, cpu_dai) \
399 if (cpu_dai->name && cpu_dai->name != d.name) { \
400 dev_err(rtd->dev, "ASoC: unmatched %s symmetry: %d - %d\n", \
401 #name, cpu_dai->name, d.name); \
402 return -EINVAL; \
403 }
404
Nicolin Chen3635bf02013-11-13 18:56:24 +0800405 /* reject unmatched parameters when applying symmetry */
Kuninori Morimoto3a906722021-01-15 13:56:39 +0900406 __soc_pcm_params_symmetry(rate);
407 __soc_pcm_params_symmetry(channels);
408 __soc_pcm_params_symmetry(sample_bits);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100409
410 return 0;
411}
412
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100413static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream)
414{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900415 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100416 struct snd_soc_dai_link *link = rtd->dai_link;
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900417 struct snd_soc_dai *dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200418 unsigned int symmetry, i;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100419
Kuninori Morimotof14654d2021-01-15 13:52:54 +0900420 symmetry = link->symmetric_rate ||
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800421 link->symmetric_channels ||
Kuninori Morimotof14654d2021-01-15 13:52:54 +0900422 link->symmetric_sample_bits;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800423
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900424 for_each_rtd_dais(rtd, i, dai)
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800425 symmetry = symmetry ||
Kuninori Morimotof14654d2021-01-15 13:52:54 +0900426 dai->driver->symmetric_rate ||
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900427 dai->driver->symmetric_channels ||
Kuninori Morimotof14654d2021-01-15 13:52:54 +0900428 dai->driver->symmetric_sample_bits;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200429
430 return symmetry;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100431}
432
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200433static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits)
Mark Brown58ba9b22012-01-16 18:38:51 +0000434{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900435 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Takashi Iwaic6068d32014-12-31 17:10:34 +0100436 int ret;
Mark Brown58ba9b22012-01-16 18:38:51 +0000437
438 if (!bits)
439 return;
440
Lars-Peter Clausen0e2a3752014-12-29 18:43:38 +0100441 ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 0, bits);
442 if (ret != 0)
443 dev_warn(rtd->dev, "ASoC: Failed to set MSB %d: %d\n",
444 bits, ret);
Mark Brown58ba9b22012-01-16 18:38:51 +0000445}
446
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200447static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200448{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900449 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800450 struct snd_soc_dai *cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200451 struct snd_soc_dai *codec_dai;
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900452 struct snd_soc_pcm_stream *pcm_codec, *pcm_cpu;
453 int stream = substream->stream;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200454 int i;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800455 unsigned int bits = 0, cpu_bits = 0;
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200456
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900457 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900458 pcm_codec = snd_soc_dai_get_pcm_stream(codec_dai, stream);
459
460 if (pcm_codec->sig_bits == 0) {
461 bits = 0;
462 break;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200463 }
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900464 bits = max(pcm_codec->sig_bits, bits);
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200465 }
466
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900467 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800468 pcm_cpu = snd_soc_dai_get_pcm_stream(cpu_dai, stream);
469
470 if (pcm_cpu->sig_bits == 0) {
471 cpu_bits = 0;
472 break;
473 }
474 cpu_bits = max(pcm_cpu->sig_bits, cpu_bits);
475 }
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900476
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200477 soc_pcm_set_msb(substream, bits);
478 soc_pcm_set_msb(substream, cpu_bits);
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200479}
480
Kuninori Morimotof6c04af2021-02-04 08:50:31 +0900481static void soc_pcm_hw_init(struct snd_pcm_hardware *hw)
482{
483 hw->rates = UINT_MAX;
484 hw->rate_min = 0;
485 hw->rate_max = UINT_MAX;
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900486 hw->channels_min = 0;
487 hw->channels_max = UINT_MAX;
Kuninori Morimotodebc71f2021-02-04 08:52:04 +0900488 hw->formats = ULLONG_MAX;
Kuninori Morimotof6c04af2021-02-04 08:50:31 +0900489}
490
491static void soc_pcm_hw_update_rate(struct snd_pcm_hardware *hw,
492 struct snd_soc_pcm_stream *p)
493{
494 hw->rates = snd_pcm_rate_mask_intersect(hw->rates, p->rates);
495
496 /* setup hw->rate_min/max via hw->rates first */
497 snd_pcm_hw_limit_rates(hw);
498
499 /* update hw->rate_min/max by snd_soc_pcm_stream */
500 hw->rate_min = max(hw->rate_min, p->rate_min);
501 hw->rate_max = min_not_zero(hw->rate_max, p->rate_max);
502}
503
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900504static void soc_pcm_hw_update_chan(struct snd_pcm_hardware *hw,
505 struct snd_soc_pcm_stream *p)
506{
507 hw->channels_min = max(hw->channels_min, p->channels_min);
508 hw->channels_max = min(hw->channels_max, p->channels_max);
509}
510
Kuninori Morimotodebc71f2021-02-04 08:52:04 +0900511static void soc_pcm_hw_update_format(struct snd_pcm_hardware *hw,
512 struct snd_soc_pcm_stream *p)
513{
514 hw->formats &= p->formats;
515}
516
Samuel Holland5854a462020-03-04 23:11:42 -0600517/**
518 * snd_soc_runtime_calc_hw() - Calculate hw limits for a PCM stream
519 * @rtd: ASoC PCM runtime
520 * @hw: PCM hardware parameters (output)
521 * @stream: Direction of the PCM stream
522 *
523 * Calculates the subset of stream parameters supported by all DAIs
524 * associated with the PCM stream.
525 */
526int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd,
527 struct snd_pcm_hardware *hw, int stream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200528{
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000529 struct snd_soc_dai *codec_dai;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800530 struct snd_soc_dai *cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200531 struct snd_soc_pcm_stream *codec_stream;
532 struct snd_soc_pcm_stream *cpu_stream;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800533 unsigned int cpu_chan_min = 0, cpu_chan_max = UINT_MAX;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200534 int i;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100535
Kuninori Morimotof6c04af2021-02-04 08:50:31 +0900536 soc_pcm_hw_init(hw);
537
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800538 /* first calculate min/max only for CPUs in the DAI link */
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900539 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800540
541 /*
542 * Skip CPUs which don't support the current stream type.
543 * Otherwise, since the rate, channel, and format values will
544 * zero in that case, we would have no usable settings left,
545 * causing the resulting setup to fail.
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800546 */
Samuel Holland5854a462020-03-04 23:11:42 -0600547 if (!snd_soc_dai_stream_valid(cpu_dai, stream))
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800548 continue;
549
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800550 cpu_stream = snd_soc_dai_get_pcm_stream(cpu_dai, stream);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100551
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900552 soc_pcm_hw_update_chan(hw, cpu_stream);
Kuninori Morimotof6c04af2021-02-04 08:50:31 +0900553 soc_pcm_hw_update_rate(hw, cpu_stream);
Kuninori Morimotodebc71f2021-02-04 08:52:04 +0900554 soc_pcm_hw_update_format(hw, cpu_stream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800555 }
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900556 cpu_chan_min = hw->channels_min;
557 cpu_chan_max = hw->channels_max;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800558
559 /* second calculate min/max only for CODECs in the DAI link */
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900560 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200561
562 /*
563 * Skip CODECs which don't support the current stream type.
564 * Otherwise, since the rate, channel, and format values will
565 * zero in that case, we would have no usable settings left,
566 * causing the resulting setup to fail.
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200567 */
Kuninori Morimoto25c2f512020-02-27 10:54:38 +0900568 if (!snd_soc_dai_stream_valid(codec_dai, stream))
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200569 continue;
570
Kuninori Morimotoacf253c2020-02-19 15:56:30 +0900571 codec_stream = snd_soc_dai_get_pcm_stream(codec_dai, stream);
572
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900573 soc_pcm_hw_update_chan(hw, codec_stream);
Kuninori Morimotof6c04af2021-02-04 08:50:31 +0900574 soc_pcm_hw_update_rate(hw, codec_stream);
Kuninori Morimotodebc71f2021-02-04 08:52:04 +0900575 soc_pcm_hw_update_format(hw, codec_stream);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200576 }
577
Samuel Holland5854a462020-03-04 23:11:42 -0600578 /* Verify both a valid CPU DAI and a valid CODEC DAI were found */
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900579 if (!hw->channels_min)
Samuel Holland5854a462020-03-04 23:11:42 -0600580 return -EINVAL;
581
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200582 /*
583 * chan min/max cannot be enforced if there are multiple CODEC DAIs
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800584 * connected to CPU DAI(s), use CPU DAI's directly and let
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200585 * channel allocation be fixed up later
586 */
587 if (rtd->num_codecs > 1) {
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900588 hw->channels_min = cpu_chan_min;
589 hw->channels_max = cpu_chan_max;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200590 }
591
Samuel Holland5854a462020-03-04 23:11:42 -0600592 return 0;
593}
594EXPORT_SYMBOL_GPL(snd_soc_runtime_calc_hw);
595
596static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
597{
598 struct snd_pcm_hardware *hw = &substream->runtime->hw;
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900599 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Samuel Holland5854a462020-03-04 23:11:42 -0600600 u64 formats = hw->formats;
601
602 /*
603 * At least one CPU and one CODEC should match. Otherwise, we should
604 * have bailed out on a higher level, since there would be no CPU or
605 * CODEC to support the transfer direction in that case.
606 */
607 snd_soc_runtime_calc_hw(rtd, hw, substream->stream);
608
609 if (formats)
610 hw->formats &= formats;
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200611}
612
Kuninori Morimotodd039072020-02-10 12:14:37 +0900613static int soc_pcm_components_open(struct snd_pcm_substream *substream)
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900614{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900615 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900616 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900617 int i, ret = 0;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900618
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900619 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto51aff912020-09-28 09:01:04 +0900620 ret = snd_soc_component_module_get_when_open(component, substream);
Kuninori Morimotobcae16312020-09-28 09:01:36 +0900621 if (ret < 0)
Kai Vehmanend2aaa8d2020-02-20 11:49:55 +0200622 break;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900623
Kuninori Morimotoae2f4842019-07-26 13:50:01 +0900624 ret = snd_soc_component_open(component, substream);
Kuninori Morimotobcae16312020-09-28 09:01:36 +0900625 if (ret < 0)
Kai Vehmanend2aaa8d2020-02-20 11:49:55 +0200626 break;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900627 }
Kuninori Morimotodd039072020-02-10 12:14:37 +0900628
Kai Vehmanend2aaa8d2020-02-20 11:49:55 +0200629 return ret;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900630}
631
Kuninori Morimoto51aff912020-09-28 09:01:04 +0900632static int soc_pcm_components_close(struct snd_pcm_substream *substream,
633 int rollback)
Charles Keepax244e2932018-06-19 16:22:09 +0100634{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900635 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Charles Keepax244e2932018-06-19 16:22:09 +0100636 struct snd_soc_component *component;
Kuninori Morimotoe82ebff2020-02-10 12:14:26 +0900637 int i, r, ret = 0;
Charles Keepax244e2932018-06-19 16:22:09 +0100638
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900639 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto51aff912020-09-28 09:01:04 +0900640 r = snd_soc_component_close(component, substream, rollback);
Kuninori Morimotoe82ebff2020-02-10 12:14:26 +0900641 if (r < 0)
642 ret = r; /* use last ret */
643
Kuninori Morimoto51aff912020-09-28 09:01:04 +0900644 snd_soc_component_module_put_when_close(component, substream, rollback);
Charles Keepax244e2932018-06-19 16:22:09 +0100645 }
646
Kuninori Morimoto3672beb2019-07-26 13:50:07 +0900647 return ret;
Charles Keepax244e2932018-06-19 16:22:09 +0100648}
649
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900650static int soc_pcm_clean(struct snd_pcm_substream *substream, int rollback)
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900651{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900652 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900653 struct snd_soc_component *component;
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900654 struct snd_soc_dai *dai;
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900655 int i;
656
657 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
658
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900659 if (!rollback)
660 snd_soc_runtime_deactivate(rtd, substream->stream);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900661
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900662 for_each_rtd_dais(rtd, i, dai)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900663 snd_soc_dai_shutdown(dai, substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900664
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900665 snd_soc_link_shutdown(substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900666
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900667 soc_pcm_components_close(substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900668
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900669
670 mutex_unlock(&rtd->card->pcm_mutex);
671
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900672 snd_soc_pcm_component_pm_runtime_put(rtd, substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900673
674 for_each_rtd_components(rtd, i, component)
Kuninori Morimotob3dea622020-05-15 09:46:51 +0900675 if (!snd_soc_component_active(component))
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900676 pinctrl_pm_select_sleep_state(component->dev);
677
678 return 0;
679}
680
681/*
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900682 * Called by ALSA when a PCM substream is closed. Private data can be
683 * freed here. The cpu DAI, codec DAI, machine and components are also
684 * shutdown.
685 */
686static int soc_pcm_close(struct snd_pcm_substream *substream)
687{
688 return soc_pcm_clean(substream, 0);
689}
690
691/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100692 * Called by ALSA when a PCM substream is opened, the runtime->hw record is
693 * then initialized and any private data can be allocated. This also calls
Charles Keepaxef050be2018-04-24 16:39:02 +0100694 * startup for the cpu DAI, component, machine and codec DAI.
Liam Girdwoodddee6272011-06-09 14:45:53 +0100695 */
696static int soc_pcm_open(struct snd_pcm_substream *substream)
697{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900698 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100699 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000700 struct snd_soc_component *component;
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900701 struct snd_soc_dai *dai;
Kuninori Morimoto6fb89442021-03-09 10:07:48 +0900702 const char *codec_dai_name = soc_codec_dai_name(rtd);
703 const char *cpu_dai_name = soc_cpu_dai_name(rtd);
Charles Keepax244e2932018-06-19 16:22:09 +0100704 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100705
Kuninori Morimoto76c39e82020-01-10 11:36:13 +0900706 for_each_rtd_components(rtd, i, component)
707 pinctrl_pm_select_default_state(component->dev);
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000708
Kuninori Morimoto939a5cf2020-09-28 09:01:17 +0900709 ret = snd_soc_pcm_component_pm_runtime_get(rtd, substream);
710 if (ret < 0)
Kuninori Morimotocb2fce92020-10-01 10:32:48 +0900711 goto pm_err;
Mark Brownd6652ef2011-12-03 20:14:31 +0000712
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300713 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100714
Kuninori Morimoto5d9fa032020-02-10 12:14:45 +0900715 ret = soc_pcm_components_open(substream);
716 if (ret < 0)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900717 goto err;
Kuninori Morimoto5d9fa032020-02-10 12:14:45 +0900718
Kuninori Morimoto7cf3c5b2020-05-25 09:57:31 +0900719 ret = snd_soc_link_startup(substream);
Kuninori Morimotoa5e6c102020-05-25 09:57:19 +0900720 if (ret < 0)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900721 goto err;
Kuninori Morimoto5d9fa032020-02-10 12:14:45 +0900722
Liam Girdwoodddee6272011-06-09 14:45:53 +0100723 /* startup the audio subsystem */
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900724 for_each_rtd_dais(rtd, i, dai) {
725 ret = snd_soc_dai_startup(dai, substream);
Kuninori Morimotoce820142020-09-28 09:01:29 +0900726 if (ret < 0)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900727 goto err;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200728
729 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900730 dai->tx_mask = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200731 else
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900732 dai->rx_mask = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100733 }
734
Liam Girdwood01d75842012-04-25 12:12:49 +0100735 /* Dynamic PCM DAI links compat checks use dynamic capabilities */
736 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm)
737 goto dynamic;
738
Liam Girdwoodddee6272011-06-09 14:45:53 +0100739 /* Check that the codec and cpu DAIs are compatible */
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200740 soc_pcm_init_runtime_hw(substream);
741
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100742 if (soc_pcm_has_symmetry(substream))
743 runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
744
Liam Girdwoodddee6272011-06-09 14:45:53 +0100745 ret = -EINVAL;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100746 if (!runtime->hw.rates) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000747 printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n",
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800748 codec_dai_name, cpu_dai_name);
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900749 goto err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100750 }
751 if (!runtime->hw.formats) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000752 printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n",
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800753 codec_dai_name, cpu_dai_name);
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900754 goto err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100755 }
756 if (!runtime->hw.channels_min || !runtime->hw.channels_max ||
757 runtime->hw.channels_min > runtime->hw.channels_max) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000758 printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n",
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800759 codec_dai_name, cpu_dai_name);
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900760 goto err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100761 }
762
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200763 soc_pcm_apply_msb(substream);
Mark Brown58ba9b22012-01-16 18:38:51 +0000764
Liam Girdwoodddee6272011-06-09 14:45:53 +0100765 /* Symmetry only applies if we've already got an active stream. */
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900766 for_each_rtd_dais(rtd, i, dai) {
Kuninori Morimotof8fc9ec2021-03-09 10:07:42 +0900767 ret = soc_pcm_apply_symmetry(substream, dai);
768 if (ret != 0)
769 goto err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100770 }
771
Liam Girdwood103d84a2012-11-19 14:39:15 +0000772 pr_debug("ASoC: %s <-> %s info:\n",
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800773 codec_dai_name, cpu_dai_name);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000774 pr_debug("ASoC: rate mask 0x%x\n", runtime->hw.rates);
775 pr_debug("ASoC: min ch %d max ch %d\n", runtime->hw.channels_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100776 runtime->hw.channels_max);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000777 pr_debug("ASoC: min rate %d max rate %d\n", runtime->hw.rate_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100778 runtime->hw.rate_max);
Liam Girdwood01d75842012-04-25 12:12:49 +0100779dynamic:
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100780 snd_soc_runtime_activate(rtd, substream->stream);
Kuninori Morimoto8e7875a2020-10-01 14:07:41 +0900781 ret = 0;
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900782err:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300783 mutex_unlock(&rtd->card->pcm_mutex);
Kuninori Morimotocb2fce92020-10-01 10:32:48 +0900784pm_err:
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900785 if (ret < 0)
786 soc_pcm_clean(substream, 1);
Mark Brownd6652ef2011-12-03 20:14:31 +0000787
Liam Girdwoodddee6272011-06-09 14:45:53 +0100788 return ret;
789}
790
Curtis Malainey4bf2e382019-12-03 09:30:07 -0800791static void codec2codec_close_delayed_work(struct snd_soc_pcm_runtime *rtd)
Jerome Bruneta3420312019-07-25 18:59:47 +0200792{
793 /*
794 * Currently nothing to do for c2c links
795 * Since c2c links are internal nodes in the DAPM graph and
796 * don't interface with the outside world or application layer
797 * we don't have to do any special handling on close.
798 */
799}
800
Liam Girdwoodddee6272011-06-09 14:45:53 +0100801/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100802 * Called by ALSA when the PCM substream is prepared, can set format, sample
803 * rate, etc. This function is non atomic and can be called multiple times,
804 * it can refer to the runtime info.
805 */
806static int soc_pcm_prepare(struct snd_pcm_substream *substream)
807{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900808 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900809 struct snd_soc_dai *dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200810 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100811
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300812 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100813
Kuninori Morimoto7cf3c5b2020-05-25 09:57:31 +0900814 ret = snd_soc_link_prepare(substream);
Kuninori Morimotoa5e6c102020-05-25 09:57:19 +0900815 if (ret < 0)
Kuninori Morimoto44c1a752020-01-22 09:44:44 +0900816 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100817
Kuninori Morimoto4f395142020-06-04 17:06:58 +0900818 ret = snd_soc_pcm_component_prepare(substream);
819 if (ret < 0)
820 goto out;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000821
Kuninori Morimotod108c7f2020-04-24 08:14:53 +0900822 ret = snd_soc_pcm_dai_prepare(substream);
823 if (ret < 0) {
824 dev_err(rtd->dev, "ASoC: DAI prepare error: %d\n", ret);
825 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100826 }
827
828 /* cancel any delayed stream shutdown that is pending */
829 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600830 rtd->pop_wait) {
831 rtd->pop_wait = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100832 cancel_delayed_work(&rtd->delayed_work);
833 }
834
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000835 snd_soc_dapm_stream_event(rtd, substream->stream,
836 SND_SOC_DAPM_STREAM_START);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100837
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900838 for_each_rtd_dais(rtd, i, dai)
839 snd_soc_dai_digital_mute(dai, 0, substream->stream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100840
841out:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300842 mutex_unlock(&rtd->card->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100843 return ret;
844}
845
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200846static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params,
847 unsigned int mask)
848{
849 struct snd_interval *interval;
850 int channels = hweight_long(mask);
851
852 interval = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
853 interval->min = channels;
854 interval->max = channels;
855}
856
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900857static int soc_pcm_hw_clean(struct snd_pcm_substream *substream, int rollback)
Kuninori Morimotoab494362020-09-29 13:31:19 +0900858{
859 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
860 struct snd_soc_dai *dai;
861 int i;
862
863 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
864
865 /* clear the corresponding DAIs parameters when going to be inactive */
866 for_each_rtd_dais(rtd, i, dai) {
867 int active = snd_soc_dai_stream_active(dai, substream->stream);
868
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900869 if (snd_soc_dai_active(dai) == 1)
870 soc_pcm_set_dai_params(dai, NULL);
Kuninori Morimotoab494362020-09-29 13:31:19 +0900871
872 if (active == 1)
873 snd_soc_dai_digital_mute(dai, 1, substream->stream);
874 }
875
Ranjani Sridharana27b4212020-11-17 13:50:01 -0800876 /* run the stream event */
877 snd_soc_dapm_stream_stop(rtd, substream->stream);
878
Kuninori Morimotoab494362020-09-29 13:31:19 +0900879 /* free any machine hw params */
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900880 snd_soc_link_hw_free(substream, rollback);
Kuninori Morimotoab494362020-09-29 13:31:19 +0900881
882 /* free any component resources */
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900883 snd_soc_pcm_component_hw_free(substream, rollback);
Kuninori Morimotoab494362020-09-29 13:31:19 +0900884
885 /* now free hw params for the DAIs */
886 for_each_rtd_dais(rtd, i, dai) {
887 if (!snd_soc_dai_stream_valid(dai, substream->stream))
888 continue;
889
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900890 snd_soc_dai_hw_free(dai, substream, rollback);
Kuninori Morimotoab494362020-09-29 13:31:19 +0900891 }
892
893 mutex_unlock(&rtd->card->pcm_mutex);
894 return 0;
895}
896
897/*
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900898 * Frees resources allocated by hw_params, can be called multiple times
899 */
900static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
901{
902 return soc_pcm_hw_clean(substream, 0);
903}
904
905/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100906 * Called by ALSA when the hardware params are set by application. This
907 * function can also be called multiple times and can allocate buffers
908 * (using snd_pcm_lib_* ). It's non-atomic.
909 */
910static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
911 struct snd_pcm_hw_params *params)
912{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900913 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800914 struct snd_soc_dai *cpu_dai;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000915 struct snd_soc_dai *codec_dai;
Charles Keepax244e2932018-06-19 16:22:09 +0100916 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100917
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300918 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Shengjiu Wang5cca5952019-11-12 18:46:42 +0800919
920 ret = soc_pcm_params_symmetry(substream, params);
921 if (ret)
922 goto out;
923
Kuninori Morimoto7cf3c5b2020-05-25 09:57:31 +0900924 ret = snd_soc_link_hw_params(substream, params);
Kuninori Morimotoa5e6c102020-05-25 09:57:19 +0900925 if (ret < 0)
Kuninori Morimotode9ad992020-01-22 09:44:48 +0900926 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100927
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900928 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200929 struct snd_pcm_hw_params codec_params;
930
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200931 /*
932 * Skip CODECs which don't support the current stream type,
933 * the idea being that if a CODEC is not used for the currently
934 * set up transfer direction, it should not need to be
935 * configured, especially since the configuration used might
936 * not even be supported by that CODEC. There may be cases
937 * however where a CODEC needs to be set up although it is
938 * actually not being used for the transfer, e.g. if a
939 * capture-only CODEC is acting as an LRCLK and/or BCLK master
940 * for the DAI link including a playback-only CODEC.
941 * If this becomes necessary, we will have to augment the
942 * machine driver setup with information on how to act, so
943 * we can do the right thing here.
944 */
945 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
946 continue;
947
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200948 /* copy params for each codec */
949 codec_params = *params;
950
951 /* fixup params based on TDM slot masks */
Rander Wang570f18b2019-03-08 16:38:57 +0800952 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
953 codec_dai->tx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200954 soc_pcm_codec_params_fixup(&codec_params,
955 codec_dai->tx_mask);
Rander Wang570f18b2019-03-08 16:38:57 +0800956
957 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
958 codec_dai->rx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200959 soc_pcm_codec_params_fixup(&codec_params,
960 codec_dai->rx_mask);
961
Kuninori Morimotoaa6166c2019-07-22 10:33:04 +0900962 ret = snd_soc_dai_hw_params(codec_dai, substream,
963 &codec_params);
Benoit Cousson93e69582014-07-08 23:19:38 +0200964 if(ret < 0)
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900965 goto out;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200966
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900967 soc_pcm_set_dai_params(codec_dai, &codec_params);
Charles Keepax078a85f2019-01-31 13:30:18 +0000968 snd_soc_dapm_update_dai(substream, &codec_params, codec_dai);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100969 }
970
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900971 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800972 /*
973 * Skip CPUs which don't support the current stream
974 * type. See soc_pcm_init_runtime_hw() for more details
975 */
976 if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream))
977 continue;
978
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800979 ret = snd_soc_dai_hw_params(cpu_dai, substream, params);
980 if (ret < 0)
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900981 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100982
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800983 /* store the parameters for each DAI */
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900984 soc_pcm_set_dai_params(cpu_dai, params);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800985 snd_soc_dapm_update_dai(substream, params, cpu_dai);
986 }
Kuninori Morimotoca58221d2019-05-13 16:07:43 +0900987
Kuninori Morimoto3a36a642020-09-29 13:31:41 +0900988 ret = snd_soc_pcm_component_hw_params(substream, params);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100989out:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300990 mutex_unlock(&rtd->card->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100991
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900992 if (ret < 0)
993 soc_pcm_hw_clean(substream, 1);
Kuninori Morimotob8135862017-10-11 01:37:23 +0000994
Liam Girdwoodddee6272011-06-09 14:45:53 +0100995 return ret;
996}
997
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +0300998static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
999{
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001000 int ret = -EINVAL, _ret = 0;
1001 int rollback = 0;
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001002
1003 switch (cmd) {
1004 case SNDRV_PCM_TRIGGER_START:
1005 case SNDRV_PCM_TRIGGER_RESUME:
1006 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001007 ret = snd_soc_link_trigger(substream, cmd, 0);
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001008 if (ret < 0)
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001009 goto start_err;
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001010
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001011 ret = snd_soc_pcm_component_trigger(substream, cmd, 0);
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001012 if (ret < 0)
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001013 goto start_err;
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001014
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001015 ret = snd_soc_pcm_dai_trigger(substream, cmd, 0);
1016start_err:
1017 if (ret < 0)
1018 rollback = 1;
1019 }
1020
1021 if (rollback) {
1022 _ret = ret;
1023 switch (cmd) {
1024 case SNDRV_PCM_TRIGGER_START:
1025 cmd = SNDRV_PCM_TRIGGER_STOP;
1026 break;
1027 case SNDRV_PCM_TRIGGER_RESUME:
1028 cmd = SNDRV_PCM_TRIGGER_SUSPEND;
1029 break;
1030 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1031 cmd = SNDRV_PCM_TRIGGER_PAUSE_PUSH;
1032 break;
1033 }
1034 }
1035
1036 switch (cmd) {
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001037 case SNDRV_PCM_TRIGGER_STOP:
1038 case SNDRV_PCM_TRIGGER_SUSPEND:
1039 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001040 ret = snd_soc_pcm_dai_trigger(substream, cmd, rollback);
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001041 if (ret < 0)
1042 break;
1043
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001044 ret = snd_soc_pcm_component_trigger(substream, cmd, rollback);
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001045 if (ret < 0)
1046 break;
1047
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001048 ret = snd_soc_link_trigger(substream, cmd, rollback);
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001049 break;
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001050 }
1051
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001052 if (_ret)
1053 ret = _ret;
1054
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001055 return ret;
1056}
1057
Liam Girdwoodddee6272011-06-09 14:45:53 +01001058/*
1059 * soc level wrapper for pointer callback
Charles Keepaxef050be2018-04-24 16:39:02 +01001060 * If cpu_dai, codec_dai, component driver has the delay callback, then
Liam Girdwoodddee6272011-06-09 14:45:53 +01001061 * the runtime->delay will be updated accordingly.
1062 */
1063static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
1064{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001065 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001066 struct snd_soc_dai *cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001067 struct snd_soc_dai *codec_dai;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001068 struct snd_pcm_runtime *runtime = substream->runtime;
1069 snd_pcm_uframes_t offset = 0;
1070 snd_pcm_sframes_t delay = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001071 snd_pcm_sframes_t codec_delay = 0;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001072 snd_pcm_sframes_t cpu_delay = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001073 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001074
Akshu Agrawal9fb4c2bf2018-08-01 15:37:33 +05301075 /* clearing the previous total delay */
1076 runtime->delay = 0;
1077
Kuninori Morimoto0035e252019-07-26 13:51:47 +09001078 offset = snd_soc_pcm_component_pointer(substream);
Kuninori Morimotob8135862017-10-11 01:37:23 +00001079
Akshu Agrawal9fb4c2bf2018-08-01 15:37:33 +05301080 /* base delay if assigned in pointer callback */
1081 delay = runtime->delay;
Kuninori Morimotob8135862017-10-11 01:37:23 +00001082
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001083 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001084 cpu_delay = max(cpu_delay,
1085 snd_soc_dai_delay(cpu_dai, substream));
1086 }
1087 delay += cpu_delay;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001088
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001089 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Kuninori Morimoto1dea80d2019-07-22 10:34:09 +09001090 codec_delay = max(codec_delay,
1091 snd_soc_dai_delay(codec_dai, substream));
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001092 }
1093 delay += codec_delay;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001094
Liam Girdwoodddee6272011-06-09 14:45:53 +01001095 runtime->delay = delay;
1096
1097 return offset;
1098}
1099
Liam Girdwood01d75842012-04-25 12:12:49 +01001100/* connect a FE and BE */
1101static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
1102 struct snd_soc_pcm_runtime *be, int stream)
1103{
1104 struct snd_soc_dpcm *dpcm;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001105 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001106
1107 /* only add new dpcms */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001108 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001109 if (dpcm->be == be && dpcm->fe == fe)
1110 return 0;
1111 }
1112
1113 dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_KERNEL);
1114 if (!dpcm)
1115 return -ENOMEM;
1116
1117 dpcm->be = be;
1118 dpcm->fe = fe;
1119 be->dpcm[stream].runtime = fe->dpcm[stream].runtime;
1120 dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001121 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001122 list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients);
1123 list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001124 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001125
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001126 dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001127 stream ? "capture" : "playback", fe->dai_link->name,
1128 stream ? "<-" : "->", be->dai_link->name);
1129
Kuninori Morimoto154dae82020-02-19 15:57:06 +09001130 dpcm_create_debugfs_state(dpcm, stream);
1131
Liam Girdwood01d75842012-04-25 12:12:49 +01001132 return 1;
1133}
1134
1135/* reparent a BE onto another FE */
1136static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
1137 struct snd_soc_pcm_runtime *be, int stream)
1138{
1139 struct snd_soc_dpcm *dpcm;
1140 struct snd_pcm_substream *fe_substream, *be_substream;
1141
1142 /* reparent if BE is connected to other FEs */
1143 if (!be->dpcm[stream].users)
1144 return;
1145
1146 be_substream = snd_soc_dpcm_get_substream(be, stream);
1147
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00001148 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001149 if (dpcm->fe == fe)
1150 continue;
1151
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001152 dev_dbg(fe->dev, "reparent %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001153 stream ? "capture" : "playback",
1154 dpcm->fe->dai_link->name,
1155 stream ? "<-" : "->", dpcm->be->dai_link->name);
1156
1157 fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, stream);
1158 be_substream->runtime = fe_substream->runtime;
1159 break;
1160 }
1161}
1162
1163/* disconnect a BE and FE */
Liam Girdwood23607022014-01-17 17:03:55 +00001164void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001165{
1166 struct snd_soc_dpcm *dpcm, *d;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001167 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001168
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001169 for_each_dpcm_be_safe(fe, stream, dpcm, d) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001170 dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001171 stream ? "capture" : "playback",
1172 dpcm->be->dai_link->name);
1173
1174 if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE)
1175 continue;
1176
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001177 dev_dbg(fe->dev, "freed DSP %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001178 stream ? "capture" : "playback", fe->dai_link->name,
1179 stream ? "<-" : "->", dpcm->be->dai_link->name);
1180
1181 /* BEs still alive need new FE */
1182 dpcm_be_reparent(fe, dpcm->be, stream);
1183
Kuninori Morimoto154dae82020-02-19 15:57:06 +09001184 dpcm_remove_debugfs_state(dpcm);
1185
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001186 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001187 list_del(&dpcm->list_be);
1188 list_del(&dpcm->list_fe);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001189 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001190 kfree(dpcm);
1191 }
1192}
1193
1194/* get BE for DAI widget and stream */
1195static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
1196 struct snd_soc_dapm_widget *widget, int stream)
1197{
1198 struct snd_soc_pcm_runtime *be;
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001199 struct snd_soc_dapm_widget *w;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001200 struct snd_soc_dai *dai;
Mengdong Lin1a497982015-11-18 02:34:11 -05001201 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01001202
Liam Girdwood3c146462018-03-14 20:43:51 +00001203 dev_dbg(card->dev, "ASoC: find BE for widget %s\n", widget->name);
1204
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001205 for_each_card_rtds(card, be) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001206
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001207 if (!be->dai_link->no_pcm)
1208 continue;
Liam Girdwood35ea0652012-06-05 19:26:59 +01001209
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001210 for_each_rtd_dais(be, i, dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001211 w = snd_soc_dai_get_widget(dai, stream);
Liam Girdwood3c146462018-03-14 20:43:51 +00001212
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001213 dev_dbg(card->dev, "ASoC: try BE : %s\n",
1214 w ? w->name : "(not set)");
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001215
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001216 if (w == widget)
1217 return be;
1218 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001219 }
1220
Jerome Brunet9d6ee362020-02-19 12:50:48 +01001221 /* Widget provided is not a BE */
Liam Girdwood01d75842012-04-25 12:12:49 +01001222 return NULL;
1223}
1224
Liam Girdwood01d75842012-04-25 12:12:49 +01001225static int widget_in_list(struct snd_soc_dapm_widget_list *list,
1226 struct snd_soc_dapm_widget *widget)
1227{
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001228 struct snd_soc_dapm_widget *w;
Liam Girdwood01d75842012-04-25 12:12:49 +01001229 int i;
1230
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001231 for_each_dapm_widgets(list, i, w)
1232 if (widget == w)
Liam Girdwood01d75842012-04-25 12:12:49 +01001233 return 1;
Liam Girdwood01d75842012-04-25 12:12:49 +01001234
1235 return 0;
1236}
1237
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001238static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget,
1239 enum snd_soc_dapm_direction dir)
1240{
1241 struct snd_soc_card *card = widget->dapm->card;
1242 struct snd_soc_pcm_runtime *rtd;
Kuninori Morimotoc2cd8212020-02-17 17:27:48 +09001243 int stream;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001244
Kuninori Morimotoc2cd8212020-02-17 17:27:48 +09001245 /* adjust dir to stream */
1246 if (dir == SND_SOC_DAPM_DIR_OUT)
1247 stream = SNDRV_PCM_STREAM_PLAYBACK;
1248 else
1249 stream = SNDRV_PCM_STREAM_CAPTURE;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001250
Kuninori Morimoto027a4832020-02-17 17:27:53 +09001251 rtd = dpcm_get_be(card, widget, stream);
1252 if (rtd)
1253 return true;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001254
1255 return false;
1256}
1257
Liam Girdwood23607022014-01-17 17:03:55 +00001258int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001259 int stream, struct snd_soc_dapm_widget_list **list)
Liam Girdwood01d75842012-04-25 12:12:49 +01001260{
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09001261 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
Liam Girdwood01d75842012-04-25 12:12:49 +01001262 int paths;
1263
Bard Liao6e1276a2020-02-25 21:39:16 +08001264 if (fe->num_cpus > 1) {
1265 dev_err(fe->dev,
1266 "%s doesn't support Multi CPU yet\n", __func__);
1267 return -EINVAL;
1268 }
1269
Liam Girdwood01d75842012-04-25 12:12:49 +01001270 /* get number of valid DAI paths and their widgets */
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001271 paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list,
Sameer Pujaraa293772020-11-02 20:40:09 +05301272 fe->card->component_chaining ?
1273 NULL : dpcm_end_walk_at_be);
Liam Girdwood01d75842012-04-25 12:12:49 +01001274
Liam Girdwood103d84a2012-11-19 14:39:15 +00001275 dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths,
Liam Girdwood01d75842012-04-25 12:12:49 +01001276 stream ? "capture" : "playback");
1277
Liam Girdwood01d75842012-04-25 12:12:49 +01001278 return paths;
1279}
1280
Kuninori Morimoto52645e332020-02-19 15:56:52 +09001281void dpcm_path_put(struct snd_soc_dapm_widget_list **list)
1282{
1283 snd_soc_dapm_dai_free_widgets(list);
1284}
1285
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001286static bool dpcm_be_is_active(struct snd_soc_dpcm *dpcm, int stream,
1287 struct snd_soc_dapm_widget_list *list)
Liam Girdwood01d75842012-04-25 12:12:49 +01001288{
Liam Girdwood01d75842012-04-25 12:12:49 +01001289 struct snd_soc_dapm_widget *widget;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001290 struct snd_soc_dai *dai;
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001291 unsigned int i;
1292
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001293 /* is there a valid DAI widget for this BE */
1294 for_each_rtd_dais(dpcm->be, i, dai) {
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001295 widget = snd_soc_dai_get_widget(dai, stream);
1296
1297 /*
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001298 * The BE is pruned only if none of the dai
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001299 * widgets are in the active list.
1300 */
1301 if (widget && widget_in_list(list, widget))
1302 return true;
1303 }
1304
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001305 return false;
1306}
1307
1308static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
1309 struct snd_soc_dapm_widget_list **list_)
1310{
1311 struct snd_soc_dpcm *dpcm;
Liam Girdwood01d75842012-04-25 12:12:49 +01001312 int prune = 0;
1313
1314 /* Destroy any old FE <--> BE connections */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001315 for_each_dpcm_be(fe, stream, dpcm) {
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001316 if (dpcm_be_is_active(dpcm, stream, *list_))
Kuninori Morimotobed646d2019-10-15 12:59:38 +09001317 continue;
Liam Girdwood01d75842012-04-25 12:12:49 +01001318
Liam Girdwood103d84a2012-11-19 14:39:15 +00001319 dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001320 stream ? "capture" : "playback",
1321 dpcm->be->dai_link->name, fe->dai_link->name);
1322 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
Kuninori Morimotoa7e204442020-12-11 14:55:22 +09001323 dpcm_set_be_update_state(dpcm->be, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001324 prune++;
1325 }
1326
Liam Girdwood103d84a2012-11-19 14:39:15 +00001327 dev_dbg(fe->dev, "ASoC: found %d old BE paths for pruning\n", prune);
Liam Girdwood01d75842012-04-25 12:12:49 +01001328 return prune;
1329}
1330
1331static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
1332 struct snd_soc_dapm_widget_list **list_)
1333{
1334 struct snd_soc_card *card = fe->card;
1335 struct snd_soc_dapm_widget_list *list = *list_;
1336 struct snd_soc_pcm_runtime *be;
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001337 struct snd_soc_dapm_widget *widget;
Liam Girdwood01d75842012-04-25 12:12:49 +01001338 int i, new = 0, err;
1339
1340 /* Create any new FE <--> BE connections */
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001341 for_each_dapm_widgets(list, i, widget) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001342
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001343 switch (widget->id) {
Mark Brown46162742013-06-05 19:36:11 +01001344 case snd_soc_dapm_dai_in:
Koro Chenc5b85402015-07-06 10:02:10 +08001345 if (stream != SNDRV_PCM_STREAM_PLAYBACK)
1346 continue;
1347 break;
Mark Brown46162742013-06-05 19:36:11 +01001348 case snd_soc_dapm_dai_out:
Koro Chenc5b85402015-07-06 10:02:10 +08001349 if (stream != SNDRV_PCM_STREAM_CAPTURE)
1350 continue;
Mark Brown46162742013-06-05 19:36:11 +01001351 break;
1352 default:
Liam Girdwood01d75842012-04-25 12:12:49 +01001353 continue;
Mark Brown46162742013-06-05 19:36:11 +01001354 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001355
1356 /* is there a valid BE rtd for this widget */
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001357 be = dpcm_get_be(card, widget, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001358 if (!be) {
Shengjiu Wangb6eabd22021-02-08 16:12:45 +08001359 dev_dbg(fe->dev, "ASoC: no BE found for %s\n",
1360 widget->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001361 continue;
1362 }
1363
Liam Girdwood01d75842012-04-25 12:12:49 +01001364 /* don't connect if FE is not running */
Liam Girdwood23607022014-01-17 17:03:55 +00001365 if (!fe->dpcm[stream].runtime && !fe->fe_compr)
Liam Girdwood01d75842012-04-25 12:12:49 +01001366 continue;
1367
1368 /* newly connected FE and BE */
1369 err = dpcm_be_connect(fe, be, stream);
1370 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001371 dev_err(fe->dev, "ASoC: can't connect %s\n",
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001372 widget->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001373 break;
1374 } else if (err == 0) /* already connected */
1375 continue;
1376
1377 /* new */
Kuninori Morimotoa7e204442020-12-11 14:55:22 +09001378 dpcm_set_be_update_state(be, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001379 new++;
1380 }
1381
Liam Girdwood103d84a2012-11-19 14:39:15 +00001382 dev_dbg(fe->dev, "ASoC: found %d new BE paths\n", new);
Liam Girdwood01d75842012-04-25 12:12:49 +01001383 return new;
1384}
1385
1386/*
1387 * Find the corresponding BE DAIs that source or sink audio to this
1388 * FE substream.
1389 */
Liam Girdwood23607022014-01-17 17:03:55 +00001390int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
Liam Girdwood01d75842012-04-25 12:12:49 +01001391 int stream, struct snd_soc_dapm_widget_list **list, int new)
1392{
1393 if (new)
1394 return dpcm_add_paths(fe, stream, list);
1395 else
1396 return dpcm_prune_paths(fe, stream, list);
1397}
1398
Liam Girdwood23607022014-01-17 17:03:55 +00001399void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001400{
1401 struct snd_soc_dpcm *dpcm;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001402 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001403
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001404 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001405 for_each_dpcm_be(fe, stream, dpcm)
Kuninori Morimotoa7e204442020-12-11 14:55:22 +09001406 dpcm_set_be_update_state(dpcm->be, stream, SND_SOC_DPCM_UPDATE_NO);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001407 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001408}
1409
1410static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe,
1411 int stream)
1412{
1413 struct snd_soc_dpcm *dpcm;
1414
1415 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001416 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001417
1418 struct snd_soc_pcm_runtime *be = dpcm->be;
1419 struct snd_pcm_substream *be_substream =
1420 snd_soc_dpcm_get_substream(be, stream);
1421
1422 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001423 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001424 stream ? "capture" : "playback",
1425 be->dpcm[stream].state);
1426
1427 if (--be->dpcm[stream].users != 0)
1428 continue;
1429
1430 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1431 continue;
1432
1433 soc_pcm_close(be_substream);
1434 be_substream->runtime = NULL;
1435 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1436 }
1437}
1438
Liam Girdwood23607022014-01-17 17:03:55 +00001439int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001440{
1441 struct snd_soc_dpcm *dpcm;
1442 int err, count = 0;
1443
1444 /* only startup BE DAIs that are either sinks or sources to this FE DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001445 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001446
1447 struct snd_soc_pcm_runtime *be = dpcm->be;
1448 struct snd_pcm_substream *be_substream =
1449 snd_soc_dpcm_get_substream(be, stream);
1450
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001451 if (!be_substream) {
1452 dev_err(be->dev, "ASoC: no backend %s stream\n",
1453 stream ? "capture" : "playback");
1454 continue;
1455 }
1456
Liam Girdwood01d75842012-04-25 12:12:49 +01001457 /* is this op for this BE ? */
1458 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1459 continue;
1460
1461 /* first time the dpcm is open ? */
1462 if (be->dpcm[stream].users == DPCM_MAX_BE_USERS)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001463 dev_err(be->dev, "ASoC: too many users %s at open %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001464 stream ? "capture" : "playback",
1465 be->dpcm[stream].state);
1466
1467 if (be->dpcm[stream].users++ != 0)
1468 continue;
1469
1470 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
1471 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
1472 continue;
1473
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001474 dev_dbg(be->dev, "ASoC: open %s BE %s\n",
1475 stream ? "capture" : "playback", be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001476
1477 be_substream->runtime = be->dpcm[stream].runtime;
1478 err = soc_pcm_open(be_substream);
1479 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001480 dev_err(be->dev, "ASoC: BE open failed %d\n", err);
Liam Girdwood01d75842012-04-25 12:12:49 +01001481 be->dpcm[stream].users--;
1482 if (be->dpcm[stream].users < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001483 dev_err(be->dev, "ASoC: no users %s at unwind %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001484 stream ? "capture" : "playback",
1485 be->dpcm[stream].state);
1486
1487 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1488 goto unwind;
1489 }
1490
1491 be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1492 count++;
1493 }
1494
1495 return count;
1496
1497unwind:
1498 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001499 for_each_dpcm_be_rollback(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001500 struct snd_soc_pcm_runtime *be = dpcm->be;
1501 struct snd_pcm_substream *be_substream =
1502 snd_soc_dpcm_get_substream(be, stream);
1503
1504 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1505 continue;
1506
1507 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001508 dev_err(be->dev, "ASoC: no users %s at close %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001509 stream ? "capture" : "playback",
1510 be->dpcm[stream].state);
1511
1512 if (--be->dpcm[stream].users != 0)
1513 continue;
1514
1515 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1516 continue;
1517
1518 soc_pcm_close(be_substream);
1519 be_substream->runtime = NULL;
1520 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1521 }
1522
1523 return err;
1524}
1525
Kuninori Morimoto5f538982021-02-22 09:47:26 +09001526static void dpcm_runtime_setup_fe(struct snd_pcm_substream *substream)
1527{
1528 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
1529 struct snd_pcm_runtime *runtime = substream->runtime;
1530 struct snd_pcm_hardware *hw = &runtime->hw;
1531 struct snd_soc_dai *dai;
1532 int stream = substream->stream;
1533 int i;
1534
1535 soc_pcm_hw_init(hw);
1536
1537 for_each_rtd_cpu_dais(fe, i, dai) {
1538 struct snd_soc_pcm_stream *cpu_stream;
1539
1540 /*
1541 * Skip CPUs which don't support the current stream
1542 * type. See soc_pcm_init_runtime_hw() for more details
1543 */
1544 if (!snd_soc_dai_stream_valid(dai, stream))
1545 continue;
1546
1547 cpu_stream = snd_soc_dai_get_pcm_stream(dai, stream);
1548
1549 soc_pcm_hw_update_rate(hw, cpu_stream);
1550 soc_pcm_hw_update_chan(hw, cpu_stream);
1551 soc_pcm_hw_update_format(hw, cpu_stream);
1552 }
1553
1554}
1555
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001556static void dpcm_runtime_setup_be_format(struct snd_pcm_substream *substream)
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001557{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001558 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001559 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto4b260f42021-01-22 10:13:48 +09001560 struct snd_pcm_hardware *hw = &runtime->hw;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001561 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001562 struct snd_soc_dai *dai;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001563 int stream = substream->stream;
1564
1565 if (!fe->dai_link->dpcm_merged_format)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001566 return;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001567
1568 /*
1569 * It returns merged BE codec format
1570 * if FE want to use it (= dpcm_merged_format)
1571 */
1572
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001573 for_each_dpcm_be(fe, stream, dpcm) {
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001574 struct snd_soc_pcm_runtime *be = dpcm->be;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001575 struct snd_soc_pcm_stream *codec_stream;
1576 int i;
1577
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001578 for_each_rtd_codec_dais(be, i, dai) {
Jerome Brunet4febced2018-06-27 17:36:38 +02001579 /*
1580 * Skip CODECs which don't support the current stream
1581 * type. See soc_pcm_init_runtime_hw() for more details
1582 */
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001583 if (!snd_soc_dai_stream_valid(dai, stream))
Jerome Brunet4febced2018-06-27 17:36:38 +02001584 continue;
1585
Kuninori Morimotoacf253c2020-02-19 15:56:30 +09001586 codec_stream = snd_soc_dai_get_pcm_stream(dai, stream);
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001587
Kuninori Morimotodebc71f2021-02-04 08:52:04 +09001588 soc_pcm_hw_update_format(hw, codec_stream);
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001589 }
1590 }
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001591}
1592
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001593static void dpcm_runtime_setup_be_chan(struct snd_pcm_substream *substream)
Jiada Wangf4c277b2018-06-20 18:25:20 +09001594{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001595 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001596 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto4b260f42021-01-22 10:13:48 +09001597 struct snd_pcm_hardware *hw = &runtime->hw;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001598 struct snd_soc_dpcm *dpcm;
1599 int stream = substream->stream;
1600
1601 if (!fe->dai_link->dpcm_merged_chan)
1602 return;
1603
Jiada Wangf4c277b2018-06-20 18:25:20 +09001604 /*
1605 * It returns merged BE codec channel;
1606 * if FE want to use it (= dpcm_merged_chan)
1607 */
1608
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001609 for_each_dpcm_be(fe, stream, dpcm) {
Jiada Wangf4c277b2018-06-20 18:25:20 +09001610 struct snd_soc_pcm_runtime *be = dpcm->be;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001611 struct snd_soc_pcm_stream *codec_stream;
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001612 struct snd_soc_pcm_stream *cpu_stream;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001613 struct snd_soc_dai *dai;
1614 int i;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001615
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001616 for_each_rtd_cpu_dais(be, i, dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001617 /*
1618 * Skip CPUs which don't support the current stream
1619 * type. See soc_pcm_init_runtime_hw() for more details
1620 */
1621 if (!snd_soc_dai_stream_valid(dai, stream))
1622 continue;
1623
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001624 cpu_stream = snd_soc_dai_get_pcm_stream(dai, stream);
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001625
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +09001626 soc_pcm_hw_update_chan(hw, cpu_stream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001627 }
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001628
1629 /*
1630 * chan min/max cannot be enforced if there are multiple CODEC
1631 * DAIs connected to a single CPU DAI, use CPU DAI's directly
1632 */
1633 if (be->num_codecs == 1) {
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09001634 codec_stream = snd_soc_dai_get_pcm_stream(asoc_rtd_to_codec(be, 0), stream);
Jiada Wangf4c277b2018-06-20 18:25:20 +09001635
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +09001636 soc_pcm_hw_update_chan(hw, codec_stream);
Jiada Wangf4c277b2018-06-20 18:25:20 +09001637 }
1638 }
1639}
1640
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001641static void dpcm_runtime_setup_be_rate(struct snd_pcm_substream *substream)
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001642{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001643 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001644 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto4b260f42021-01-22 10:13:48 +09001645 struct snd_pcm_hardware *hw = &runtime->hw;
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001646 struct snd_soc_dpcm *dpcm;
1647 int stream = substream->stream;
1648
1649 if (!fe->dai_link->dpcm_merged_rate)
1650 return;
1651
1652 /*
1653 * It returns merged BE codec channel;
1654 * if FE want to use it (= dpcm_merged_chan)
1655 */
1656
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001657 for_each_dpcm_be(fe, stream, dpcm) {
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001658 struct snd_soc_pcm_runtime *be = dpcm->be;
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001659 struct snd_soc_pcm_stream *pcm;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001660 struct snd_soc_dai *dai;
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001661 int i;
1662
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001663 for_each_rtd_dais(be, i, dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001664 /*
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001665 * Skip DAIs which don't support the current stream
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001666 * type. See soc_pcm_init_runtime_hw() for more details
1667 */
1668 if (!snd_soc_dai_stream_valid(dai, stream))
1669 continue;
1670
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001671 pcm = snd_soc_dai_get_pcm_stream(dai, stream);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001672
Kuninori Morimotof6c04af2021-02-04 08:50:31 +09001673 soc_pcm_hw_update_rate(hw, pcm);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001674 }
1675 }
1676}
1677
PC Liao906c7d62015-12-11 11:33:51 +08001678static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
1679 int stream)
1680{
1681 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001682 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001683 struct snd_soc_dai *fe_cpu_dai;
PC Liao906c7d62015-12-11 11:33:51 +08001684 int err;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001685 int i;
PC Liao906c7d62015-12-11 11:33:51 +08001686
1687 /* apply symmetry for FE */
1688 if (soc_pcm_has_symmetry(fe_substream))
1689 fe_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1690
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001691 for_each_rtd_cpu_dais (fe, i, fe_cpu_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001692 /* Symmetry only applies if we've got an active stream. */
Kuninori Morimotof8fc9ec2021-03-09 10:07:42 +09001693 err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai);
1694 if (err < 0)
1695 return err;
PC Liao906c7d62015-12-11 11:33:51 +08001696 }
1697
1698 /* apply symmetry for BE */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001699 for_each_dpcm_be(fe, stream, dpcm) {
PC Liao906c7d62015-12-11 11:33:51 +08001700 struct snd_soc_pcm_runtime *be = dpcm->be;
1701 struct snd_pcm_substream *be_substream =
1702 snd_soc_dpcm_get_substream(be, stream);
Jerome Brunet6246f282019-04-01 15:03:54 +02001703 struct snd_soc_pcm_runtime *rtd;
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001704 struct snd_soc_dai *dai;
PC Liao906c7d62015-12-11 11:33:51 +08001705
Jerome Brunet6246f282019-04-01 15:03:54 +02001706 /* A backend may not have the requested substream */
1707 if (!be_substream)
1708 continue;
1709
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001710 rtd = asoc_substream_to_rtd(be_substream);
Jeeja KPf1176612016-09-06 14:17:55 +05301711 if (rtd->dai_link->be_hw_params_fixup)
1712 continue;
1713
PC Liao906c7d62015-12-11 11:33:51 +08001714 if (soc_pcm_has_symmetry(be_substream))
1715 be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1716
1717 /* Symmetry only applies if we've got an active stream. */
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001718 for_each_rtd_dais(rtd, i, dai) {
Kuninori Morimotof8fc9ec2021-03-09 10:07:42 +09001719 err = soc_pcm_apply_symmetry(fe_substream, dai);
1720 if (err < 0)
1721 return err;
PC Liao906c7d62015-12-11 11:33:51 +08001722 }
1723 }
1724
1725 return 0;
1726}
1727
Liam Girdwood01d75842012-04-25 12:12:49 +01001728static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
1729{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001730 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001731 int stream = fe_substream->stream, ret = 0;
1732
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001733 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001734
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09001735 ret = dpcm_be_dai_startup(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001736 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001737 dev_err(fe->dev,"ASoC: failed to start some BEs %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001738 goto be_err;
1739 }
1740
Liam Girdwood103d84a2012-11-19 14:39:15 +00001741 dev_dbg(fe->dev, "ASoC: open FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001742
1743 /* start the DAI frontend */
1744 ret = soc_pcm_open(fe_substream);
1745 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001746 dev_err(fe->dev,"ASoC: failed to start FE %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001747 goto unwind;
1748 }
1749
1750 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1751
Kuninori Morimoto4fe28462021-02-22 09:47:36 +09001752 dpcm_runtime_setup_fe(fe_substream);
1753
1754 dpcm_runtime_setup_be_format(fe_substream);
1755 dpcm_runtime_setup_be_chan(fe_substream);
1756 dpcm_runtime_setup_be_rate(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001757
PC Liao906c7d62015-12-11 11:33:51 +08001758 ret = dpcm_apply_symmetry(fe_substream, stream);
Kuninori Morimoto8a01fbf2020-03-06 10:09:59 +09001759 if (ret < 0)
PC Liao906c7d62015-12-11 11:33:51 +08001760 dev_err(fe->dev, "ASoC: failed to apply dpcm symmetry %d\n",
1761 ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001762
1763unwind:
Kuninori Morimoto8a01fbf2020-03-06 10:09:59 +09001764 if (ret < 0)
1765 dpcm_be_dai_startup_unwind(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001766be_err:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001767 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001768 return ret;
1769}
1770
Liam Girdwood23607022014-01-17 17:03:55 +00001771int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001772{
1773 struct snd_soc_dpcm *dpcm;
1774
1775 /* only shutdown BEs that are either sinks or sources to this FE DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001776 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001777
1778 struct snd_soc_pcm_runtime *be = dpcm->be;
1779 struct snd_pcm_substream *be_substream =
1780 snd_soc_dpcm_get_substream(be, stream);
1781
1782 /* is this op for this BE ? */
1783 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1784 continue;
1785
1786 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001787 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001788 stream ? "capture" : "playback",
1789 be->dpcm[stream].state);
1790
1791 if (--be->dpcm[stream].users != 0)
1792 continue;
1793
1794 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Kai Chieh Chuang9c0ac702018-05-28 10:18:18 +08001795 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) {
1796 soc_pcm_hw_free(be_substream);
1797 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1798 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001799
Liam Girdwood103d84a2012-11-19 14:39:15 +00001800 dev_dbg(be->dev, "ASoC: close BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001801 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001802
1803 soc_pcm_close(be_substream);
1804 be_substream->runtime = NULL;
1805
1806 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1807 }
1808 return 0;
1809}
1810
1811static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
1812{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001813 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001814 int stream = substream->stream;
1815
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001816 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001817
1818 /* shutdown the BEs */
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09001819 dpcm_be_dai_shutdown(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001820
Liam Girdwood103d84a2012-11-19 14:39:15 +00001821 dev_dbg(fe->dev, "ASoC: close FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001822
1823 /* now shutdown the frontend */
1824 soc_pcm_close(substream);
1825
Ranjani Sridharanbb9dd3c2020-12-02 11:33:43 -08001826 /* run the stream stop event */
1827 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
1828
Liam Girdwood01d75842012-04-25 12:12:49 +01001829 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001830 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001831 return 0;
1832}
1833
Liam Girdwood23607022014-01-17 17:03:55 +00001834int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001835{
1836 struct snd_soc_dpcm *dpcm;
1837
1838 /* only hw_params backends that are either sinks or sources
1839 * to this frontend DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001840 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001841
1842 struct snd_soc_pcm_runtime *be = dpcm->be;
1843 struct snd_pcm_substream *be_substream =
1844 snd_soc_dpcm_get_substream(be, stream);
1845
1846 /* is this op for this BE ? */
1847 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1848 continue;
1849
1850 /* only free hw when no longer used - check all FEs */
1851 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1852 continue;
1853
Qiao Zhou36fba622014-12-03 10:13:43 +08001854 /* do not free hw if this BE is used by other FE */
1855 if (be->dpcm[stream].users > 1)
1856 continue;
1857
Liam Girdwood01d75842012-04-25 12:12:49 +01001858 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1859 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
1860 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Patrick Lai08b27842012-12-19 19:36:02 -08001861 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
Vinod Koul5e82d2b2016-02-01 22:26:40 +05301862 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
1863 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
Liam Girdwood01d75842012-04-25 12:12:49 +01001864 continue;
1865
Liam Girdwood103d84a2012-11-19 14:39:15 +00001866 dev_dbg(be->dev, "ASoC: hw_free BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001867 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001868
1869 soc_pcm_hw_free(be_substream);
1870
1871 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1872 }
1873
1874 return 0;
1875}
1876
Mark Brown45c0a182012-05-09 21:46:27 +01001877static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001878{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001879 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001880 int err, stream = substream->stream;
1881
1882 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001883 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001884
Liam Girdwood103d84a2012-11-19 14:39:15 +00001885 dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001886
1887 /* call hw_free on the frontend */
1888 err = soc_pcm_hw_free(substream);
1889 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001890 dev_err(fe->dev,"ASoC: hw_free FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001891 fe->dai_link->name);
1892
1893 /* only hw_params backends that are either sinks or sources
1894 * to this frontend DAI */
1895 err = dpcm_be_dai_hw_free(fe, stream);
Pierre-Louis Bossart61456212021-02-18 16:19:19 -06001896 if (err < 0)
1897 dev_err(fe->dev, "ASoC: hw_free BE failed %d\n", err);
Liam Girdwood01d75842012-04-25 12:12:49 +01001898
1899 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001900 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001901
1902 mutex_unlock(&fe->card->mutex);
1903 return 0;
1904}
1905
Liam Girdwood23607022014-01-17 17:03:55 +00001906int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001907{
1908 struct snd_soc_dpcm *dpcm;
1909 int ret;
1910
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001911 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001912
1913 struct snd_soc_pcm_runtime *be = dpcm->be;
1914 struct snd_pcm_substream *be_substream =
1915 snd_soc_dpcm_get_substream(be, stream);
1916
1917 /* is this op for this BE ? */
1918 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1919 continue;
1920
Liam Girdwood01d75842012-04-25 12:12:49 +01001921 /* copy params for each dpcm */
1922 memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params,
1923 sizeof(struct snd_pcm_hw_params));
1924
1925 /* perform any hw_params fixups */
Kuninori Morimoto0cbbf8a2020-05-25 09:57:36 +09001926 ret = snd_soc_link_be_hw_params_fixup(be, &dpcm->hw_params);
1927 if (ret < 0)
1928 goto unwind;
Liam Girdwood01d75842012-04-25 12:12:49 +01001929
Libin Yangae061d22019-04-19 09:53:12 +08001930 /* copy the fixed-up hw params for BE dai */
1931 memcpy(&be->dpcm[stream].hw_params, &dpcm->hw_params,
1932 sizeof(struct snd_pcm_hw_params));
1933
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00001934 /* only allow hw_params() if no connected FEs are running */
1935 if (!snd_soc_dpcm_can_be_params(fe, be, stream))
1936 continue;
1937
1938 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
1939 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1940 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE))
1941 continue;
1942
1943 dev_dbg(be->dev, "ASoC: hw_params BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001944 be->dai_link->name);
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00001945
Liam Girdwood01d75842012-04-25 12:12:49 +01001946 ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params);
1947 if (ret < 0) {
1948 dev_err(dpcm->be->dev,
Liam Girdwood103d84a2012-11-19 14:39:15 +00001949 "ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001950 goto unwind;
1951 }
1952
1953 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
1954 }
1955 return 0;
1956
1957unwind:
1958 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001959 for_each_dpcm_be_rollback(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001960 struct snd_soc_pcm_runtime *be = dpcm->be;
1961 struct snd_pcm_substream *be_substream =
1962 snd_soc_dpcm_get_substream(be, stream);
1963
1964 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1965 continue;
1966
1967 /* only allow hw_free() if no connected FEs are running */
1968 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1969 continue;
1970
1971 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
1972 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1973 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
1974 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
1975 continue;
1976
1977 soc_pcm_hw_free(be_substream);
1978 }
1979
1980 return ret;
1981}
1982
Mark Brown45c0a182012-05-09 21:46:27 +01001983static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
1984 struct snd_pcm_hw_params *params)
Liam Girdwood01d75842012-04-25 12:12:49 +01001985{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001986 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001987 int ret, stream = substream->stream;
1988
1989 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001990 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001991
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09001992 memcpy(&fe->dpcm[stream].hw_params, params,
Liam Girdwood01d75842012-04-25 12:12:49 +01001993 sizeof(struct snd_pcm_hw_params));
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09001994 ret = dpcm_be_dai_hw_params(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001995 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001996 dev_err(fe->dev,"ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001997 goto out;
1998 }
1999
Liam Girdwood103d84a2012-11-19 14:39:15 +00002000 dev_dbg(fe->dev, "ASoC: hw_params FE %s rate %d chan %x fmt %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002001 fe->dai_link->name, params_rate(params),
2002 params_channels(params), params_format(params));
2003
2004 /* call hw_params on the frontend */
2005 ret = soc_pcm_hw_params(substream, params);
2006 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002007 dev_err(fe->dev,"ASoC: hw_params FE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002008 dpcm_be_dai_hw_free(fe, stream);
2009 } else
2010 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2011
2012out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002013 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002014 mutex_unlock(&fe->card->mutex);
2015 return ret;
2016}
2017
Liam Girdwood23607022014-01-17 17:03:55 +00002018int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
Mark Brown45c0a182012-05-09 21:46:27 +01002019 int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002020{
2021 struct snd_soc_dpcm *dpcm;
2022 int ret = 0;
2023
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002024 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002025
2026 struct snd_soc_pcm_runtime *be = dpcm->be;
2027 struct snd_pcm_substream *be_substream =
2028 snd_soc_dpcm_get_substream(be, stream);
2029
2030 /* is this op for this BE ? */
2031 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2032 continue;
2033
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002034 dev_dbg(be->dev, "ASoC: trigger BE %s cmd %d\n",
2035 be->dai_link->name, cmd);
2036
Liam Girdwood01d75842012-04-25 12:12:49 +01002037 switch (cmd) {
2038 case SNDRV_PCM_TRIGGER_START:
2039 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
이경택21fca8b2020-04-01 10:04:21 +09002040 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
2041 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Liam Girdwood01d75842012-04-25 12:12:49 +01002042 continue;
2043
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002044 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002045 if (ret)
2046 return ret;
2047
2048 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2049 break;
2050 case SNDRV_PCM_TRIGGER_RESUME:
2051 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
2052 continue;
2053
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002054 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002055 if (ret)
2056 return ret;
2057
2058 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2059 break;
2060 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2061 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
2062 continue;
2063
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002064 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002065 if (ret)
2066 return ret;
2067
2068 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2069 break;
2070 case SNDRV_PCM_TRIGGER_STOP:
이경택21fca8b2020-04-01 10:04:21 +09002071 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) &&
2072 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Liam Girdwood01d75842012-04-25 12:12:49 +01002073 continue;
2074
2075 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2076 continue;
2077
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002078 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002079 if (ret)
2080 return ret;
2081
2082 be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2083 break;
2084 case SNDRV_PCM_TRIGGER_SUSPEND:
Nicolin Chen868a6ca2014-05-12 20:12:05 +08002085 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
Liam Girdwood01d75842012-04-25 12:12:49 +01002086 continue;
2087
2088 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2089 continue;
2090
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002091 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002092 if (ret)
2093 return ret;
2094
2095 be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND;
2096 break;
2097 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2098 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2099 continue;
2100
2101 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2102 continue;
2103
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002104 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002105 if (ret)
2106 return ret;
2107
2108 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2109 break;
2110 }
2111 }
2112
2113 return ret;
2114}
2115EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
2116
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002117static int dpcm_dai_trigger_fe_be(struct snd_pcm_substream *substream,
2118 int cmd, bool fe_first)
2119{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002120 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002121 int ret;
2122
2123 /* call trigger on the frontend before the backend. */
2124 if (fe_first) {
2125 dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n",
2126 fe->dai_link->name, cmd);
2127
2128 ret = soc_pcm_trigger(substream, cmd);
2129 if (ret < 0)
2130 return ret;
2131
2132 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2133 return ret;
2134 }
2135
2136 /* call trigger on the frontend after the backend. */
2137 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2138 if (ret < 0)
2139 return ret;
2140
2141 dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n",
2142 fe->dai_link->name, cmd);
2143
2144 ret = soc_pcm_trigger(substream, cmd);
2145
2146 return ret;
2147}
2148
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002149static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002150{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002151 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002152 int stream = substream->stream;
2153 int ret = 0;
Liam Girdwood01d75842012-04-25 12:12:49 +01002154 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
2155
2156 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
2157
2158 switch (trigger) {
2159 case SND_SOC_DPCM_TRIGGER_PRE:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002160 switch (cmd) {
2161 case SNDRV_PCM_TRIGGER_START:
2162 case SNDRV_PCM_TRIGGER_RESUME:
2163 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Cezary Rojewski4c22b802020-10-26 11:01:29 +01002164 case SNDRV_PCM_TRIGGER_DRAIN:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002165 ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
2166 break;
2167 case SNDRV_PCM_TRIGGER_STOP:
2168 case SNDRV_PCM_TRIGGER_SUSPEND:
2169 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2170 ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
2171 break;
2172 default:
2173 ret = -EINVAL;
2174 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002175 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002176 break;
2177 case SND_SOC_DPCM_TRIGGER_POST:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002178 switch (cmd) {
2179 case SNDRV_PCM_TRIGGER_START:
2180 case SNDRV_PCM_TRIGGER_RESUME:
2181 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Cezary Rojewski4c22b802020-10-26 11:01:29 +01002182 case SNDRV_PCM_TRIGGER_DRAIN:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002183 ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
2184 break;
2185 case SNDRV_PCM_TRIGGER_STOP:
2186 case SNDRV_PCM_TRIGGER_SUSPEND:
2187 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2188 ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
2189 break;
2190 default:
2191 ret = -EINVAL;
2192 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002193 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002194 break;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002195 case SND_SOC_DPCM_TRIGGER_BESPOKE:
2196 /* bespoke trigger() - handles both FE and BEs */
2197
Liam Girdwood103d84a2012-11-19 14:39:15 +00002198 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd %d\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002199 fe->dai_link->name, cmd);
2200
Kuninori Morimoto308193582020-04-24 08:15:09 +09002201 ret = snd_soc_pcm_dai_bespoke_trigger(substream, cmd);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002202 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002203 default:
Liam Girdwood103d84a2012-11-19 14:39:15 +00002204 dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd,
Liam Girdwood01d75842012-04-25 12:12:49 +01002205 fe->dai_link->name);
2206 ret = -EINVAL;
2207 goto out;
2208 }
2209
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002210 if (ret < 0) {
2211 dev_err(fe->dev, "ASoC: trigger FE cmd: %d failed: %d\n",
2212 cmd, ret);
2213 goto out;
2214 }
2215
Liam Girdwood01d75842012-04-25 12:12:49 +01002216 switch (cmd) {
2217 case SNDRV_PCM_TRIGGER_START:
2218 case SNDRV_PCM_TRIGGER_RESUME:
2219 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2220 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2221 break;
2222 case SNDRV_PCM_TRIGGER_STOP:
2223 case SNDRV_PCM_TRIGGER_SUSPEND:
Liam Girdwood01d75842012-04-25 12:12:49 +01002224 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2225 break;
Patrick Lai9f169b92016-12-31 22:44:39 -08002226 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2227 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2228 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002229 }
2230
2231out:
2232 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
2233 return ret;
2234}
2235
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002236static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
2237{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002238 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002239 int stream = substream->stream;
2240
2241 /* if FE's runtime_update is already set, we're in race;
2242 * process this trigger later at exit
2243 */
2244 if (fe->dpcm[stream].runtime_update != SND_SOC_DPCM_UPDATE_NO) {
2245 fe->dpcm[stream].trigger_pending = cmd + 1;
2246 return 0; /* delayed, assuming it's successful */
2247 }
2248
2249 /* we're alone, let's trigger */
2250 return dpcm_fe_dai_do_trigger(substream, cmd);
2251}
2252
Liam Girdwood23607022014-01-17 17:03:55 +00002253int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002254{
2255 struct snd_soc_dpcm *dpcm;
2256 int ret = 0;
2257
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002258 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002259
2260 struct snd_soc_pcm_runtime *be = dpcm->be;
2261 struct snd_pcm_substream *be_substream =
2262 snd_soc_dpcm_get_substream(be, stream);
2263
2264 /* is this op for this BE ? */
2265 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2266 continue;
2267
2268 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
Koro Chen95f444d2015-10-28 10:15:34 +08002269 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
Libin Yang5087a8f2019-05-08 10:32:41 +08002270 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND) &&
2271 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Liam Girdwood01d75842012-04-25 12:12:49 +01002272 continue;
2273
Liam Girdwood103d84a2012-11-19 14:39:15 +00002274 dev_dbg(be->dev, "ASoC: prepare BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002275 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002276
2277 ret = soc_pcm_prepare(be_substream);
2278 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002279 dev_err(be->dev, "ASoC: backend prepare failed %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002280 ret);
2281 break;
2282 }
2283
2284 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2285 }
2286 return ret;
2287}
2288
Mark Brown45c0a182012-05-09 21:46:27 +01002289static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002290{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002291 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002292 int stream = substream->stream, ret = 0;
2293
2294 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2295
Liam Girdwood103d84a2012-11-19 14:39:15 +00002296 dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002297
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002298 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002299
2300 /* there is no point preparing this FE if there are no BEs */
2301 if (list_empty(&fe->dpcm[stream].be_clients)) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002302 dev_err(fe->dev, "ASoC: no backend DAIs enabled for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002303 fe->dai_link->name);
2304 ret = -EINVAL;
2305 goto out;
2306 }
2307
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09002308 ret = dpcm_be_dai_prepare(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002309 if (ret < 0)
2310 goto out;
2311
2312 /* call prepare on the frontend */
2313 ret = soc_pcm_prepare(substream);
2314 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002315 dev_err(fe->dev,"ASoC: prepare FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002316 fe->dai_link->name);
2317 goto out;
2318 }
2319
Liam Girdwood01d75842012-04-25 12:12:49 +01002320 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2321
2322out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002323 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002324 mutex_unlock(&fe->card->mutex);
2325
2326 return ret;
2327}
2328
Liam Girdwood618dae12012-04-25 12:12:51 +01002329static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
2330{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002331 struct snd_pcm_substream *substream =
2332 snd_soc_dpcm_get_substream(fe, stream);
2333 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01002334 int err;
Liam Girdwood01d75842012-04-25 12:12:49 +01002335
Liam Girdwood103d84a2012-11-19 14:39:15 +00002336 dev_dbg(fe->dev, "ASoC: runtime %s close on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002337 stream ? "capture" : "playback", fe->dai_link->name);
2338
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002339 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2340 /* call bespoke trigger - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002341 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002342 fe->dai_link->name);
2343
Kuninori Morimoto308193582020-04-24 08:15:09 +09002344 err = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002345 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002346 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002347 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002348 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002349 fe->dai_link->name);
2350
2351 err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
2352 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002353 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002354 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002355
2356 err = dpcm_be_dai_hw_free(fe, stream);
2357 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002358 dev_err(fe->dev,"ASoC: hw_free FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002359
2360 err = dpcm_be_dai_shutdown(fe, stream);
2361 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002362 dev_err(fe->dev,"ASoC: shutdown FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002363
2364 /* run the stream event for each BE */
2365 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2366
2367 return 0;
2368}
2369
2370static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
2371{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002372 struct snd_pcm_substream *substream =
2373 snd_soc_dpcm_get_substream(fe, stream);
Liam Girdwood618dae12012-04-25 12:12:51 +01002374 struct snd_soc_dpcm *dpcm;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002375 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Souptick Joarder4eeed5f2021-01-09 09:15:01 +05302376 int ret = 0;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002377 unsigned long flags;
Liam Girdwood618dae12012-04-25 12:12:51 +01002378
Liam Girdwood103d84a2012-11-19 14:39:15 +00002379 dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002380 stream ? "capture" : "playback", fe->dai_link->name);
2381
2382 /* Only start the BE if the FE is ready */
2383 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
朱灿灿2c138282020-12-25 16:42:46 +08002384 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE) {
2385 dev_err(fe->dev, "ASoC: FE %s is not ready %d\n",
2386 fe->dai_link->name, fe->dpcm[stream].state);
Dan Carpentere91b65b2021-01-11 12:50:21 +03002387 ret = -EINVAL;
朱灿灿2c138282020-12-25 16:42:46 +08002388 goto disconnect;
2389 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002390
2391 /* startup must always be called for new BEs */
2392 ret = dpcm_be_dai_startup(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002393 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002394 goto disconnect;
Liam Girdwood618dae12012-04-25 12:12:51 +01002395
2396 /* keep going if FE state is > open */
2397 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN)
2398 return 0;
2399
2400 ret = dpcm_be_dai_hw_params(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002401 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002402 goto close;
Liam Girdwood618dae12012-04-25 12:12:51 +01002403
2404 /* keep going if FE state is > hw_params */
2405 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS)
2406 return 0;
2407
2408
2409 ret = dpcm_be_dai_prepare(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002410 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002411 goto hw_free;
Liam Girdwood618dae12012-04-25 12:12:51 +01002412
2413 /* run the stream event for each BE */
2414 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2415
2416 /* keep going if FE state is > prepare */
2417 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE ||
2418 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP)
2419 return 0;
2420
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002421 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2422 /* call trigger on the frontend - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002423 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002424 fe->dai_link->name);
Liam Girdwood618dae12012-04-25 12:12:51 +01002425
Kuninori Morimoto308193582020-04-24 08:15:09 +09002426 ret = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002427 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002428 dev_err(fe->dev,"ASoC: bespoke trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002429 goto hw_free;
2430 }
2431 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002432 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002433 fe->dai_link->name);
2434
2435 ret = dpcm_be_dai_trigger(fe, stream,
2436 SNDRV_PCM_TRIGGER_START);
2437 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002438 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002439 goto hw_free;
2440 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002441 }
2442
2443 return 0;
2444
2445hw_free:
2446 dpcm_be_dai_hw_free(fe, stream);
2447close:
2448 dpcm_be_dai_shutdown(fe, stream);
2449disconnect:
朱灿灿2c138282020-12-25 16:42:46 +08002450 /* disconnect any pending BEs */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002451 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002452 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood618dae12012-04-25 12:12:51 +01002453 struct snd_soc_pcm_runtime *be = dpcm->be;
朱灿灿2c138282020-12-25 16:42:46 +08002454
2455 /* is this op for this BE ? */
2456 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2457 continue;
2458
2459 if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE ||
2460 be->dpcm[stream].state == SND_SOC_DPCM_STATE_NEW)
2461 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
Liam Girdwood618dae12012-04-25 12:12:51 +01002462 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002463 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood618dae12012-04-25 12:12:51 +01002464
2465 return ret;
2466}
2467
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002468static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
2469{
2470 struct snd_soc_dapm_widget_list *list;
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002471 int stream;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002472 int count, paths;
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002473 int ret;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002474
Pierre-Louis Bossart96bf62f2020-06-12 15:35:07 -05002475 if (!fe->dai_link->dynamic)
2476 return 0;
2477
Bard Liao6e1276a2020-02-25 21:39:16 +08002478 if (fe->num_cpus > 1) {
2479 dev_err(fe->dev,
2480 "%s doesn't support Multi CPU yet\n", __func__);
2481 return -EINVAL;
2482 }
2483
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002484 /* only check active links */
Kuninori Morimotob3dea622020-05-15 09:46:51 +09002485 if (!snd_soc_dai_active(asoc_rtd_to_cpu(fe, 0)))
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002486 return 0;
2487
2488 /* DAPM sync will call this to update DSP paths */
2489 dev_dbg(fe->dev, "ASoC: DPCM %s runtime update for FE %s\n",
2490 new ? "new" : "old", fe->dai_link->name);
2491
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002492 for_each_pcm_streams(stream) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002493
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002494 /* skip if FE doesn't have playback/capture capability */
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002495 if (!snd_soc_dai_stream_valid(asoc_rtd_to_cpu(fe, 0), stream) ||
2496 !snd_soc_dai_stream_valid(asoc_rtd_to_codec(fe, 0), stream))
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002497 continue;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002498
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002499 /* skip if FE isn't currently playing/capturing */
Kuninori Morimotob3dea622020-05-15 09:46:51 +09002500 if (!snd_soc_dai_stream_active(asoc_rtd_to_cpu(fe, 0), stream) ||
2501 !snd_soc_dai_stream_active(asoc_rtd_to_codec(fe, 0), stream))
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002502 continue;
2503
2504 paths = dpcm_path_get(fe, stream, &list);
2505 if (paths < 0) {
2506 dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
2507 fe->dai_link->name,
2508 stream == SNDRV_PCM_STREAM_PLAYBACK ?
2509 "playback" : "capture");
2510 return paths;
2511 }
2512
2513 /* update any playback/capture paths */
2514 count = dpcm_process_paths(fe, stream, &list, new);
2515 if (count) {
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002516 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002517 if (new)
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002518 ret = dpcm_run_update_startup(fe, stream);
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002519 else
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002520 ret = dpcm_run_update_shutdown(fe, stream);
2521 if (ret < 0)
2522 dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n");
2523 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002524
2525 dpcm_clear_pending_state(fe, stream);
2526 dpcm_be_disconnect(fe, stream);
2527 }
2528
2529 dpcm_path_put(&list);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002530 }
2531
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002532 return 0;
2533}
2534
Liam Girdwood618dae12012-04-25 12:12:51 +01002535/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
2536 * any DAI links.
2537 */
Guennadi Liakhovetskif17a1472020-03-12 10:52:14 +01002538int snd_soc_dpcm_runtime_update(struct snd_soc_card *card)
Liam Girdwood618dae12012-04-25 12:12:51 +01002539{
Mengdong Lin1a497982015-11-18 02:34:11 -05002540 struct snd_soc_pcm_runtime *fe;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002541 int ret = 0;
Liam Girdwood618dae12012-04-25 12:12:51 +01002542
Liam Girdwood618dae12012-04-25 12:12:51 +01002543 mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002544 /* shutdown all old paths first */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002545 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002546 ret = soc_dpcm_fe_runtime_update(fe, 0);
2547 if (ret)
2548 goto out;
Liam Girdwood618dae12012-04-25 12:12:51 +01002549 }
2550
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002551 /* bring new paths up */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002552 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002553 ret = soc_dpcm_fe_runtime_update(fe, 1);
2554 if (ret)
2555 goto out;
2556 }
2557
2558out:
Liam Girdwood618dae12012-04-25 12:12:51 +01002559 mutex_unlock(&card->mutex);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002560 return ret;
Liam Girdwood618dae12012-04-25 12:12:51 +01002561}
Guennadi Liakhovetskif17a1472020-03-12 10:52:14 +01002562EXPORT_SYMBOL_GPL(snd_soc_dpcm_runtime_update);
Liam Girdwood01d75842012-04-25 12:12:49 +01002563
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002564static void dpcm_fe_dai_cleanup(struct snd_pcm_substream *fe_substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002565{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002566 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002567 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002568 int stream = fe_substream->stream;
Kuninori Morimoto30fca262020-03-06 10:09:44 +09002569
2570 /* mark FE's links ready to prune */
2571 for_each_dpcm_be(fe, stream, dpcm)
2572 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2573
2574 dpcm_be_disconnect(fe, stream);
2575
2576 fe->dpcm[stream].runtime = NULL;
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002577}
2578
2579static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
2580{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002581 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002582 int ret;
2583
2584 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2585 ret = dpcm_fe_dai_shutdown(fe_substream);
2586
2587 dpcm_fe_dai_cleanup(fe_substream);
2588
Kuninori Morimoto30fca262020-03-06 10:09:44 +09002589 mutex_unlock(&fe->card->mutex);
2590 return ret;
2591}
2592
Liam Girdwood01d75842012-04-25 12:12:49 +01002593static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
2594{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002595 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002596 struct snd_soc_dapm_widget_list *list;
2597 int ret;
2598 int stream = fe_substream->stream;
2599
2600 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2601 fe->dpcm[stream].runtime = fe_substream->runtime;
2602
Qiao Zhou8f70e512014-09-10 17:54:07 +08002603 ret = dpcm_path_get(fe, stream, &list);
2604 if (ret < 0) {
Kuninori Morimotocae06eb2020-02-17 17:28:11 +09002605 goto open_end;
Qiao Zhou8f70e512014-09-10 17:54:07 +08002606 } else if (ret == 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002607 dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002608 fe->dai_link->name, stream ? "capture" : "playback");
Liam Girdwood01d75842012-04-25 12:12:49 +01002609 }
2610
2611 /* calculate valid and active FE <-> BE dpcms */
2612 dpcm_process_paths(fe, stream, &list, 1);
2613
2614 ret = dpcm_fe_dai_startup(fe_substream);
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002615 if (ret < 0)
2616 dpcm_fe_dai_cleanup(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002617
2618 dpcm_clear_pending_state(fe, stream);
2619 dpcm_path_put(&list);
Kuninori Morimotocae06eb2020-02-17 17:28:11 +09002620open_end:
Liam Girdwood01d75842012-04-25 12:12:49 +01002621 mutex_unlock(&fe->card->mutex);
2622 return ret;
2623}
2624
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002625static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd,
2626 int *playback, int *capture)
Liam Girdwoodddee6272011-06-09 14:45:53 +01002627{
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002628 struct snd_soc_dai *codec_dai;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002629 struct snd_soc_dai *cpu_dai;
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002630 int stream;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002631 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002632
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002633 if (rtd->dai_link->dynamic && rtd->num_cpus > 1) {
2634 dev_err(rtd->dev,
2635 "DPCM doesn't support Multi CPU for Front-Ends yet\n");
2636 return -EINVAL;
2637 }
Stephan Gerhold9b5db052020-04-15 12:49:28 +02002638
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002639 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
2640 if (rtd->dai_link->dpcm_playback) {
2641 stream = SNDRV_PCM_STREAM_PLAYBACK;
2642
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002643 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
2644 if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002645 *playback = 1;
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002646 break;
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002647 }
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002648 }
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002649 if (!*playback) {
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002650 dev_err(rtd->card->dev,
2651 "No CPU DAIs support playback for stream %s\n",
2652 rtd->dai_link->stream_name);
2653 return -EINVAL;
2654 }
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002655 }
2656 if (rtd->dai_link->dpcm_capture) {
2657 stream = SNDRV_PCM_STREAM_CAPTURE;
2658
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002659 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
2660 if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002661 *capture = 1;
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002662 break;
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002663 }
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002664 }
2665
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002666 if (!*capture) {
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002667 dev_err(rtd->card->dev,
2668 "No CPU DAIs support capture for stream %s\n",
2669 rtd->dai_link->stream_name);
2670 return -EINVAL;
2671 }
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002672 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002673 } else {
Jerome Bruneta3420312019-07-25 18:59:47 +02002674 /* Adapt stream for codec2codec links */
Stephan Gerholda4877a62020-02-18 11:38:24 +01002675 int cpu_capture = rtd->dai_link->params ?
2676 SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
2677 int cpu_playback = rtd->dai_link->params ?
2678 SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
Jerome Bruneta3420312019-07-25 18:59:47 +02002679
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09002680 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002681 if (rtd->num_cpus == 1) {
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002682 cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002683 } else if (rtd->num_cpus == rtd->num_codecs) {
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002684 cpu_dai = asoc_rtd_to_cpu(rtd, i);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002685 } else {
2686 dev_err(rtd->card->dev,
2687 "N cpus to M codecs link is not supported yet\n");
2688 return -EINVAL;
2689 }
2690
Kuninori Morimoto467fece2019-07-22 10:36:16 +09002691 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
Stephan Gerholda4877a62020-02-18 11:38:24 +01002692 snd_soc_dai_stream_valid(cpu_dai, cpu_playback))
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002693 *playback = 1;
Kuninori Morimoto467fece2019-07-22 10:36:16 +09002694 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
Stephan Gerholda4877a62020-02-18 11:38:24 +01002695 snd_soc_dai_stream_valid(cpu_dai, cpu_capture))
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002696 *capture = 1;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002697 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002698 }
Sangsu Parka5002312012-01-02 17:15:10 +09002699
Fabio Estevamd6bead02013-08-29 10:32:13 -03002700 if (rtd->dai_link->playback_only) {
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002701 *playback = 1;
2702 *capture = 0;
Fabio Estevamd6bead02013-08-29 10:32:13 -03002703 }
2704
2705 if (rtd->dai_link->capture_only) {
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002706 *playback = 0;
2707 *capture = 1;
Fabio Estevamd6bead02013-08-29 10:32:13 -03002708 }
2709
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002710 return 0;
2711}
2712
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002713static int soc_create_pcm(struct snd_pcm **pcm,
2714 struct snd_soc_pcm_runtime *rtd,
2715 int playback, int capture, int num)
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002716{
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002717 char new_name[64];
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002718 int ret;
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002719
Liam Girdwood01d75842012-04-25 12:12:49 +01002720 /* create the PCM */
Jerome Bruneta3420312019-07-25 18:59:47 +02002721 if (rtd->dai_link->params) {
2722 snprintf(new_name, sizeof(new_name), "codec2codec(%s)",
2723 rtd->dai_link->stream_name);
2724
2725 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002726 playback, capture, pcm);
Jerome Bruneta3420312019-07-25 18:59:47 +02002727 } else if (rtd->dai_link->no_pcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002728 snprintf(new_name, sizeof(new_name), "(%s)",
2729 rtd->dai_link->stream_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002730
Liam Girdwood01d75842012-04-25 12:12:49 +01002731 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002732 playback, capture, pcm);
Liam Girdwood01d75842012-04-25 12:12:49 +01002733 } else {
2734 if (rtd->dai_link->dynamic)
2735 snprintf(new_name, sizeof(new_name), "%s (*)",
2736 rtd->dai_link->stream_name);
2737 else
2738 snprintf(new_name, sizeof(new_name), "%s %s-%d",
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002739 rtd->dai_link->stream_name,
Kuninori Morimoto6fb89442021-03-09 10:07:48 +09002740 soc_codec_dai_name(rtd), num);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002741
Liam Girdwood01d75842012-04-25 12:12:49 +01002742 ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002743 capture, pcm);
Liam Girdwood01d75842012-04-25 12:12:49 +01002744 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01002745 if (ret < 0) {
Pierre-Louis Bossart799827a2020-06-12 15:40:49 -05002746 dev_err(rtd->card->dev, "ASoC: can't create pcm %s for dailink %s: %d\n",
2747 new_name, rtd->dai_link->name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002748 return ret;
2749 }
Liam Girdwood103d84a2012-11-19 14:39:15 +00002750 dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002751
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002752 return 0;
2753}
2754
2755/* create a new pcm */
2756int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
2757{
2758 struct snd_soc_component *component;
2759 struct snd_pcm *pcm;
2760 int ret = 0, playback = 0, capture = 0;
2761 int i;
2762
2763 ret = soc_get_playback_capture(rtd, &playback, &capture);
2764 if (ret < 0)
2765 return ret;
2766
2767 ret = soc_create_pcm(&pcm, rtd, playback, capture, num);
2768 if (ret < 0)
2769 return ret;
2770
Liam Girdwoodddee6272011-06-09 14:45:53 +01002771 /* DAPM dai link stream work */
Jerome Bruneta3420312019-07-25 18:59:47 +02002772 if (rtd->dai_link->params)
Curtis Malainey4bf2e382019-12-03 09:30:07 -08002773 rtd->close_delayed_work_func = codec2codec_close_delayed_work;
Jerome Bruneta3420312019-07-25 18:59:47 +02002774 else
Kuninori Morimoto83f94a22020-01-10 11:36:17 +09002775 rtd->close_delayed_work_func = snd_soc_close_delayed_work;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002776
2777 rtd->pcm = pcm;
Kuninori Morimotoe04e7b82021-01-22 10:13:32 +09002778 pcm->nonatomic = rtd->dai_link->nonatomic;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002779 pcm->private_data = rtd;
Liam Girdwood01d75842012-04-25 12:12:49 +01002780
Jerome Bruneta3420312019-07-25 18:59:47 +02002781 if (rtd->dai_link->no_pcm || rtd->dai_link->params) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002782 if (playback)
2783 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
2784 if (capture)
2785 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
2786 goto out;
2787 }
2788
2789 /* ASoC PCM operations */
2790 if (rtd->dai_link->dynamic) {
2791 rtd->ops.open = dpcm_fe_dai_open;
2792 rtd->ops.hw_params = dpcm_fe_dai_hw_params;
2793 rtd->ops.prepare = dpcm_fe_dai_prepare;
2794 rtd->ops.trigger = dpcm_fe_dai_trigger;
2795 rtd->ops.hw_free = dpcm_fe_dai_hw_free;
2796 rtd->ops.close = dpcm_fe_dai_close;
2797 rtd->ops.pointer = soc_pcm_pointer;
2798 } else {
2799 rtd->ops.open = soc_pcm_open;
2800 rtd->ops.hw_params = soc_pcm_hw_params;
2801 rtd->ops.prepare = soc_pcm_prepare;
2802 rtd->ops.trigger = soc_pcm_trigger;
2803 rtd->ops.hw_free = soc_pcm_hw_free;
2804 rtd->ops.close = soc_pcm_close;
2805 rtd->ops.pointer = soc_pcm_pointer;
2806 }
2807
Kuninori Morimoto613fb502020-01-10 11:35:21 +09002808 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto2b544dd2019-10-15 12:59:31 +09002809 const struct snd_soc_component_driver *drv = component->driver;
Kuninori Morimotob8135862017-10-11 01:37:23 +00002810
Takashi Iwai3b1c9522019-11-21 20:07:08 +01002811 if (drv->ioctl)
2812 rtd->ops.ioctl = snd_soc_pcm_component_ioctl;
Takashi Iwai1e5ddb62019-11-21 20:07:09 +01002813 if (drv->sync_stop)
2814 rtd->ops.sync_stop = snd_soc_pcm_component_sync_stop;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002815 if (drv->copy_user)
Kuninori Morimoto82d81f52019-07-26 13:51:56 +09002816 rtd->ops.copy_user = snd_soc_pcm_component_copy_user;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002817 if (drv->page)
Kuninori Morimoto9c712e42019-07-26 13:52:00 +09002818 rtd->ops.page = snd_soc_pcm_component_page;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002819 if (drv->mmap)
Kuninori Morimoto205875e2019-07-26 13:52:04 +09002820 rtd->ops.mmap = snd_soc_pcm_component_mmap;
Kuninori Morimotob8135862017-10-11 01:37:23 +00002821 }
2822
Liam Girdwoodddee6272011-06-09 14:45:53 +01002823 if (playback)
Liam Girdwood01d75842012-04-25 12:12:49 +01002824 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002825
2826 if (capture)
Liam Girdwood01d75842012-04-25 12:12:49 +01002827 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002828
Kuninori Morimotob2b2afb2019-11-18 10:50:32 +09002829 ret = snd_soc_pcm_component_new(rtd);
Kuninori Morimoto74842912019-07-26 13:52:08 +09002830 if (ret < 0) {
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002831 dev_err(rtd->dev, "ASoC: pcm constructor failed for dailink %s: %d\n",
2832 rtd->dai_link->name, ret);
Kuninori Morimoto74842912019-07-26 13:52:08 +09002833 return ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002834 }
Johan Hovoldc641e5b2017-07-12 17:55:29 +02002835
Takashi Iwai3d21ef02019-01-11 15:58:39 +01002836 pcm->no_device_suspend = true;
Liam Girdwood01d75842012-04-25 12:12:49 +01002837out:
Pierre-Louis Bossart1d5cd522020-06-12 15:40:50 -05002838 dev_dbg(rtd->card->dev, "%s <-> %s mapping ok\n",
Kuninori Morimoto6fb89442021-03-09 10:07:48 +09002839 soc_codec_dai_name(rtd), soc_cpu_dai_name(rtd));
Liam Girdwoodddee6272011-06-09 14:45:53 +01002840 return ret;
2841}
Liam Girdwood01d75842012-04-25 12:12:49 +01002842
2843/* is the current PCM operation for this FE ? */
2844int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream)
2845{
2846 if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE)
2847 return 1;
2848 return 0;
2849}
2850EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update);
2851
2852/* is the current PCM operation for this BE ? */
2853int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
2854 struct snd_soc_pcm_runtime *be, int stream)
2855{
2856 if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) ||
2857 ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) &&
2858 be->dpcm[stream].runtime_update))
2859 return 1;
2860 return 0;
2861}
2862EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update);
2863
2864/* get the substream for this BE */
2865struct snd_pcm_substream *
2866 snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream)
2867{
2868 return be->pcm->streams[stream].substream;
2869}
2870EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream);
2871
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002872static int snd_soc_dpcm_check_state(struct snd_soc_pcm_runtime *fe,
2873 struct snd_soc_pcm_runtime *be,
2874 int stream,
2875 const enum snd_soc_dpcm_state *states,
2876 int num_states)
Liam Girdwood01d75842012-04-25 12:12:49 +01002877{
2878 struct snd_soc_dpcm *dpcm;
2879 int state;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002880 int ret = 1;
2881 unsigned long flags;
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002882 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01002883
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002884 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00002885 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002886
2887 if (dpcm->fe == fe)
2888 continue;
2889
2890 state = dpcm->fe->dpcm[stream].state;
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002891 for (i = 0; i < num_states; i++) {
2892 if (state == states[i]) {
2893 ret = 0;
2894 break;
2895 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002896 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002897 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002898 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01002899
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002900 /* it's safe to do this BE DAI */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002901 return ret;
Liam Girdwood01d75842012-04-25 12:12:49 +01002902}
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002903
2904/*
2905 * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE
2906 * are not running, paused or suspended for the specified stream direction.
2907 */
2908int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
2909 struct snd_soc_pcm_runtime *be, int stream)
2910{
2911 const enum snd_soc_dpcm_state state[] = {
2912 SND_SOC_DPCM_STATE_START,
2913 SND_SOC_DPCM_STATE_PAUSED,
2914 SND_SOC_DPCM_STATE_SUSPEND,
2915 };
2916
2917 return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
2918}
Liam Girdwood01d75842012-04-25 12:12:49 +01002919EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop);
2920
2921/*
2922 * We can only change hw params a BE DAI if any of it's FE are not prepared,
2923 * running, paused or suspended for the specified stream direction.
2924 */
2925int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
2926 struct snd_soc_pcm_runtime *be, int stream)
2927{
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002928 const enum snd_soc_dpcm_state state[] = {
2929 SND_SOC_DPCM_STATE_START,
2930 SND_SOC_DPCM_STATE_PAUSED,
2931 SND_SOC_DPCM_STATE_SUSPEND,
2932 SND_SOC_DPCM_STATE_PREPARE,
2933 };
Liam Girdwood01d75842012-04-25 12:12:49 +01002934
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002935 return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
Liam Girdwood01d75842012-04-25 12:12:49 +01002936}
2937EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);