blob: 9b5ab7a05f6528c2b4ea65e6cca4563dd6309436 [file] [log] [blame]
Kuninori Morimotoed517582018-07-02 06:22:44 +00001// SPDX-License-Identifier: GPL-2.0+
2//
3// soc-pcm.c -- ALSA SoC PCM
4//
5// Copyright 2005 Wolfson Microelectronics PLC.
6// Copyright 2005 Openedhand Ltd.
7// Copyright (C) 2010 Slimlogic Ltd.
8// Copyright (C) 2010 Texas Instruments Inc.
9//
10// Authors: Liam Girdwood <lrg@ti.com>
11// Mark Brown <broonie@opensource.wolfsonmicro.com>
Liam Girdwoodddee6272011-06-09 14:45:53 +010012
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/delay.h>
Nicolin Chen988e8cc2013-11-04 14:57:31 +080016#include <linux/pinctrl/consumer.h>
Mark Brownd6652ef2011-12-03 20:14:31 +000017#include <linux/pm_runtime.h>
Liam Girdwoodddee6272011-06-09 14:45:53 +010018#include <linux/slab.h>
19#include <linux/workqueue.h>
Liam Girdwood01d75842012-04-25 12:12:49 +010020#include <linux/export.h>
Liam Girdwoodf86dcef2012-04-25 12:12:50 +010021#include <linux/debugfs.h>
Liam Girdwoodddee6272011-06-09 14:45:53 +010022#include <sound/core.h>
23#include <sound/pcm.h>
24#include <sound/pcm_params.h>
25#include <sound/soc.h>
Liam Girdwood01d75842012-04-25 12:12:49 +010026#include <sound/soc-dpcm.h>
Kuninori Morimotoa5e6c102020-05-25 09:57:19 +090027#include <sound/soc-link.h>
Liam Girdwoodddee6272011-06-09 14:45:53 +010028#include <sound/initval.h>
29
Liam Girdwood01d75842012-04-25 12:12:49 +010030#define DPCM_MAX_BE_USERS 8
31
Kuninori Morimotoc3212822020-02-19 15:56:57 +090032#ifdef CONFIG_DEBUG_FS
33static const char *dpcm_state_string(enum snd_soc_dpcm_state state)
34{
35 switch (state) {
36 case SND_SOC_DPCM_STATE_NEW:
37 return "new";
38 case SND_SOC_DPCM_STATE_OPEN:
39 return "open";
40 case SND_SOC_DPCM_STATE_HW_PARAMS:
41 return "hw_params";
42 case SND_SOC_DPCM_STATE_PREPARE:
43 return "prepare";
44 case SND_SOC_DPCM_STATE_START:
45 return "start";
46 case SND_SOC_DPCM_STATE_STOP:
47 return "stop";
48 case SND_SOC_DPCM_STATE_SUSPEND:
49 return "suspend";
50 case SND_SOC_DPCM_STATE_PAUSED:
51 return "paused";
52 case SND_SOC_DPCM_STATE_HW_FREE:
53 return "hw_free";
54 case SND_SOC_DPCM_STATE_CLOSE:
55 return "close";
56 }
57
58 return "unknown";
59}
60
61static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
62 int stream, char *buf, size_t size)
63{
64 struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params;
65 struct snd_soc_dpcm *dpcm;
66 ssize_t offset = 0;
67 unsigned long flags;
68
69 /* FE state */
Takashi Iwaid0c9abb2020-03-10 17:36:25 +010070 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +090071 "[%s - %s]\n", fe->dai_link->name,
72 stream ? "Capture" : "Playback");
73
Takashi Iwaid0c9abb2020-03-10 17:36:25 +010074 offset += scnprintf(buf + offset, size - offset, "State: %s\n",
Kuninori Morimotoc3212822020-02-19 15:56:57 +090075 dpcm_state_string(fe->dpcm[stream].state));
76
77 if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
78 (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
Takashi Iwaid0c9abb2020-03-10 17:36:25 +010079 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +090080 "Hardware Params: "
81 "Format = %s, Channels = %d, Rate = %d\n",
82 snd_pcm_format_name(params_format(params)),
83 params_channels(params),
84 params_rate(params));
85
86 /* BEs state */
Takashi Iwaid0c9abb2020-03-10 17:36:25 +010087 offset += scnprintf(buf + offset, size - offset, "Backends:\n");
Kuninori Morimotoc3212822020-02-19 15:56:57 +090088
89 if (list_empty(&fe->dpcm[stream].be_clients)) {
Takashi Iwaid0c9abb2020-03-10 17:36:25 +010090 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +090091 " No active DSP links\n");
92 goto out;
93 }
94
95 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
96 for_each_dpcm_be(fe, stream, dpcm) {
97 struct snd_soc_pcm_runtime *be = dpcm->be;
98 params = &dpcm->hw_params;
99
Takashi Iwaid0c9abb2020-03-10 17:36:25 +0100100 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900101 "- %s\n", be->dai_link->name);
102
Takashi Iwaid0c9abb2020-03-10 17:36:25 +0100103 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900104 " State: %s\n",
105 dpcm_state_string(be->dpcm[stream].state));
106
107 if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
108 (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
Takashi Iwaid0c9abb2020-03-10 17:36:25 +0100109 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900110 " Hardware Params: "
111 "Format = %s, Channels = %d, Rate = %d\n",
112 snd_pcm_format_name(params_format(params)),
113 params_channels(params),
114 params_rate(params));
115 }
116 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
117out:
118 return offset;
119}
120
121static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf,
122 size_t count, loff_t *ppos)
123{
124 struct snd_soc_pcm_runtime *fe = file->private_data;
125 ssize_t out_count = PAGE_SIZE, offset = 0, ret = 0;
126 int stream;
127 char *buf;
128
Bard Liao6e1276a2020-02-25 21:39:16 +0800129 if (fe->num_cpus > 1) {
130 dev_err(fe->dev,
131 "%s doesn't support Multi CPU yet\n", __func__);
132 return -EINVAL;
133 }
134
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900135 buf = kmalloc(out_count, GFP_KERNEL);
136 if (!buf)
137 return -ENOMEM;
138
139 for_each_pcm_streams(stream)
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900140 if (snd_soc_dai_stream_valid(asoc_rtd_to_cpu(fe, 0), stream))
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900141 offset += dpcm_show_state(fe, stream,
142 buf + offset,
143 out_count - offset);
144
145 ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
146
147 kfree(buf);
148 return ret;
149}
150
151static const struct file_operations dpcm_state_fops = {
152 .open = simple_open,
153 .read = dpcm_state_read_file,
154 .llseek = default_llseek,
155};
156
157void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
158{
159 if (!rtd->dai_link)
160 return;
161
162 if (!rtd->dai_link->dynamic)
163 return;
164
165 if (!rtd->card->debugfs_card_root)
166 return;
167
168 rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name,
169 rtd->card->debugfs_card_root);
170
171 debugfs_create_file("state", 0444, rtd->debugfs_dpcm_root,
172 rtd, &dpcm_state_fops);
173}
Kuninori Morimoto154dae82020-02-19 15:57:06 +0900174
175static void dpcm_create_debugfs_state(struct snd_soc_dpcm *dpcm, int stream)
176{
177 char *name;
178
179 name = kasprintf(GFP_KERNEL, "%s:%s", dpcm->be->dai_link->name,
180 stream ? "capture" : "playback");
181 if (name) {
182 dpcm->debugfs_state = debugfs_create_dir(
183 name, dpcm->fe->debugfs_dpcm_root);
184 debugfs_create_u32("state", 0644, dpcm->debugfs_state,
185 &dpcm->state);
186 kfree(name);
187 }
188}
189
190static void dpcm_remove_debugfs_state(struct snd_soc_dpcm *dpcm)
191{
192 debugfs_remove_recursive(dpcm->debugfs_state);
193}
194
195#else
196static inline void dpcm_create_debugfs_state(struct snd_soc_dpcm *dpcm,
197 int stream)
198{
199}
200
201static inline void dpcm_remove_debugfs_state(struct snd_soc_dpcm *dpcm)
202{
203}
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900204#endif
205
Kuninori Morimoto9c6d7f92020-12-11 14:55:16 +0900206/* Set FE's runtime_update state; the state is protected via PCM stream lock
207 * for avoiding the race with trigger callback.
208 * If the state is unset and a trigger is pending while the previous operation,
209 * process the pending trigger action here.
210 */
211static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
212static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
213 int stream, enum snd_soc_dpcm_update state)
214{
215 struct snd_pcm_substream *substream =
216 snd_soc_dpcm_get_substream(fe, stream);
217
218 snd_pcm_stream_lock_irq(substream);
219 if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) {
220 dpcm_fe_dai_do_trigger(substream,
221 fe->dpcm[stream].trigger_pending - 1);
222 fe->dpcm[stream].trigger_pending = 0;
223 }
224 fe->dpcm[stream].runtime_update = state;
225 snd_pcm_stream_unlock_irq(substream);
226}
227
Kuninori Morimotoa7e204442020-12-11 14:55:22 +0900228static void dpcm_set_be_update_state(struct snd_soc_pcm_runtime *be,
229 int stream, enum snd_soc_dpcm_update state)
230{
231 be->dpcm[stream].runtime_update = state;
232}
233
Kuninori Morimotod9051d82020-05-15 09:46:21 +0900234/**
235 * snd_soc_runtime_action() - Increment/Decrement active count for
236 * PCM runtime components
237 * @rtd: ASoC PCM runtime that is activated
238 * @stream: Direction of the PCM stream
Colton Lewisb6d6e9e2020-06-26 05:40:24 +0000239 * @action: Activate stream if 1. Deactivate if -1.
Kuninori Morimotod9051d82020-05-15 09:46:21 +0900240 *
241 * Increments/Decrements the active count for all the DAIs and components
242 * attached to a PCM runtime.
243 * Should typically be called when a stream is opened.
244 *
245 * Must be called with the rtd->card->pcm_mutex being held
246 */
247void snd_soc_runtime_action(struct snd_soc_pcm_runtime *rtd,
248 int stream, int action)
Kuninori Morimoto7a5aaba2020-02-10 12:14:12 +0900249{
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900250 struct snd_soc_dai *dai;
Kuninori Morimoto7a5aaba2020-02-10 12:14:12 +0900251 int i;
252
253 lockdep_assert_held(&rtd->card->pcm_mutex);
254
Kuninori Morimotodc829102020-05-15 09:46:27 +0900255 for_each_rtd_dais(rtd, i, dai)
256 snd_soc_dai_action(dai, stream, action);
Kuninori Morimoto7a5aaba2020-02-10 12:14:12 +0900257}
Kuninori Morimotod9051d82020-05-15 09:46:21 +0900258EXPORT_SYMBOL_GPL(snd_soc_runtime_action);
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100259
260/**
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100261 * snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay
262 * @rtd: The ASoC PCM runtime that should be checked.
263 *
264 * This function checks whether the power down delay should be ignored for a
265 * specific PCM runtime. Returns true if the delay is 0, if it the DAI link has
266 * been configured to ignore the delay, or if none of the components benefits
267 * from having the delay.
268 */
269bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
270{
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000271 struct snd_soc_component *component;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200272 bool ignore = true;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900273 int i;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200274
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100275 if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
276 return true;
277
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900278 for_each_rtd_components(rtd, i, component)
Kuninori Morimoto72c38182018-01-19 05:21:19 +0000279 ignore &= !component->driver->use_pmdown_time;
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000280
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000281 return ignore;
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100282}
283
284/**
Lars-Peter Clausen90996f42013-05-14 11:05:30 +0200285 * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
286 * @substream: the pcm substream
287 * @hw: the hardware parameters
288 *
289 * Sets the substream runtime hardware parameters.
290 */
291int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
292 const struct snd_pcm_hardware *hw)
293{
294 struct snd_pcm_runtime *runtime = substream->runtime;
295 runtime->hw.info = hw->info;
296 runtime->hw.formats = hw->formats;
297 runtime->hw.period_bytes_min = hw->period_bytes_min;
298 runtime->hw.period_bytes_max = hw->period_bytes_max;
299 runtime->hw.periods_min = hw->periods_min;
300 runtime->hw.periods_max = hw->periods_max;
301 runtime->hw.buffer_bytes_max = hw->buffer_bytes_max;
302 runtime->hw.fifo_size = hw->fifo_size;
303 return 0;
304}
305EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
306
Liam Girdwood01d75842012-04-25 12:12:49 +0100307/* DPCM stream event, send event to FE and all active BEs. */
Liam Girdwood23607022014-01-17 17:03:55 +0000308int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
Liam Girdwood01d75842012-04-25 12:12:49 +0100309 int event)
310{
311 struct snd_soc_dpcm *dpcm;
312
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +0000313 for_each_dpcm_be(fe, dir, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +0100314
315 struct snd_soc_pcm_runtime *be = dpcm->be;
316
Liam Girdwood103d84a2012-11-19 14:39:15 +0000317 dev_dbg(be->dev, "ASoC: BE %s event %d dir %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +0100318 be->dai_link->name, event, dir);
319
Banajit Goswamib1cd2e32017-07-14 23:15:05 -0700320 if ((event == SND_SOC_DAPM_STREAM_STOP) &&
321 (be->dpcm[dir].users >= 1))
322 continue;
323
Liam Girdwood01d75842012-04-25 12:12:49 +0100324 snd_soc_dapm_stream_event(be, dir, event);
325 }
326
327 snd_soc_dapm_stream_event(fe, dir, event);
328
329 return 0;
330}
331
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900332static void soc_pcm_set_dai_params(struct snd_soc_dai *dai,
333 struct snd_pcm_hw_params *params)
334{
335 if (params) {
336 dai->rate = params_rate(params);
337 dai->channels = params_channels(params);
338 dai->sample_bits = snd_pcm_format_physical_width(params_format(params));
339 } else {
340 dai->rate = 0;
341 dai->channels = 0;
342 dai->sample_bits = 0;
343 }
344}
345
Dong Aisheng17841022011-08-29 17:15:14 +0800346static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
347 struct snd_soc_dai *soc_dai)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100348{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900349 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100350 int ret;
351
Kuninori Morimotof8fc9ec2021-03-09 10:07:42 +0900352 if (!snd_soc_dai_active(soc_dai))
353 return 0;
354
Kuninori Morimotofac110c2021-01-15 13:56:35 +0900355#define __soc_pcm_apply_symmetry(name, NAME) \
356 if (soc_dai->name && (soc_dai->driver->symmetric_##name || \
357 rtd->dai_link->symmetric_##name)) { \
358 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %s to %d\n",\
359 #name, soc_dai->name); \
360 \
361 ret = snd_pcm_hw_constraint_single(substream->runtime, \
362 SNDRV_PCM_HW_PARAM_##NAME,\
363 soc_dai->name); \
364 if (ret < 0) { \
365 dev_err(soc_dai->dev, \
366 "ASoC: Unable to apply %s constraint: %d\n",\
367 #name, ret); \
368 return ret; \
369 } \
Liam Girdwoodddee6272011-06-09 14:45:53 +0100370 }
371
Kuninori Morimotofac110c2021-01-15 13:56:35 +0900372 __soc_pcm_apply_symmetry(rate, RATE);
373 __soc_pcm_apply_symmetry(channels, CHANNELS);
374 __soc_pcm_apply_symmetry(sample_bits, SAMPLE_BITS);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100375
376 return 0;
377}
378
Nicolin Chen3635bf02013-11-13 18:56:24 +0800379static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
380 struct snd_pcm_hw_params *params)
381{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900382 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900383 struct snd_soc_dai d;
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900384 struct snd_soc_dai *dai;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800385 struct snd_soc_dai *cpu_dai;
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900386 unsigned int symmetry, i;
Nicolin Chen3635bf02013-11-13 18:56:24 +0800387
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900388 soc_pcm_set_dai_params(&d, params);
Nicolin Chen3635bf02013-11-13 18:56:24 +0800389
Kuninori Morimoto3a906722021-01-15 13:56:39 +0900390#define __soc_pcm_params_symmetry(name) \
391 symmetry = rtd->dai_link->symmetric_##name; \
392 for_each_rtd_dais(rtd, i, dai) \
393 symmetry |= dai->driver->symmetric_##name; \
394 \
395 if (symmetry) \
396 for_each_rtd_cpu_dais(rtd, i, cpu_dai) \
397 if (cpu_dai->name && cpu_dai->name != d.name) { \
398 dev_err(rtd->dev, "ASoC: unmatched %s symmetry: %d - %d\n", \
399 #name, cpu_dai->name, d.name); \
400 return -EINVAL; \
401 }
402
Nicolin Chen3635bf02013-11-13 18:56:24 +0800403 /* reject unmatched parameters when applying symmetry */
Kuninori Morimoto3a906722021-01-15 13:56:39 +0900404 __soc_pcm_params_symmetry(rate);
405 __soc_pcm_params_symmetry(channels);
406 __soc_pcm_params_symmetry(sample_bits);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100407
408 return 0;
409}
410
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100411static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream)
412{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900413 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100414 struct snd_soc_dai_link *link = rtd->dai_link;
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900415 struct snd_soc_dai *dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200416 unsigned int symmetry, i;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100417
Kuninori Morimotof14654d2021-01-15 13:52:54 +0900418 symmetry = link->symmetric_rate ||
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800419 link->symmetric_channels ||
Kuninori Morimotof14654d2021-01-15 13:52:54 +0900420 link->symmetric_sample_bits;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800421
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900422 for_each_rtd_dais(rtd, i, dai)
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800423 symmetry = symmetry ||
Kuninori Morimotof14654d2021-01-15 13:52:54 +0900424 dai->driver->symmetric_rate ||
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900425 dai->driver->symmetric_channels ||
Kuninori Morimotof14654d2021-01-15 13:52:54 +0900426 dai->driver->symmetric_sample_bits;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200427
428 return symmetry;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100429}
430
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200431static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits)
Mark Brown58ba9b22012-01-16 18:38:51 +0000432{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900433 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Takashi Iwaic6068d32014-12-31 17:10:34 +0100434 int ret;
Mark Brown58ba9b22012-01-16 18:38:51 +0000435
436 if (!bits)
437 return;
438
Lars-Peter Clausen0e2a3752014-12-29 18:43:38 +0100439 ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 0, bits);
440 if (ret != 0)
441 dev_warn(rtd->dev, "ASoC: Failed to set MSB %d: %d\n",
442 bits, ret);
Mark Brown58ba9b22012-01-16 18:38:51 +0000443}
444
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200445static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200446{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900447 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800448 struct snd_soc_dai *cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200449 struct snd_soc_dai *codec_dai;
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900450 struct snd_soc_pcm_stream *pcm_codec, *pcm_cpu;
451 int stream = substream->stream;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200452 int i;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800453 unsigned int bits = 0, cpu_bits = 0;
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200454
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900455 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900456 pcm_codec = snd_soc_dai_get_pcm_stream(codec_dai, stream);
457
458 if (pcm_codec->sig_bits == 0) {
459 bits = 0;
460 break;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200461 }
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900462 bits = max(pcm_codec->sig_bits, bits);
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200463 }
464
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900465 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800466 pcm_cpu = snd_soc_dai_get_pcm_stream(cpu_dai, stream);
467
468 if (pcm_cpu->sig_bits == 0) {
469 cpu_bits = 0;
470 break;
471 }
472 cpu_bits = max(pcm_cpu->sig_bits, cpu_bits);
473 }
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900474
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200475 soc_pcm_set_msb(substream, bits);
476 soc_pcm_set_msb(substream, cpu_bits);
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200477}
478
Kuninori Morimotof6c04af2021-02-04 08:50:31 +0900479static void soc_pcm_hw_init(struct snd_pcm_hardware *hw)
480{
481 hw->rates = UINT_MAX;
482 hw->rate_min = 0;
483 hw->rate_max = UINT_MAX;
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900484 hw->channels_min = 0;
485 hw->channels_max = UINT_MAX;
Kuninori Morimotodebc71f2021-02-04 08:52:04 +0900486 hw->formats = ULLONG_MAX;
Kuninori Morimotof6c04af2021-02-04 08:50:31 +0900487}
488
489static void soc_pcm_hw_update_rate(struct snd_pcm_hardware *hw,
490 struct snd_soc_pcm_stream *p)
491{
492 hw->rates = snd_pcm_rate_mask_intersect(hw->rates, p->rates);
493
494 /* setup hw->rate_min/max via hw->rates first */
495 snd_pcm_hw_limit_rates(hw);
496
497 /* update hw->rate_min/max by snd_soc_pcm_stream */
498 hw->rate_min = max(hw->rate_min, p->rate_min);
499 hw->rate_max = min_not_zero(hw->rate_max, p->rate_max);
500}
501
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900502static void soc_pcm_hw_update_chan(struct snd_pcm_hardware *hw,
503 struct snd_soc_pcm_stream *p)
504{
505 hw->channels_min = max(hw->channels_min, p->channels_min);
506 hw->channels_max = min(hw->channels_max, p->channels_max);
507}
508
Kuninori Morimotodebc71f2021-02-04 08:52:04 +0900509static void soc_pcm_hw_update_format(struct snd_pcm_hardware *hw,
510 struct snd_soc_pcm_stream *p)
511{
512 hw->formats &= p->formats;
513}
514
Samuel Holland5854a462020-03-04 23:11:42 -0600515/**
516 * snd_soc_runtime_calc_hw() - Calculate hw limits for a PCM stream
517 * @rtd: ASoC PCM runtime
518 * @hw: PCM hardware parameters (output)
519 * @stream: Direction of the PCM stream
520 *
521 * Calculates the subset of stream parameters supported by all DAIs
522 * associated with the PCM stream.
523 */
524int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd,
525 struct snd_pcm_hardware *hw, int stream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200526{
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000527 struct snd_soc_dai *codec_dai;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800528 struct snd_soc_dai *cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200529 struct snd_soc_pcm_stream *codec_stream;
530 struct snd_soc_pcm_stream *cpu_stream;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800531 unsigned int cpu_chan_min = 0, cpu_chan_max = UINT_MAX;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200532 int i;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100533
Kuninori Morimotof6c04af2021-02-04 08:50:31 +0900534 soc_pcm_hw_init(hw);
535
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800536 /* first calculate min/max only for CPUs in the DAI link */
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900537 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800538
539 /*
540 * Skip CPUs which don't support the current stream type.
541 * Otherwise, since the rate, channel, and format values will
542 * zero in that case, we would have no usable settings left,
543 * causing the resulting setup to fail.
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800544 */
Samuel Holland5854a462020-03-04 23:11:42 -0600545 if (!snd_soc_dai_stream_valid(cpu_dai, stream))
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800546 continue;
547
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800548 cpu_stream = snd_soc_dai_get_pcm_stream(cpu_dai, stream);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100549
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900550 soc_pcm_hw_update_chan(hw, cpu_stream);
Kuninori Morimotof6c04af2021-02-04 08:50:31 +0900551 soc_pcm_hw_update_rate(hw, cpu_stream);
Kuninori Morimotodebc71f2021-02-04 08:52:04 +0900552 soc_pcm_hw_update_format(hw, cpu_stream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800553 }
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900554 cpu_chan_min = hw->channels_min;
555 cpu_chan_max = hw->channels_max;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800556
557 /* second calculate min/max only for CODECs in the DAI link */
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900558 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200559
560 /*
561 * Skip CODECs which don't support the current stream type.
562 * Otherwise, since the rate, channel, and format values will
563 * zero in that case, we would have no usable settings left,
564 * causing the resulting setup to fail.
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200565 */
Kuninori Morimoto25c2f512020-02-27 10:54:38 +0900566 if (!snd_soc_dai_stream_valid(codec_dai, stream))
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200567 continue;
568
Kuninori Morimotoacf253c2020-02-19 15:56:30 +0900569 codec_stream = snd_soc_dai_get_pcm_stream(codec_dai, stream);
570
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900571 soc_pcm_hw_update_chan(hw, codec_stream);
Kuninori Morimotof6c04af2021-02-04 08:50:31 +0900572 soc_pcm_hw_update_rate(hw, codec_stream);
Kuninori Morimotodebc71f2021-02-04 08:52:04 +0900573 soc_pcm_hw_update_format(hw, codec_stream);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200574 }
575
Samuel Holland5854a462020-03-04 23:11:42 -0600576 /* Verify both a valid CPU DAI and a valid CODEC DAI were found */
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900577 if (!hw->channels_min)
Samuel Holland5854a462020-03-04 23:11:42 -0600578 return -EINVAL;
579
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200580 /*
581 * chan min/max cannot be enforced if there are multiple CODEC DAIs
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800582 * connected to CPU DAI(s), use CPU DAI's directly and let
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200583 * channel allocation be fixed up later
584 */
585 if (rtd->num_codecs > 1) {
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900586 hw->channels_min = cpu_chan_min;
587 hw->channels_max = cpu_chan_max;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200588 }
589
Samuel Holland5854a462020-03-04 23:11:42 -0600590 return 0;
591}
592EXPORT_SYMBOL_GPL(snd_soc_runtime_calc_hw);
593
594static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
595{
596 struct snd_pcm_hardware *hw = &substream->runtime->hw;
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900597 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Samuel Holland5854a462020-03-04 23:11:42 -0600598 u64 formats = hw->formats;
599
600 /*
601 * At least one CPU and one CODEC should match. Otherwise, we should
602 * have bailed out on a higher level, since there would be no CPU or
603 * CODEC to support the transfer direction in that case.
604 */
605 snd_soc_runtime_calc_hw(rtd, hw, substream->stream);
606
607 if (formats)
608 hw->formats &= formats;
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200609}
610
Kuninori Morimotodd039072020-02-10 12:14:37 +0900611static int soc_pcm_components_open(struct snd_pcm_substream *substream)
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900612{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900613 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900614 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900615 int i, ret = 0;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900616
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900617 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto51aff912020-09-28 09:01:04 +0900618 ret = snd_soc_component_module_get_when_open(component, substream);
Kuninori Morimotobcae16312020-09-28 09:01:36 +0900619 if (ret < 0)
Kai Vehmanend2aaa8d2020-02-20 11:49:55 +0200620 break;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900621
Kuninori Morimotoae2f4842019-07-26 13:50:01 +0900622 ret = snd_soc_component_open(component, substream);
Kuninori Morimotobcae16312020-09-28 09:01:36 +0900623 if (ret < 0)
Kai Vehmanend2aaa8d2020-02-20 11:49:55 +0200624 break;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900625 }
Kuninori Morimotodd039072020-02-10 12:14:37 +0900626
Kai Vehmanend2aaa8d2020-02-20 11:49:55 +0200627 return ret;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900628}
629
Kuninori Morimoto51aff912020-09-28 09:01:04 +0900630static int soc_pcm_components_close(struct snd_pcm_substream *substream,
631 int rollback)
Charles Keepax244e2932018-06-19 16:22:09 +0100632{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900633 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Charles Keepax244e2932018-06-19 16:22:09 +0100634 struct snd_soc_component *component;
Kuninori Morimotoe82ebff2020-02-10 12:14:26 +0900635 int i, r, ret = 0;
Charles Keepax244e2932018-06-19 16:22:09 +0100636
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900637 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto51aff912020-09-28 09:01:04 +0900638 r = snd_soc_component_close(component, substream, rollback);
Kuninori Morimotoe82ebff2020-02-10 12:14:26 +0900639 if (r < 0)
640 ret = r; /* use last ret */
641
Kuninori Morimoto51aff912020-09-28 09:01:04 +0900642 snd_soc_component_module_put_when_close(component, substream, rollback);
Charles Keepax244e2932018-06-19 16:22:09 +0100643 }
644
Kuninori Morimoto3672beb2019-07-26 13:50:07 +0900645 return ret;
Charles Keepax244e2932018-06-19 16:22:09 +0100646}
647
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900648static int soc_pcm_clean(struct snd_pcm_substream *substream, int rollback)
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900649{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900650 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900651 struct snd_soc_component *component;
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900652 struct snd_soc_dai *dai;
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900653 int i;
654
655 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
656
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900657 if (!rollback)
658 snd_soc_runtime_deactivate(rtd, substream->stream);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900659
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900660 for_each_rtd_dais(rtd, i, dai)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900661 snd_soc_dai_shutdown(dai, substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900662
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900663 snd_soc_link_shutdown(substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900664
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900665 soc_pcm_components_close(substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900666
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900667
668 mutex_unlock(&rtd->card->pcm_mutex);
669
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900670 snd_soc_pcm_component_pm_runtime_put(rtd, substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900671
672 for_each_rtd_components(rtd, i, component)
Kuninori Morimotob3dea622020-05-15 09:46:51 +0900673 if (!snd_soc_component_active(component))
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900674 pinctrl_pm_select_sleep_state(component->dev);
675
676 return 0;
677}
678
679/*
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900680 * Called by ALSA when a PCM substream is closed. Private data can be
681 * freed here. The cpu DAI, codec DAI, machine and components are also
682 * shutdown.
683 */
684static int soc_pcm_close(struct snd_pcm_substream *substream)
685{
686 return soc_pcm_clean(substream, 0);
687}
688
689/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100690 * Called by ALSA when a PCM substream is opened, the runtime->hw record is
691 * then initialized and any private data can be allocated. This also calls
Charles Keepaxef050be2018-04-24 16:39:02 +0100692 * startup for the cpu DAI, component, machine and codec DAI.
Liam Girdwoodddee6272011-06-09 14:45:53 +0100693 */
694static int soc_pcm_open(struct snd_pcm_substream *substream)
695{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900696 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100697 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000698 struct snd_soc_component *component;
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900699 struct snd_soc_dai *dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200700 const char *codec_dai_name = "multicodec";
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800701 const char *cpu_dai_name = "multicpu";
Charles Keepax244e2932018-06-19 16:22:09 +0100702 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100703
Kuninori Morimoto76c39e82020-01-10 11:36:13 +0900704 for_each_rtd_components(rtd, i, component)
705 pinctrl_pm_select_default_state(component->dev);
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000706
Kuninori Morimoto939a5cf2020-09-28 09:01:17 +0900707 ret = snd_soc_pcm_component_pm_runtime_get(rtd, substream);
708 if (ret < 0)
Kuninori Morimotocb2fce92020-10-01 10:32:48 +0900709 goto pm_err;
Mark Brownd6652ef2011-12-03 20:14:31 +0000710
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300711 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100712
Kuninori Morimoto5d9fa032020-02-10 12:14:45 +0900713 ret = soc_pcm_components_open(substream);
714 if (ret < 0)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900715 goto err;
Kuninori Morimoto5d9fa032020-02-10 12:14:45 +0900716
Kuninori Morimoto7cf3c5b2020-05-25 09:57:31 +0900717 ret = snd_soc_link_startup(substream);
Kuninori Morimotoa5e6c102020-05-25 09:57:19 +0900718 if (ret < 0)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900719 goto err;
Kuninori Morimoto5d9fa032020-02-10 12:14:45 +0900720
Liam Girdwoodddee6272011-06-09 14:45:53 +0100721 /* startup the audio subsystem */
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900722 for_each_rtd_dais(rtd, i, dai) {
723 ret = snd_soc_dai_startup(dai, substream);
Kuninori Morimotoce820142020-09-28 09:01:29 +0900724 if (ret < 0)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900725 goto err;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200726
727 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900728 dai->tx_mask = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200729 else
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900730 dai->rx_mask = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100731 }
732
Liam Girdwood01d75842012-04-25 12:12:49 +0100733 /* Dynamic PCM DAI links compat checks use dynamic capabilities */
734 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm)
735 goto dynamic;
736
Liam Girdwoodddee6272011-06-09 14:45:53 +0100737 /* Check that the codec and cpu DAIs are compatible */
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200738 soc_pcm_init_runtime_hw(substream);
739
740 if (rtd->num_codecs == 1)
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900741 codec_dai_name = asoc_rtd_to_codec(rtd, 0)->name;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100742
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800743 if (rtd->num_cpus == 1)
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900744 cpu_dai_name = asoc_rtd_to_cpu(rtd, 0)->name;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800745
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100746 if (soc_pcm_has_symmetry(substream))
747 runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
748
Liam Girdwoodddee6272011-06-09 14:45:53 +0100749 ret = -EINVAL;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100750 if (!runtime->hw.rates) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000751 printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n",
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800752 codec_dai_name, cpu_dai_name);
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900753 goto err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100754 }
755 if (!runtime->hw.formats) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000756 printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n",
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800757 codec_dai_name, cpu_dai_name);
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900758 goto err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100759 }
760 if (!runtime->hw.channels_min || !runtime->hw.channels_max ||
761 runtime->hw.channels_min > runtime->hw.channels_max) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000762 printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n",
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800763 codec_dai_name, cpu_dai_name);
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900764 goto err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100765 }
766
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200767 soc_pcm_apply_msb(substream);
Mark Brown58ba9b22012-01-16 18:38:51 +0000768
Liam Girdwoodddee6272011-06-09 14:45:53 +0100769 /* Symmetry only applies if we've already got an active stream. */
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900770 for_each_rtd_dais(rtd, i, dai) {
Kuninori Morimotof8fc9ec2021-03-09 10:07:42 +0900771 ret = soc_pcm_apply_symmetry(substream, dai);
772 if (ret != 0)
773 goto err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100774 }
775
Liam Girdwood103d84a2012-11-19 14:39:15 +0000776 pr_debug("ASoC: %s <-> %s info:\n",
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800777 codec_dai_name, cpu_dai_name);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000778 pr_debug("ASoC: rate mask 0x%x\n", runtime->hw.rates);
779 pr_debug("ASoC: min ch %d max ch %d\n", runtime->hw.channels_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100780 runtime->hw.channels_max);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000781 pr_debug("ASoC: min rate %d max rate %d\n", runtime->hw.rate_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100782 runtime->hw.rate_max);
Liam Girdwood01d75842012-04-25 12:12:49 +0100783dynamic:
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100784 snd_soc_runtime_activate(rtd, substream->stream);
Kuninori Morimoto8e7875a2020-10-01 14:07:41 +0900785 ret = 0;
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900786err:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300787 mutex_unlock(&rtd->card->pcm_mutex);
Kuninori Morimotocb2fce92020-10-01 10:32:48 +0900788pm_err:
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900789 if (ret < 0)
790 soc_pcm_clean(substream, 1);
Mark Brownd6652ef2011-12-03 20:14:31 +0000791
Liam Girdwoodddee6272011-06-09 14:45:53 +0100792 return ret;
793}
794
Curtis Malainey4bf2e382019-12-03 09:30:07 -0800795static void codec2codec_close_delayed_work(struct snd_soc_pcm_runtime *rtd)
Jerome Bruneta3420312019-07-25 18:59:47 +0200796{
797 /*
798 * Currently nothing to do for c2c links
799 * Since c2c links are internal nodes in the DAPM graph and
800 * don't interface with the outside world or application layer
801 * we don't have to do any special handling on close.
802 */
803}
804
Liam Girdwoodddee6272011-06-09 14:45:53 +0100805/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100806 * Called by ALSA when the PCM substream is prepared, can set format, sample
807 * rate, etc. This function is non atomic and can be called multiple times,
808 * it can refer to the runtime info.
809 */
810static int soc_pcm_prepare(struct snd_pcm_substream *substream)
811{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900812 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900813 struct snd_soc_dai *dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200814 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100815
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300816 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100817
Kuninori Morimoto7cf3c5b2020-05-25 09:57:31 +0900818 ret = snd_soc_link_prepare(substream);
Kuninori Morimotoa5e6c102020-05-25 09:57:19 +0900819 if (ret < 0)
Kuninori Morimoto44c1a752020-01-22 09:44:44 +0900820 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100821
Kuninori Morimoto4f395142020-06-04 17:06:58 +0900822 ret = snd_soc_pcm_component_prepare(substream);
823 if (ret < 0)
824 goto out;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000825
Kuninori Morimotod108c7f2020-04-24 08:14:53 +0900826 ret = snd_soc_pcm_dai_prepare(substream);
827 if (ret < 0) {
828 dev_err(rtd->dev, "ASoC: DAI prepare error: %d\n", ret);
829 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100830 }
831
832 /* cancel any delayed stream shutdown that is pending */
833 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600834 rtd->pop_wait) {
835 rtd->pop_wait = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100836 cancel_delayed_work(&rtd->delayed_work);
837 }
838
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000839 snd_soc_dapm_stream_event(rtd, substream->stream,
840 SND_SOC_DAPM_STREAM_START);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100841
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900842 for_each_rtd_dais(rtd, i, dai)
843 snd_soc_dai_digital_mute(dai, 0, substream->stream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100844
845out:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300846 mutex_unlock(&rtd->card->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100847 return ret;
848}
849
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200850static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params,
851 unsigned int mask)
852{
853 struct snd_interval *interval;
854 int channels = hweight_long(mask);
855
856 interval = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
857 interval->min = channels;
858 interval->max = channels;
859}
860
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900861static int soc_pcm_hw_clean(struct snd_pcm_substream *substream, int rollback)
Kuninori Morimotoab494362020-09-29 13:31:19 +0900862{
863 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
864 struct snd_soc_dai *dai;
865 int i;
866
867 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
868
869 /* clear the corresponding DAIs parameters when going to be inactive */
870 for_each_rtd_dais(rtd, i, dai) {
871 int active = snd_soc_dai_stream_active(dai, substream->stream);
872
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900873 if (snd_soc_dai_active(dai) == 1)
874 soc_pcm_set_dai_params(dai, NULL);
Kuninori Morimotoab494362020-09-29 13:31:19 +0900875
876 if (active == 1)
877 snd_soc_dai_digital_mute(dai, 1, substream->stream);
878 }
879
Ranjani Sridharana27b4212020-11-17 13:50:01 -0800880 /* run the stream event */
881 snd_soc_dapm_stream_stop(rtd, substream->stream);
882
Kuninori Morimotoab494362020-09-29 13:31:19 +0900883 /* free any machine hw params */
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900884 snd_soc_link_hw_free(substream, rollback);
Kuninori Morimotoab494362020-09-29 13:31:19 +0900885
886 /* free any component resources */
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900887 snd_soc_pcm_component_hw_free(substream, rollback);
Kuninori Morimotoab494362020-09-29 13:31:19 +0900888
889 /* now free hw params for the DAIs */
890 for_each_rtd_dais(rtd, i, dai) {
891 if (!snd_soc_dai_stream_valid(dai, substream->stream))
892 continue;
893
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900894 snd_soc_dai_hw_free(dai, substream, rollback);
Kuninori Morimotoab494362020-09-29 13:31:19 +0900895 }
896
897 mutex_unlock(&rtd->card->pcm_mutex);
898 return 0;
899}
900
901/*
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900902 * Frees resources allocated by hw_params, can be called multiple times
903 */
904static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
905{
906 return soc_pcm_hw_clean(substream, 0);
907}
908
909/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100910 * Called by ALSA when the hardware params are set by application. This
911 * function can also be called multiple times and can allocate buffers
912 * (using snd_pcm_lib_* ). It's non-atomic.
913 */
914static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
915 struct snd_pcm_hw_params *params)
916{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900917 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800918 struct snd_soc_dai *cpu_dai;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000919 struct snd_soc_dai *codec_dai;
Charles Keepax244e2932018-06-19 16:22:09 +0100920 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100921
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300922 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Shengjiu Wang5cca5952019-11-12 18:46:42 +0800923
924 ret = soc_pcm_params_symmetry(substream, params);
925 if (ret)
926 goto out;
927
Kuninori Morimoto7cf3c5b2020-05-25 09:57:31 +0900928 ret = snd_soc_link_hw_params(substream, params);
Kuninori Morimotoa5e6c102020-05-25 09:57:19 +0900929 if (ret < 0)
Kuninori Morimotode9ad992020-01-22 09:44:48 +0900930 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100931
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900932 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200933 struct snd_pcm_hw_params codec_params;
934
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200935 /*
936 * Skip CODECs which don't support the current stream type,
937 * the idea being that if a CODEC is not used for the currently
938 * set up transfer direction, it should not need to be
939 * configured, especially since the configuration used might
940 * not even be supported by that CODEC. There may be cases
941 * however where a CODEC needs to be set up although it is
942 * actually not being used for the transfer, e.g. if a
943 * capture-only CODEC is acting as an LRCLK and/or BCLK master
944 * for the DAI link including a playback-only CODEC.
945 * If this becomes necessary, we will have to augment the
946 * machine driver setup with information on how to act, so
947 * we can do the right thing here.
948 */
949 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
950 continue;
951
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200952 /* copy params for each codec */
953 codec_params = *params;
954
955 /* fixup params based on TDM slot masks */
Rander Wang570f18b2019-03-08 16:38:57 +0800956 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
957 codec_dai->tx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200958 soc_pcm_codec_params_fixup(&codec_params,
959 codec_dai->tx_mask);
Rander Wang570f18b2019-03-08 16:38:57 +0800960
961 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
962 codec_dai->rx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200963 soc_pcm_codec_params_fixup(&codec_params,
964 codec_dai->rx_mask);
965
Kuninori Morimotoaa6166c2019-07-22 10:33:04 +0900966 ret = snd_soc_dai_hw_params(codec_dai, substream,
967 &codec_params);
Benoit Cousson93e69582014-07-08 23:19:38 +0200968 if(ret < 0)
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900969 goto out;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200970
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900971 soc_pcm_set_dai_params(codec_dai, &codec_params);
Charles Keepax078a85f2019-01-31 13:30:18 +0000972 snd_soc_dapm_update_dai(substream, &codec_params, codec_dai);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100973 }
974
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900975 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800976 /*
977 * Skip CPUs which don't support the current stream
978 * type. See soc_pcm_init_runtime_hw() for more details
979 */
980 if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream))
981 continue;
982
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800983 ret = snd_soc_dai_hw_params(cpu_dai, substream, params);
984 if (ret < 0)
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900985 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100986
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800987 /* store the parameters for each DAI */
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900988 soc_pcm_set_dai_params(cpu_dai, params);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800989 snd_soc_dapm_update_dai(substream, params, cpu_dai);
990 }
Kuninori Morimotoca58221d2019-05-13 16:07:43 +0900991
Kuninori Morimoto3a36a642020-09-29 13:31:41 +0900992 ret = snd_soc_pcm_component_hw_params(substream, params);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100993out:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300994 mutex_unlock(&rtd->card->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100995
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900996 if (ret < 0)
997 soc_pcm_hw_clean(substream, 1);
Kuninori Morimotob8135862017-10-11 01:37:23 +0000998
Liam Girdwoodddee6272011-06-09 14:45:53 +0100999 return ret;
1000}
1001
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001002static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1003{
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001004 int ret = -EINVAL, _ret = 0;
1005 int rollback = 0;
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001006
1007 switch (cmd) {
1008 case SNDRV_PCM_TRIGGER_START:
1009 case SNDRV_PCM_TRIGGER_RESUME:
1010 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001011 ret = snd_soc_link_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_component_trigger(substream, cmd, 0);
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001016 if (ret < 0)
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001017 goto start_err;
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001018
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001019 ret = snd_soc_pcm_dai_trigger(substream, cmd, 0);
1020start_err:
1021 if (ret < 0)
1022 rollback = 1;
1023 }
1024
1025 if (rollback) {
1026 _ret = ret;
1027 switch (cmd) {
1028 case SNDRV_PCM_TRIGGER_START:
1029 cmd = SNDRV_PCM_TRIGGER_STOP;
1030 break;
1031 case SNDRV_PCM_TRIGGER_RESUME:
1032 cmd = SNDRV_PCM_TRIGGER_SUSPEND;
1033 break;
1034 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1035 cmd = SNDRV_PCM_TRIGGER_PAUSE_PUSH;
1036 break;
1037 }
1038 }
1039
1040 switch (cmd) {
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001041 case SNDRV_PCM_TRIGGER_STOP:
1042 case SNDRV_PCM_TRIGGER_SUSPEND:
1043 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001044 ret = snd_soc_pcm_dai_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_pcm_component_trigger(substream, cmd, rollback);
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001049 if (ret < 0)
1050 break;
1051
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001052 ret = snd_soc_link_trigger(substream, cmd, rollback);
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001053 break;
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001054 }
1055
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001056 if (_ret)
1057 ret = _ret;
1058
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001059 return ret;
1060}
1061
Liam Girdwoodddee6272011-06-09 14:45:53 +01001062/*
1063 * soc level wrapper for pointer callback
Charles Keepaxef050be2018-04-24 16:39:02 +01001064 * If cpu_dai, codec_dai, component driver has the delay callback, then
Liam Girdwoodddee6272011-06-09 14:45:53 +01001065 * the runtime->delay will be updated accordingly.
1066 */
1067static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
1068{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001069 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001070 struct snd_soc_dai *cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001071 struct snd_soc_dai *codec_dai;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001072 struct snd_pcm_runtime *runtime = substream->runtime;
1073 snd_pcm_uframes_t offset = 0;
1074 snd_pcm_sframes_t delay = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001075 snd_pcm_sframes_t codec_delay = 0;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001076 snd_pcm_sframes_t cpu_delay = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001077 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001078
Akshu Agrawal9fb4c2bf2018-08-01 15:37:33 +05301079 /* clearing the previous total delay */
1080 runtime->delay = 0;
1081
Kuninori Morimoto0035e252019-07-26 13:51:47 +09001082 offset = snd_soc_pcm_component_pointer(substream);
Kuninori Morimotob8135862017-10-11 01:37:23 +00001083
Akshu Agrawal9fb4c2bf2018-08-01 15:37:33 +05301084 /* base delay if assigned in pointer callback */
1085 delay = runtime->delay;
Kuninori Morimotob8135862017-10-11 01:37:23 +00001086
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001087 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001088 cpu_delay = max(cpu_delay,
1089 snd_soc_dai_delay(cpu_dai, substream));
1090 }
1091 delay += cpu_delay;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001092
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001093 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Kuninori Morimoto1dea80d2019-07-22 10:34:09 +09001094 codec_delay = max(codec_delay,
1095 snd_soc_dai_delay(codec_dai, substream));
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001096 }
1097 delay += codec_delay;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001098
Liam Girdwoodddee6272011-06-09 14:45:53 +01001099 runtime->delay = delay;
1100
1101 return offset;
1102}
1103
Liam Girdwood01d75842012-04-25 12:12:49 +01001104/* connect a FE and BE */
1105static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
1106 struct snd_soc_pcm_runtime *be, int stream)
1107{
1108 struct snd_soc_dpcm *dpcm;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001109 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001110
1111 /* only add new dpcms */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001112 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001113 if (dpcm->be == be && dpcm->fe == fe)
1114 return 0;
1115 }
1116
1117 dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_KERNEL);
1118 if (!dpcm)
1119 return -ENOMEM;
1120
1121 dpcm->be = be;
1122 dpcm->fe = fe;
1123 be->dpcm[stream].runtime = fe->dpcm[stream].runtime;
1124 dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001125 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001126 list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients);
1127 list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001128 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001129
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001130 dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001131 stream ? "capture" : "playback", fe->dai_link->name,
1132 stream ? "<-" : "->", be->dai_link->name);
1133
Kuninori Morimoto154dae82020-02-19 15:57:06 +09001134 dpcm_create_debugfs_state(dpcm, stream);
1135
Liam Girdwood01d75842012-04-25 12:12:49 +01001136 return 1;
1137}
1138
1139/* reparent a BE onto another FE */
1140static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
1141 struct snd_soc_pcm_runtime *be, int stream)
1142{
1143 struct snd_soc_dpcm *dpcm;
1144 struct snd_pcm_substream *fe_substream, *be_substream;
1145
1146 /* reparent if BE is connected to other FEs */
1147 if (!be->dpcm[stream].users)
1148 return;
1149
1150 be_substream = snd_soc_dpcm_get_substream(be, stream);
1151
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00001152 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001153 if (dpcm->fe == fe)
1154 continue;
1155
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001156 dev_dbg(fe->dev, "reparent %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001157 stream ? "capture" : "playback",
1158 dpcm->fe->dai_link->name,
1159 stream ? "<-" : "->", dpcm->be->dai_link->name);
1160
1161 fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, stream);
1162 be_substream->runtime = fe_substream->runtime;
1163 break;
1164 }
1165}
1166
1167/* disconnect a BE and FE */
Liam Girdwood23607022014-01-17 17:03:55 +00001168void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001169{
1170 struct snd_soc_dpcm *dpcm, *d;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001171 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001172
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001173 for_each_dpcm_be_safe(fe, stream, dpcm, d) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001174 dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001175 stream ? "capture" : "playback",
1176 dpcm->be->dai_link->name);
1177
1178 if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE)
1179 continue;
1180
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001181 dev_dbg(fe->dev, "freed DSP %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001182 stream ? "capture" : "playback", fe->dai_link->name,
1183 stream ? "<-" : "->", dpcm->be->dai_link->name);
1184
1185 /* BEs still alive need new FE */
1186 dpcm_be_reparent(fe, dpcm->be, stream);
1187
Kuninori Morimoto154dae82020-02-19 15:57:06 +09001188 dpcm_remove_debugfs_state(dpcm);
1189
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001190 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001191 list_del(&dpcm->list_be);
1192 list_del(&dpcm->list_fe);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001193 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001194 kfree(dpcm);
1195 }
1196}
1197
1198/* get BE for DAI widget and stream */
1199static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
1200 struct snd_soc_dapm_widget *widget, int stream)
1201{
1202 struct snd_soc_pcm_runtime *be;
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001203 struct snd_soc_dapm_widget *w;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001204 struct snd_soc_dai *dai;
Mengdong Lin1a497982015-11-18 02:34:11 -05001205 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01001206
Liam Girdwood3c146462018-03-14 20:43:51 +00001207 dev_dbg(card->dev, "ASoC: find BE for widget %s\n", widget->name);
1208
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001209 for_each_card_rtds(card, be) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001210
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001211 if (!be->dai_link->no_pcm)
1212 continue;
Liam Girdwood35ea0652012-06-05 19:26:59 +01001213
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001214 for_each_rtd_dais(be, i, dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001215 w = snd_soc_dai_get_widget(dai, stream);
Liam Girdwood3c146462018-03-14 20:43:51 +00001216
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001217 dev_dbg(card->dev, "ASoC: try BE : %s\n",
1218 w ? w->name : "(not set)");
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001219
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001220 if (w == widget)
1221 return be;
1222 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001223 }
1224
Jerome Brunet9d6ee362020-02-19 12:50:48 +01001225 /* Widget provided is not a BE */
Liam Girdwood01d75842012-04-25 12:12:49 +01001226 return NULL;
1227}
1228
Liam Girdwood01d75842012-04-25 12:12:49 +01001229static int widget_in_list(struct snd_soc_dapm_widget_list *list,
1230 struct snd_soc_dapm_widget *widget)
1231{
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001232 struct snd_soc_dapm_widget *w;
Liam Girdwood01d75842012-04-25 12:12:49 +01001233 int i;
1234
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001235 for_each_dapm_widgets(list, i, w)
1236 if (widget == w)
Liam Girdwood01d75842012-04-25 12:12:49 +01001237 return 1;
Liam Girdwood01d75842012-04-25 12:12:49 +01001238
1239 return 0;
1240}
1241
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001242static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget,
1243 enum snd_soc_dapm_direction dir)
1244{
1245 struct snd_soc_card *card = widget->dapm->card;
1246 struct snd_soc_pcm_runtime *rtd;
Kuninori Morimotoc2cd8212020-02-17 17:27:48 +09001247 int stream;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001248
Kuninori Morimotoc2cd8212020-02-17 17:27:48 +09001249 /* adjust dir to stream */
1250 if (dir == SND_SOC_DAPM_DIR_OUT)
1251 stream = SNDRV_PCM_STREAM_PLAYBACK;
1252 else
1253 stream = SNDRV_PCM_STREAM_CAPTURE;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001254
Kuninori Morimoto027a4832020-02-17 17:27:53 +09001255 rtd = dpcm_get_be(card, widget, stream);
1256 if (rtd)
1257 return true;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001258
1259 return false;
1260}
1261
Liam Girdwood23607022014-01-17 17:03:55 +00001262int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001263 int stream, struct snd_soc_dapm_widget_list **list)
Liam Girdwood01d75842012-04-25 12:12:49 +01001264{
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09001265 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
Liam Girdwood01d75842012-04-25 12:12:49 +01001266 int paths;
1267
Bard Liao6e1276a2020-02-25 21:39:16 +08001268 if (fe->num_cpus > 1) {
1269 dev_err(fe->dev,
1270 "%s doesn't support Multi CPU yet\n", __func__);
1271 return -EINVAL;
1272 }
1273
Liam Girdwood01d75842012-04-25 12:12:49 +01001274 /* get number of valid DAI paths and their widgets */
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001275 paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list,
Sameer Pujaraa293772020-11-02 20:40:09 +05301276 fe->card->component_chaining ?
1277 NULL : dpcm_end_walk_at_be);
Liam Girdwood01d75842012-04-25 12:12:49 +01001278
Liam Girdwood103d84a2012-11-19 14:39:15 +00001279 dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths,
Liam Girdwood01d75842012-04-25 12:12:49 +01001280 stream ? "capture" : "playback");
1281
Liam Girdwood01d75842012-04-25 12:12:49 +01001282 return paths;
1283}
1284
Kuninori Morimoto52645e332020-02-19 15:56:52 +09001285void dpcm_path_put(struct snd_soc_dapm_widget_list **list)
1286{
1287 snd_soc_dapm_dai_free_widgets(list);
1288}
1289
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001290static bool dpcm_be_is_active(struct snd_soc_dpcm *dpcm, int stream,
1291 struct snd_soc_dapm_widget_list *list)
Liam Girdwood01d75842012-04-25 12:12:49 +01001292{
Liam Girdwood01d75842012-04-25 12:12:49 +01001293 struct snd_soc_dapm_widget *widget;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001294 struct snd_soc_dai *dai;
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001295 unsigned int i;
1296
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001297 /* is there a valid DAI widget for this BE */
1298 for_each_rtd_dais(dpcm->be, i, dai) {
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001299 widget = snd_soc_dai_get_widget(dai, stream);
1300
1301 /*
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001302 * The BE is pruned only if none of the dai
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001303 * widgets are in the active list.
1304 */
1305 if (widget && widget_in_list(list, widget))
1306 return true;
1307 }
1308
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001309 return false;
1310}
1311
1312static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
1313 struct snd_soc_dapm_widget_list **list_)
1314{
1315 struct snd_soc_dpcm *dpcm;
Liam Girdwood01d75842012-04-25 12:12:49 +01001316 int prune = 0;
1317
1318 /* Destroy any old FE <--> BE connections */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001319 for_each_dpcm_be(fe, stream, dpcm) {
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001320 if (dpcm_be_is_active(dpcm, stream, *list_))
Kuninori Morimotobed646d2019-10-15 12:59:38 +09001321 continue;
Liam Girdwood01d75842012-04-25 12:12:49 +01001322
Liam Girdwood103d84a2012-11-19 14:39:15 +00001323 dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001324 stream ? "capture" : "playback",
1325 dpcm->be->dai_link->name, fe->dai_link->name);
1326 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
Kuninori Morimotoa7e204442020-12-11 14:55:22 +09001327 dpcm_set_be_update_state(dpcm->be, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001328 prune++;
1329 }
1330
Liam Girdwood103d84a2012-11-19 14:39:15 +00001331 dev_dbg(fe->dev, "ASoC: found %d old BE paths for pruning\n", prune);
Liam Girdwood01d75842012-04-25 12:12:49 +01001332 return prune;
1333}
1334
1335static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
1336 struct snd_soc_dapm_widget_list **list_)
1337{
1338 struct snd_soc_card *card = fe->card;
1339 struct snd_soc_dapm_widget_list *list = *list_;
1340 struct snd_soc_pcm_runtime *be;
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001341 struct snd_soc_dapm_widget *widget;
Liam Girdwood01d75842012-04-25 12:12:49 +01001342 int i, new = 0, err;
1343
1344 /* Create any new FE <--> BE connections */
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001345 for_each_dapm_widgets(list, i, widget) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001346
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001347 switch (widget->id) {
Mark Brown46162742013-06-05 19:36:11 +01001348 case snd_soc_dapm_dai_in:
Koro Chenc5b85402015-07-06 10:02:10 +08001349 if (stream != SNDRV_PCM_STREAM_PLAYBACK)
1350 continue;
1351 break;
Mark Brown46162742013-06-05 19:36:11 +01001352 case snd_soc_dapm_dai_out:
Koro Chenc5b85402015-07-06 10:02:10 +08001353 if (stream != SNDRV_PCM_STREAM_CAPTURE)
1354 continue;
Mark Brown46162742013-06-05 19:36:11 +01001355 break;
1356 default:
Liam Girdwood01d75842012-04-25 12:12:49 +01001357 continue;
Mark Brown46162742013-06-05 19:36:11 +01001358 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001359
1360 /* is there a valid BE rtd for this widget */
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001361 be = dpcm_get_be(card, widget, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001362 if (!be) {
Shengjiu Wangb6eabd22021-02-08 16:12:45 +08001363 dev_dbg(fe->dev, "ASoC: no BE found for %s\n",
1364 widget->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001365 continue;
1366 }
1367
Liam Girdwood01d75842012-04-25 12:12:49 +01001368 /* don't connect if FE is not running */
Liam Girdwood23607022014-01-17 17:03:55 +00001369 if (!fe->dpcm[stream].runtime && !fe->fe_compr)
Liam Girdwood01d75842012-04-25 12:12:49 +01001370 continue;
1371
1372 /* newly connected FE and BE */
1373 err = dpcm_be_connect(fe, be, stream);
1374 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001375 dev_err(fe->dev, "ASoC: can't connect %s\n",
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001376 widget->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001377 break;
1378 } else if (err == 0) /* already connected */
1379 continue;
1380
1381 /* new */
Kuninori Morimotoa7e204442020-12-11 14:55:22 +09001382 dpcm_set_be_update_state(be, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001383 new++;
1384 }
1385
Liam Girdwood103d84a2012-11-19 14:39:15 +00001386 dev_dbg(fe->dev, "ASoC: found %d new BE paths\n", new);
Liam Girdwood01d75842012-04-25 12:12:49 +01001387 return new;
1388}
1389
1390/*
1391 * Find the corresponding BE DAIs that source or sink audio to this
1392 * FE substream.
1393 */
Liam Girdwood23607022014-01-17 17:03:55 +00001394int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
Liam Girdwood01d75842012-04-25 12:12:49 +01001395 int stream, struct snd_soc_dapm_widget_list **list, int new)
1396{
1397 if (new)
1398 return dpcm_add_paths(fe, stream, list);
1399 else
1400 return dpcm_prune_paths(fe, stream, list);
1401}
1402
Liam Girdwood23607022014-01-17 17:03:55 +00001403void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001404{
1405 struct snd_soc_dpcm *dpcm;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001406 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001407
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001408 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001409 for_each_dpcm_be(fe, stream, dpcm)
Kuninori Morimotoa7e204442020-12-11 14:55:22 +09001410 dpcm_set_be_update_state(dpcm->be, stream, SND_SOC_DPCM_UPDATE_NO);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001411 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001412}
1413
1414static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe,
1415 int stream)
1416{
1417 struct snd_soc_dpcm *dpcm;
1418
1419 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001420 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001421
1422 struct snd_soc_pcm_runtime *be = dpcm->be;
1423 struct snd_pcm_substream *be_substream =
1424 snd_soc_dpcm_get_substream(be, stream);
1425
1426 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001427 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001428 stream ? "capture" : "playback",
1429 be->dpcm[stream].state);
1430
1431 if (--be->dpcm[stream].users != 0)
1432 continue;
1433
1434 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1435 continue;
1436
1437 soc_pcm_close(be_substream);
1438 be_substream->runtime = NULL;
1439 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1440 }
1441}
1442
Liam Girdwood23607022014-01-17 17:03:55 +00001443int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001444{
1445 struct snd_soc_dpcm *dpcm;
1446 int err, count = 0;
1447
1448 /* only startup BE DAIs that are either sinks or sources to this FE DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001449 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001450
1451 struct snd_soc_pcm_runtime *be = dpcm->be;
1452 struct snd_pcm_substream *be_substream =
1453 snd_soc_dpcm_get_substream(be, stream);
1454
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001455 if (!be_substream) {
1456 dev_err(be->dev, "ASoC: no backend %s stream\n",
1457 stream ? "capture" : "playback");
1458 continue;
1459 }
1460
Liam Girdwood01d75842012-04-25 12:12:49 +01001461 /* is this op for this BE ? */
1462 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1463 continue;
1464
1465 /* first time the dpcm is open ? */
1466 if (be->dpcm[stream].users == DPCM_MAX_BE_USERS)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001467 dev_err(be->dev, "ASoC: too many users %s at open %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001468 stream ? "capture" : "playback",
1469 be->dpcm[stream].state);
1470
1471 if (be->dpcm[stream].users++ != 0)
1472 continue;
1473
1474 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
1475 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
1476 continue;
1477
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001478 dev_dbg(be->dev, "ASoC: open %s BE %s\n",
1479 stream ? "capture" : "playback", be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001480
1481 be_substream->runtime = be->dpcm[stream].runtime;
1482 err = soc_pcm_open(be_substream);
1483 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001484 dev_err(be->dev, "ASoC: BE open failed %d\n", err);
Liam Girdwood01d75842012-04-25 12:12:49 +01001485 be->dpcm[stream].users--;
1486 if (be->dpcm[stream].users < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001487 dev_err(be->dev, "ASoC: no users %s at unwind %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001488 stream ? "capture" : "playback",
1489 be->dpcm[stream].state);
1490
1491 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1492 goto unwind;
1493 }
1494
1495 be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1496 count++;
1497 }
1498
1499 return count;
1500
1501unwind:
1502 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001503 for_each_dpcm_be_rollback(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001504 struct snd_soc_pcm_runtime *be = dpcm->be;
1505 struct snd_pcm_substream *be_substream =
1506 snd_soc_dpcm_get_substream(be, stream);
1507
1508 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1509 continue;
1510
1511 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001512 dev_err(be->dev, "ASoC: no users %s at close %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001513 stream ? "capture" : "playback",
1514 be->dpcm[stream].state);
1515
1516 if (--be->dpcm[stream].users != 0)
1517 continue;
1518
1519 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1520 continue;
1521
1522 soc_pcm_close(be_substream);
1523 be_substream->runtime = NULL;
1524 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1525 }
1526
1527 return err;
1528}
1529
Kuninori Morimoto5f538982021-02-22 09:47:26 +09001530static void dpcm_runtime_setup_fe(struct snd_pcm_substream *substream)
1531{
1532 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
1533 struct snd_pcm_runtime *runtime = substream->runtime;
1534 struct snd_pcm_hardware *hw = &runtime->hw;
1535 struct snd_soc_dai *dai;
1536 int stream = substream->stream;
1537 int i;
1538
1539 soc_pcm_hw_init(hw);
1540
1541 for_each_rtd_cpu_dais(fe, i, dai) {
1542 struct snd_soc_pcm_stream *cpu_stream;
1543
1544 /*
1545 * Skip CPUs which don't support the current stream
1546 * type. See soc_pcm_init_runtime_hw() for more details
1547 */
1548 if (!snd_soc_dai_stream_valid(dai, stream))
1549 continue;
1550
1551 cpu_stream = snd_soc_dai_get_pcm_stream(dai, stream);
1552
1553 soc_pcm_hw_update_rate(hw, cpu_stream);
1554 soc_pcm_hw_update_chan(hw, cpu_stream);
1555 soc_pcm_hw_update_format(hw, cpu_stream);
1556 }
1557
1558}
1559
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001560static void dpcm_runtime_setup_be_format(struct snd_pcm_substream *substream)
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001561{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001562 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001563 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto4b260f42021-01-22 10:13:48 +09001564 struct snd_pcm_hardware *hw = &runtime->hw;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001565 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001566 struct snd_soc_dai *dai;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001567 int stream = substream->stream;
1568
1569 if (!fe->dai_link->dpcm_merged_format)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001570 return;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001571
1572 /*
1573 * It returns merged BE codec format
1574 * if FE want to use it (= dpcm_merged_format)
1575 */
1576
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001577 for_each_dpcm_be(fe, stream, dpcm) {
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001578 struct snd_soc_pcm_runtime *be = dpcm->be;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001579 struct snd_soc_pcm_stream *codec_stream;
1580 int i;
1581
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001582 for_each_rtd_codec_dais(be, i, dai) {
Jerome Brunet4febced2018-06-27 17:36:38 +02001583 /*
1584 * Skip CODECs which don't support the current stream
1585 * type. See soc_pcm_init_runtime_hw() for more details
1586 */
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001587 if (!snd_soc_dai_stream_valid(dai, stream))
Jerome Brunet4febced2018-06-27 17:36:38 +02001588 continue;
1589
Kuninori Morimotoacf253c2020-02-19 15:56:30 +09001590 codec_stream = snd_soc_dai_get_pcm_stream(dai, stream);
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001591
Kuninori Morimotodebc71f2021-02-04 08:52:04 +09001592 soc_pcm_hw_update_format(hw, codec_stream);
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001593 }
1594 }
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001595}
1596
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001597static void dpcm_runtime_setup_be_chan(struct snd_pcm_substream *substream)
Jiada Wangf4c277b2018-06-20 18:25:20 +09001598{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001599 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001600 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto4b260f42021-01-22 10:13:48 +09001601 struct snd_pcm_hardware *hw = &runtime->hw;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001602 struct snd_soc_dpcm *dpcm;
1603 int stream = substream->stream;
1604
1605 if (!fe->dai_link->dpcm_merged_chan)
1606 return;
1607
Jiada Wangf4c277b2018-06-20 18:25:20 +09001608 /*
1609 * It returns merged BE codec channel;
1610 * if FE want to use it (= dpcm_merged_chan)
1611 */
1612
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001613 for_each_dpcm_be(fe, stream, dpcm) {
Jiada Wangf4c277b2018-06-20 18:25:20 +09001614 struct snd_soc_pcm_runtime *be = dpcm->be;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001615 struct snd_soc_pcm_stream *codec_stream;
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001616 struct snd_soc_pcm_stream *cpu_stream;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001617 struct snd_soc_dai *dai;
1618 int i;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001619
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001620 for_each_rtd_cpu_dais(be, i, dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001621 /*
1622 * Skip CPUs which don't support the current stream
1623 * type. See soc_pcm_init_runtime_hw() for more details
1624 */
1625 if (!snd_soc_dai_stream_valid(dai, stream))
1626 continue;
1627
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001628 cpu_stream = snd_soc_dai_get_pcm_stream(dai, stream);
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001629
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +09001630 soc_pcm_hw_update_chan(hw, cpu_stream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001631 }
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001632
1633 /*
1634 * chan min/max cannot be enforced if there are multiple CODEC
1635 * DAIs connected to a single CPU DAI, use CPU DAI's directly
1636 */
1637 if (be->num_codecs == 1) {
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09001638 codec_stream = snd_soc_dai_get_pcm_stream(asoc_rtd_to_codec(be, 0), stream);
Jiada Wangf4c277b2018-06-20 18:25:20 +09001639
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +09001640 soc_pcm_hw_update_chan(hw, codec_stream);
Jiada Wangf4c277b2018-06-20 18:25:20 +09001641 }
1642 }
1643}
1644
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001645static void dpcm_runtime_setup_be_rate(struct snd_pcm_substream *substream)
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001646{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001647 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001648 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto4b260f42021-01-22 10:13:48 +09001649 struct snd_pcm_hardware *hw = &runtime->hw;
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001650 struct snd_soc_dpcm *dpcm;
1651 int stream = substream->stream;
1652
1653 if (!fe->dai_link->dpcm_merged_rate)
1654 return;
1655
1656 /*
1657 * It returns merged BE codec channel;
1658 * if FE want to use it (= dpcm_merged_chan)
1659 */
1660
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001661 for_each_dpcm_be(fe, stream, dpcm) {
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001662 struct snd_soc_pcm_runtime *be = dpcm->be;
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001663 struct snd_soc_pcm_stream *pcm;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001664 struct snd_soc_dai *dai;
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001665 int i;
1666
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001667 for_each_rtd_dais(be, i, dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001668 /*
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001669 * Skip DAIs which don't support the current stream
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001670 * type. See soc_pcm_init_runtime_hw() for more details
1671 */
1672 if (!snd_soc_dai_stream_valid(dai, stream))
1673 continue;
1674
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001675 pcm = snd_soc_dai_get_pcm_stream(dai, stream);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001676
Kuninori Morimotof6c04af2021-02-04 08:50:31 +09001677 soc_pcm_hw_update_rate(hw, pcm);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001678 }
1679 }
1680}
1681
PC Liao906c7d62015-12-11 11:33:51 +08001682static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
1683 int stream)
1684{
1685 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001686 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001687 struct snd_soc_dai *fe_cpu_dai;
PC Liao906c7d62015-12-11 11:33:51 +08001688 int err;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001689 int i;
PC Liao906c7d62015-12-11 11:33:51 +08001690
1691 /* apply symmetry for FE */
1692 if (soc_pcm_has_symmetry(fe_substream))
1693 fe_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1694
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001695 for_each_rtd_cpu_dais (fe, i, fe_cpu_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001696 /* Symmetry only applies if we've got an active stream. */
Kuninori Morimotof8fc9ec2021-03-09 10:07:42 +09001697 err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai);
1698 if (err < 0)
1699 return err;
PC Liao906c7d62015-12-11 11:33:51 +08001700 }
1701
1702 /* apply symmetry for BE */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001703 for_each_dpcm_be(fe, stream, dpcm) {
PC Liao906c7d62015-12-11 11:33:51 +08001704 struct snd_soc_pcm_runtime *be = dpcm->be;
1705 struct snd_pcm_substream *be_substream =
1706 snd_soc_dpcm_get_substream(be, stream);
Jerome Brunet6246f282019-04-01 15:03:54 +02001707 struct snd_soc_pcm_runtime *rtd;
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001708 struct snd_soc_dai *dai;
PC Liao906c7d62015-12-11 11:33:51 +08001709
Jerome Brunet6246f282019-04-01 15:03:54 +02001710 /* A backend may not have the requested substream */
1711 if (!be_substream)
1712 continue;
1713
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001714 rtd = asoc_substream_to_rtd(be_substream);
Jeeja KPf1176612016-09-06 14:17:55 +05301715 if (rtd->dai_link->be_hw_params_fixup)
1716 continue;
1717
PC Liao906c7d62015-12-11 11:33:51 +08001718 if (soc_pcm_has_symmetry(be_substream))
1719 be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1720
1721 /* Symmetry only applies if we've got an active stream. */
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001722 for_each_rtd_dais(rtd, i, dai) {
Kuninori Morimotof8fc9ec2021-03-09 10:07:42 +09001723 err = soc_pcm_apply_symmetry(fe_substream, dai);
1724 if (err < 0)
1725 return err;
PC Liao906c7d62015-12-11 11:33:51 +08001726 }
1727 }
1728
1729 return 0;
1730}
1731
Liam Girdwood01d75842012-04-25 12:12:49 +01001732static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
1733{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001734 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001735 int stream = fe_substream->stream, ret = 0;
1736
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001737 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001738
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09001739 ret = dpcm_be_dai_startup(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001740 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001741 dev_err(fe->dev,"ASoC: failed to start some BEs %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001742 goto be_err;
1743 }
1744
Liam Girdwood103d84a2012-11-19 14:39:15 +00001745 dev_dbg(fe->dev, "ASoC: open FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001746
1747 /* start the DAI frontend */
1748 ret = soc_pcm_open(fe_substream);
1749 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001750 dev_err(fe->dev,"ASoC: failed to start FE %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001751 goto unwind;
1752 }
1753
1754 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1755
Kuninori Morimoto4fe28462021-02-22 09:47:36 +09001756 dpcm_runtime_setup_fe(fe_substream);
1757
1758 dpcm_runtime_setup_be_format(fe_substream);
1759 dpcm_runtime_setup_be_chan(fe_substream);
1760 dpcm_runtime_setup_be_rate(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001761
PC Liao906c7d62015-12-11 11:33:51 +08001762 ret = dpcm_apply_symmetry(fe_substream, stream);
Kuninori Morimoto8a01fbf2020-03-06 10:09:59 +09001763 if (ret < 0)
PC Liao906c7d62015-12-11 11:33:51 +08001764 dev_err(fe->dev, "ASoC: failed to apply dpcm symmetry %d\n",
1765 ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001766
1767unwind:
Kuninori Morimoto8a01fbf2020-03-06 10:09:59 +09001768 if (ret < 0)
1769 dpcm_be_dai_startup_unwind(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001770be_err:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001771 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001772 return ret;
1773}
1774
Liam Girdwood23607022014-01-17 17:03:55 +00001775int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001776{
1777 struct snd_soc_dpcm *dpcm;
1778
1779 /* only shutdown BEs that are either sinks or sources to this FE DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001780 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001781
1782 struct snd_soc_pcm_runtime *be = dpcm->be;
1783 struct snd_pcm_substream *be_substream =
1784 snd_soc_dpcm_get_substream(be, stream);
1785
1786 /* is this op for this BE ? */
1787 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1788 continue;
1789
1790 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001791 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001792 stream ? "capture" : "playback",
1793 be->dpcm[stream].state);
1794
1795 if (--be->dpcm[stream].users != 0)
1796 continue;
1797
1798 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Kai Chieh Chuang9c0ac702018-05-28 10:18:18 +08001799 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) {
1800 soc_pcm_hw_free(be_substream);
1801 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1802 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001803
Liam Girdwood103d84a2012-11-19 14:39:15 +00001804 dev_dbg(be->dev, "ASoC: close BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001805 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001806
1807 soc_pcm_close(be_substream);
1808 be_substream->runtime = NULL;
1809
1810 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1811 }
1812 return 0;
1813}
1814
1815static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
1816{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001817 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001818 int stream = substream->stream;
1819
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001820 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001821
1822 /* shutdown the BEs */
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09001823 dpcm_be_dai_shutdown(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001824
Liam Girdwood103d84a2012-11-19 14:39:15 +00001825 dev_dbg(fe->dev, "ASoC: close FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001826
1827 /* now shutdown the frontend */
1828 soc_pcm_close(substream);
1829
Ranjani Sridharanbb9dd3c2020-12-02 11:33:43 -08001830 /* run the stream stop event */
1831 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
1832
Liam Girdwood01d75842012-04-25 12:12:49 +01001833 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001834 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001835 return 0;
1836}
1837
Liam Girdwood23607022014-01-17 17:03:55 +00001838int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001839{
1840 struct snd_soc_dpcm *dpcm;
1841
1842 /* only hw_params backends that are either sinks or sources
1843 * to this frontend DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001844 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001845
1846 struct snd_soc_pcm_runtime *be = dpcm->be;
1847 struct snd_pcm_substream *be_substream =
1848 snd_soc_dpcm_get_substream(be, stream);
1849
1850 /* is this op for this BE ? */
1851 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1852 continue;
1853
1854 /* only free hw when no longer used - check all FEs */
1855 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1856 continue;
1857
Qiao Zhou36fba622014-12-03 10:13:43 +08001858 /* do not free hw if this BE is used by other FE */
1859 if (be->dpcm[stream].users > 1)
1860 continue;
1861
Liam Girdwood01d75842012-04-25 12:12:49 +01001862 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1863 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
1864 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Patrick Lai08b27842012-12-19 19:36:02 -08001865 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
Vinod Koul5e82d2b2016-02-01 22:26:40 +05301866 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
1867 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
Liam Girdwood01d75842012-04-25 12:12:49 +01001868 continue;
1869
Liam Girdwood103d84a2012-11-19 14:39:15 +00001870 dev_dbg(be->dev, "ASoC: hw_free BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001871 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001872
1873 soc_pcm_hw_free(be_substream);
1874
1875 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1876 }
1877
1878 return 0;
1879}
1880
Mark Brown45c0a182012-05-09 21:46:27 +01001881static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001882{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001883 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001884 int err, stream = substream->stream;
1885
1886 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001887 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001888
Liam Girdwood103d84a2012-11-19 14:39:15 +00001889 dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001890
1891 /* call hw_free on the frontend */
1892 err = soc_pcm_hw_free(substream);
1893 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001894 dev_err(fe->dev,"ASoC: hw_free FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001895 fe->dai_link->name);
1896
1897 /* only hw_params backends that are either sinks or sources
1898 * to this frontend DAI */
1899 err = dpcm_be_dai_hw_free(fe, stream);
Pierre-Louis Bossart61456212021-02-18 16:19:19 -06001900 if (err < 0)
1901 dev_err(fe->dev, "ASoC: hw_free BE failed %d\n", err);
Liam Girdwood01d75842012-04-25 12:12:49 +01001902
1903 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001904 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001905
1906 mutex_unlock(&fe->card->mutex);
1907 return 0;
1908}
1909
Liam Girdwood23607022014-01-17 17:03:55 +00001910int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001911{
1912 struct snd_soc_dpcm *dpcm;
1913 int ret;
1914
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001915 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001916
1917 struct snd_soc_pcm_runtime *be = dpcm->be;
1918 struct snd_pcm_substream *be_substream =
1919 snd_soc_dpcm_get_substream(be, stream);
1920
1921 /* is this op for this BE ? */
1922 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1923 continue;
1924
Liam Girdwood01d75842012-04-25 12:12:49 +01001925 /* copy params for each dpcm */
1926 memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params,
1927 sizeof(struct snd_pcm_hw_params));
1928
1929 /* perform any hw_params fixups */
Kuninori Morimoto0cbbf8a2020-05-25 09:57:36 +09001930 ret = snd_soc_link_be_hw_params_fixup(be, &dpcm->hw_params);
1931 if (ret < 0)
1932 goto unwind;
Liam Girdwood01d75842012-04-25 12:12:49 +01001933
Libin Yangae061d22019-04-19 09:53:12 +08001934 /* copy the fixed-up hw params for BE dai */
1935 memcpy(&be->dpcm[stream].hw_params, &dpcm->hw_params,
1936 sizeof(struct snd_pcm_hw_params));
1937
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00001938 /* only allow hw_params() if no connected FEs are running */
1939 if (!snd_soc_dpcm_can_be_params(fe, be, stream))
1940 continue;
1941
1942 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
1943 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1944 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE))
1945 continue;
1946
1947 dev_dbg(be->dev, "ASoC: hw_params BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001948 be->dai_link->name);
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00001949
Liam Girdwood01d75842012-04-25 12:12:49 +01001950 ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params);
1951 if (ret < 0) {
1952 dev_err(dpcm->be->dev,
Liam Girdwood103d84a2012-11-19 14:39:15 +00001953 "ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001954 goto unwind;
1955 }
1956
1957 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
1958 }
1959 return 0;
1960
1961unwind:
1962 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001963 for_each_dpcm_be_rollback(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001964 struct snd_soc_pcm_runtime *be = dpcm->be;
1965 struct snd_pcm_substream *be_substream =
1966 snd_soc_dpcm_get_substream(be, stream);
1967
1968 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1969 continue;
1970
1971 /* only allow hw_free() if no connected FEs are running */
1972 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1973 continue;
1974
1975 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
1976 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1977 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
1978 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
1979 continue;
1980
1981 soc_pcm_hw_free(be_substream);
1982 }
1983
1984 return ret;
1985}
1986
Mark Brown45c0a182012-05-09 21:46:27 +01001987static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
1988 struct snd_pcm_hw_params *params)
Liam Girdwood01d75842012-04-25 12:12:49 +01001989{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001990 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001991 int ret, stream = substream->stream;
1992
1993 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001994 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001995
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09001996 memcpy(&fe->dpcm[stream].hw_params, params,
Liam Girdwood01d75842012-04-25 12:12:49 +01001997 sizeof(struct snd_pcm_hw_params));
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09001998 ret = dpcm_be_dai_hw_params(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001999 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002000 dev_err(fe->dev,"ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002001 goto out;
2002 }
2003
Liam Girdwood103d84a2012-11-19 14:39:15 +00002004 dev_dbg(fe->dev, "ASoC: hw_params FE %s rate %d chan %x fmt %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002005 fe->dai_link->name, params_rate(params),
2006 params_channels(params), params_format(params));
2007
2008 /* call hw_params on the frontend */
2009 ret = soc_pcm_hw_params(substream, params);
2010 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002011 dev_err(fe->dev,"ASoC: hw_params FE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002012 dpcm_be_dai_hw_free(fe, stream);
2013 } else
2014 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2015
2016out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002017 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002018 mutex_unlock(&fe->card->mutex);
2019 return ret;
2020}
2021
Liam Girdwood23607022014-01-17 17:03:55 +00002022int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
Mark Brown45c0a182012-05-09 21:46:27 +01002023 int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002024{
2025 struct snd_soc_dpcm *dpcm;
2026 int ret = 0;
2027
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002028 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002029
2030 struct snd_soc_pcm_runtime *be = dpcm->be;
2031 struct snd_pcm_substream *be_substream =
2032 snd_soc_dpcm_get_substream(be, stream);
2033
2034 /* is this op for this BE ? */
2035 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2036 continue;
2037
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002038 dev_dbg(be->dev, "ASoC: trigger BE %s cmd %d\n",
2039 be->dai_link->name, cmd);
2040
Liam Girdwood01d75842012-04-25 12:12:49 +01002041 switch (cmd) {
2042 case SNDRV_PCM_TRIGGER_START:
2043 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
이경택21fca8b2020-04-01 10:04:21 +09002044 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
2045 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Liam Girdwood01d75842012-04-25 12:12:49 +01002046 continue;
2047
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002048 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002049 if (ret)
2050 return ret;
2051
2052 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2053 break;
2054 case SNDRV_PCM_TRIGGER_RESUME:
2055 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
2056 continue;
2057
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002058 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002059 if (ret)
2060 return ret;
2061
2062 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2063 break;
2064 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2065 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
2066 continue;
2067
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002068 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002069 if (ret)
2070 return ret;
2071
2072 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2073 break;
2074 case SNDRV_PCM_TRIGGER_STOP:
이경택21fca8b2020-04-01 10:04:21 +09002075 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) &&
2076 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Liam Girdwood01d75842012-04-25 12:12:49 +01002077 continue;
2078
2079 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2080 continue;
2081
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002082 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002083 if (ret)
2084 return ret;
2085
2086 be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2087 break;
2088 case SNDRV_PCM_TRIGGER_SUSPEND:
Nicolin Chen868a6ca2014-05-12 20:12:05 +08002089 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
Liam Girdwood01d75842012-04-25 12:12:49 +01002090 continue;
2091
2092 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2093 continue;
2094
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002095 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002096 if (ret)
2097 return ret;
2098
2099 be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND;
2100 break;
2101 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2102 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2103 continue;
2104
2105 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2106 continue;
2107
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002108 ret = soc_pcm_trigger(be_substream, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002109 if (ret)
2110 return ret;
2111
2112 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2113 break;
2114 }
2115 }
2116
2117 return ret;
2118}
2119EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
2120
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002121static int dpcm_dai_trigger_fe_be(struct snd_pcm_substream *substream,
2122 int cmd, bool fe_first)
2123{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002124 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002125 int ret;
2126
2127 /* call trigger on the frontend before the backend. */
2128 if (fe_first) {
2129 dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n",
2130 fe->dai_link->name, cmd);
2131
2132 ret = soc_pcm_trigger(substream, cmd);
2133 if (ret < 0)
2134 return ret;
2135
2136 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2137 return ret;
2138 }
2139
2140 /* call trigger on the frontend after the backend. */
2141 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2142 if (ret < 0)
2143 return ret;
2144
2145 dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n",
2146 fe->dai_link->name, cmd);
2147
2148 ret = soc_pcm_trigger(substream, cmd);
2149
2150 return ret;
2151}
2152
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002153static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002154{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002155 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002156 int stream = substream->stream;
2157 int ret = 0;
Liam Girdwood01d75842012-04-25 12:12:49 +01002158 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
2159
2160 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
2161
2162 switch (trigger) {
2163 case SND_SOC_DPCM_TRIGGER_PRE:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002164 switch (cmd) {
2165 case SNDRV_PCM_TRIGGER_START:
2166 case SNDRV_PCM_TRIGGER_RESUME:
2167 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Cezary Rojewski4c22b802020-10-26 11:01:29 +01002168 case SNDRV_PCM_TRIGGER_DRAIN:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002169 ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
2170 break;
2171 case SNDRV_PCM_TRIGGER_STOP:
2172 case SNDRV_PCM_TRIGGER_SUSPEND:
2173 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2174 ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
2175 break;
2176 default:
2177 ret = -EINVAL;
2178 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002179 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002180 break;
2181 case SND_SOC_DPCM_TRIGGER_POST:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002182 switch (cmd) {
2183 case SNDRV_PCM_TRIGGER_START:
2184 case SNDRV_PCM_TRIGGER_RESUME:
2185 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Cezary Rojewski4c22b802020-10-26 11:01:29 +01002186 case SNDRV_PCM_TRIGGER_DRAIN:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002187 ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
2188 break;
2189 case SNDRV_PCM_TRIGGER_STOP:
2190 case SNDRV_PCM_TRIGGER_SUSPEND:
2191 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2192 ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
2193 break;
2194 default:
2195 ret = -EINVAL;
2196 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002197 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002198 break;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002199 case SND_SOC_DPCM_TRIGGER_BESPOKE:
2200 /* bespoke trigger() - handles both FE and BEs */
2201
Liam Girdwood103d84a2012-11-19 14:39:15 +00002202 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd %d\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002203 fe->dai_link->name, cmd);
2204
Kuninori Morimoto308193582020-04-24 08:15:09 +09002205 ret = snd_soc_pcm_dai_bespoke_trigger(substream, cmd);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002206 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002207 default:
Liam Girdwood103d84a2012-11-19 14:39:15 +00002208 dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd,
Liam Girdwood01d75842012-04-25 12:12:49 +01002209 fe->dai_link->name);
2210 ret = -EINVAL;
2211 goto out;
2212 }
2213
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002214 if (ret < 0) {
2215 dev_err(fe->dev, "ASoC: trigger FE cmd: %d failed: %d\n",
2216 cmd, ret);
2217 goto out;
2218 }
2219
Liam Girdwood01d75842012-04-25 12:12:49 +01002220 switch (cmd) {
2221 case SNDRV_PCM_TRIGGER_START:
2222 case SNDRV_PCM_TRIGGER_RESUME:
2223 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2224 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2225 break;
2226 case SNDRV_PCM_TRIGGER_STOP:
2227 case SNDRV_PCM_TRIGGER_SUSPEND:
Liam Girdwood01d75842012-04-25 12:12:49 +01002228 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2229 break;
Patrick Lai9f169b92016-12-31 22:44:39 -08002230 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2231 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2232 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002233 }
2234
2235out:
2236 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
2237 return ret;
2238}
2239
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002240static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
2241{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002242 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002243 int stream = substream->stream;
2244
2245 /* if FE's runtime_update is already set, we're in race;
2246 * process this trigger later at exit
2247 */
2248 if (fe->dpcm[stream].runtime_update != SND_SOC_DPCM_UPDATE_NO) {
2249 fe->dpcm[stream].trigger_pending = cmd + 1;
2250 return 0; /* delayed, assuming it's successful */
2251 }
2252
2253 /* we're alone, let's trigger */
2254 return dpcm_fe_dai_do_trigger(substream, cmd);
2255}
2256
Liam Girdwood23607022014-01-17 17:03:55 +00002257int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002258{
2259 struct snd_soc_dpcm *dpcm;
2260 int ret = 0;
2261
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002262 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002263
2264 struct snd_soc_pcm_runtime *be = dpcm->be;
2265 struct snd_pcm_substream *be_substream =
2266 snd_soc_dpcm_get_substream(be, stream);
2267
2268 /* is this op for this BE ? */
2269 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2270 continue;
2271
2272 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
Koro Chen95f444d2015-10-28 10:15:34 +08002273 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
Libin Yang5087a8f2019-05-08 10:32:41 +08002274 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND) &&
2275 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Liam Girdwood01d75842012-04-25 12:12:49 +01002276 continue;
2277
Liam Girdwood103d84a2012-11-19 14:39:15 +00002278 dev_dbg(be->dev, "ASoC: prepare BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002279 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002280
2281 ret = soc_pcm_prepare(be_substream);
2282 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002283 dev_err(be->dev, "ASoC: backend prepare failed %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002284 ret);
2285 break;
2286 }
2287
2288 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2289 }
2290 return ret;
2291}
2292
Mark Brown45c0a182012-05-09 21:46:27 +01002293static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002294{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002295 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002296 int stream = substream->stream, ret = 0;
2297
2298 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2299
Liam Girdwood103d84a2012-11-19 14:39:15 +00002300 dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002301
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002302 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002303
2304 /* there is no point preparing this FE if there are no BEs */
2305 if (list_empty(&fe->dpcm[stream].be_clients)) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002306 dev_err(fe->dev, "ASoC: no backend DAIs enabled for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002307 fe->dai_link->name);
2308 ret = -EINVAL;
2309 goto out;
2310 }
2311
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09002312 ret = dpcm_be_dai_prepare(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002313 if (ret < 0)
2314 goto out;
2315
2316 /* call prepare on the frontend */
2317 ret = soc_pcm_prepare(substream);
2318 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002319 dev_err(fe->dev,"ASoC: prepare FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002320 fe->dai_link->name);
2321 goto out;
2322 }
2323
Liam Girdwood01d75842012-04-25 12:12:49 +01002324 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2325
2326out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002327 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002328 mutex_unlock(&fe->card->mutex);
2329
2330 return ret;
2331}
2332
Liam Girdwood618dae12012-04-25 12:12:51 +01002333static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
2334{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002335 struct snd_pcm_substream *substream =
2336 snd_soc_dpcm_get_substream(fe, stream);
2337 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01002338 int err;
Liam Girdwood01d75842012-04-25 12:12:49 +01002339
Liam Girdwood103d84a2012-11-19 14:39:15 +00002340 dev_dbg(fe->dev, "ASoC: runtime %s close on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002341 stream ? "capture" : "playback", fe->dai_link->name);
2342
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002343 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2344 /* call bespoke trigger - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002345 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002346 fe->dai_link->name);
2347
Kuninori Morimoto308193582020-04-24 08:15:09 +09002348 err = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002349 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002350 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002351 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002352 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002353 fe->dai_link->name);
2354
2355 err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
2356 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002357 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002358 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002359
2360 err = dpcm_be_dai_hw_free(fe, stream);
2361 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002362 dev_err(fe->dev,"ASoC: hw_free FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002363
2364 err = dpcm_be_dai_shutdown(fe, stream);
2365 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002366 dev_err(fe->dev,"ASoC: shutdown FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002367
2368 /* run the stream event for each BE */
2369 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2370
2371 return 0;
2372}
2373
2374static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
2375{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002376 struct snd_pcm_substream *substream =
2377 snd_soc_dpcm_get_substream(fe, stream);
Liam Girdwood618dae12012-04-25 12:12:51 +01002378 struct snd_soc_dpcm *dpcm;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002379 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Souptick Joarder4eeed5f2021-01-09 09:15:01 +05302380 int ret = 0;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002381 unsigned long flags;
Liam Girdwood618dae12012-04-25 12:12:51 +01002382
Liam Girdwood103d84a2012-11-19 14:39:15 +00002383 dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002384 stream ? "capture" : "playback", fe->dai_link->name);
2385
2386 /* Only start the BE if the FE is ready */
2387 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
朱灿灿2c138282020-12-25 16:42:46 +08002388 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE) {
2389 dev_err(fe->dev, "ASoC: FE %s is not ready %d\n",
2390 fe->dai_link->name, fe->dpcm[stream].state);
Dan Carpentere91b65b2021-01-11 12:50:21 +03002391 ret = -EINVAL;
朱灿灿2c138282020-12-25 16:42:46 +08002392 goto disconnect;
2393 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002394
2395 /* startup must always be called for new BEs */
2396 ret = dpcm_be_dai_startup(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002397 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002398 goto disconnect;
Liam Girdwood618dae12012-04-25 12:12:51 +01002399
2400 /* keep going if FE state is > open */
2401 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN)
2402 return 0;
2403
2404 ret = dpcm_be_dai_hw_params(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002405 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002406 goto close;
Liam Girdwood618dae12012-04-25 12:12:51 +01002407
2408 /* keep going if FE state is > hw_params */
2409 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS)
2410 return 0;
2411
2412
2413 ret = dpcm_be_dai_prepare(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002414 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002415 goto hw_free;
Liam Girdwood618dae12012-04-25 12:12:51 +01002416
2417 /* run the stream event for each BE */
2418 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2419
2420 /* keep going if FE state is > prepare */
2421 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE ||
2422 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP)
2423 return 0;
2424
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002425 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2426 /* call trigger on the frontend - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002427 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002428 fe->dai_link->name);
Liam Girdwood618dae12012-04-25 12:12:51 +01002429
Kuninori Morimoto308193582020-04-24 08:15:09 +09002430 ret = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002431 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002432 dev_err(fe->dev,"ASoC: bespoke trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002433 goto hw_free;
2434 }
2435 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002436 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002437 fe->dai_link->name);
2438
2439 ret = dpcm_be_dai_trigger(fe, stream,
2440 SNDRV_PCM_TRIGGER_START);
2441 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002442 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002443 goto hw_free;
2444 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002445 }
2446
2447 return 0;
2448
2449hw_free:
2450 dpcm_be_dai_hw_free(fe, stream);
2451close:
2452 dpcm_be_dai_shutdown(fe, stream);
2453disconnect:
朱灿灿2c138282020-12-25 16:42:46 +08002454 /* disconnect any pending BEs */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002455 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002456 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood618dae12012-04-25 12:12:51 +01002457 struct snd_soc_pcm_runtime *be = dpcm->be;
朱灿灿2c138282020-12-25 16:42:46 +08002458
2459 /* is this op for this BE ? */
2460 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2461 continue;
2462
2463 if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE ||
2464 be->dpcm[stream].state == SND_SOC_DPCM_STATE_NEW)
2465 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
Liam Girdwood618dae12012-04-25 12:12:51 +01002466 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002467 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood618dae12012-04-25 12:12:51 +01002468
2469 return ret;
2470}
2471
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002472static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
2473{
2474 struct snd_soc_dapm_widget_list *list;
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002475 int stream;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002476 int count, paths;
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002477 int ret;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002478
Pierre-Louis Bossart96bf62f2020-06-12 15:35:07 -05002479 if (!fe->dai_link->dynamic)
2480 return 0;
2481
Bard Liao6e1276a2020-02-25 21:39:16 +08002482 if (fe->num_cpus > 1) {
2483 dev_err(fe->dev,
2484 "%s doesn't support Multi CPU yet\n", __func__);
2485 return -EINVAL;
2486 }
2487
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002488 /* only check active links */
Kuninori Morimotob3dea622020-05-15 09:46:51 +09002489 if (!snd_soc_dai_active(asoc_rtd_to_cpu(fe, 0)))
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002490 return 0;
2491
2492 /* DAPM sync will call this to update DSP paths */
2493 dev_dbg(fe->dev, "ASoC: DPCM %s runtime update for FE %s\n",
2494 new ? "new" : "old", fe->dai_link->name);
2495
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002496 for_each_pcm_streams(stream) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002497
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002498 /* skip if FE doesn't have playback/capture capability */
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002499 if (!snd_soc_dai_stream_valid(asoc_rtd_to_cpu(fe, 0), stream) ||
2500 !snd_soc_dai_stream_valid(asoc_rtd_to_codec(fe, 0), stream))
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002501 continue;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002502
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002503 /* skip if FE isn't currently playing/capturing */
Kuninori Morimotob3dea622020-05-15 09:46:51 +09002504 if (!snd_soc_dai_stream_active(asoc_rtd_to_cpu(fe, 0), stream) ||
2505 !snd_soc_dai_stream_active(asoc_rtd_to_codec(fe, 0), stream))
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002506 continue;
2507
2508 paths = dpcm_path_get(fe, stream, &list);
2509 if (paths < 0) {
2510 dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
2511 fe->dai_link->name,
2512 stream == SNDRV_PCM_STREAM_PLAYBACK ?
2513 "playback" : "capture");
2514 return paths;
2515 }
2516
2517 /* update any playback/capture paths */
2518 count = dpcm_process_paths(fe, stream, &list, new);
2519 if (count) {
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002520 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002521 if (new)
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002522 ret = dpcm_run_update_startup(fe, stream);
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002523 else
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002524 ret = dpcm_run_update_shutdown(fe, stream);
2525 if (ret < 0)
2526 dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n");
2527 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002528
2529 dpcm_clear_pending_state(fe, stream);
2530 dpcm_be_disconnect(fe, stream);
2531 }
2532
2533 dpcm_path_put(&list);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002534 }
2535
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002536 return 0;
2537}
2538
Liam Girdwood618dae12012-04-25 12:12:51 +01002539/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
2540 * any DAI links.
2541 */
Guennadi Liakhovetskif17a1472020-03-12 10:52:14 +01002542int snd_soc_dpcm_runtime_update(struct snd_soc_card *card)
Liam Girdwood618dae12012-04-25 12:12:51 +01002543{
Mengdong Lin1a497982015-11-18 02:34:11 -05002544 struct snd_soc_pcm_runtime *fe;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002545 int ret = 0;
Liam Girdwood618dae12012-04-25 12:12:51 +01002546
Liam Girdwood618dae12012-04-25 12:12:51 +01002547 mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002548 /* shutdown all old paths first */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002549 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002550 ret = soc_dpcm_fe_runtime_update(fe, 0);
2551 if (ret)
2552 goto out;
Liam Girdwood618dae12012-04-25 12:12:51 +01002553 }
2554
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002555 /* bring new paths up */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002556 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002557 ret = soc_dpcm_fe_runtime_update(fe, 1);
2558 if (ret)
2559 goto out;
2560 }
2561
2562out:
Liam Girdwood618dae12012-04-25 12:12:51 +01002563 mutex_unlock(&card->mutex);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002564 return ret;
Liam Girdwood618dae12012-04-25 12:12:51 +01002565}
Guennadi Liakhovetskif17a1472020-03-12 10:52:14 +01002566EXPORT_SYMBOL_GPL(snd_soc_dpcm_runtime_update);
Liam Girdwood01d75842012-04-25 12:12:49 +01002567
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002568static void dpcm_fe_dai_cleanup(struct snd_pcm_substream *fe_substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002569{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002570 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002571 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002572 int stream = fe_substream->stream;
Kuninori Morimoto30fca262020-03-06 10:09:44 +09002573
2574 /* mark FE's links ready to prune */
2575 for_each_dpcm_be(fe, stream, dpcm)
2576 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2577
2578 dpcm_be_disconnect(fe, stream);
2579
2580 fe->dpcm[stream].runtime = NULL;
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002581}
2582
2583static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
2584{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002585 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002586 int ret;
2587
2588 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2589 ret = dpcm_fe_dai_shutdown(fe_substream);
2590
2591 dpcm_fe_dai_cleanup(fe_substream);
2592
Kuninori Morimoto30fca262020-03-06 10:09:44 +09002593 mutex_unlock(&fe->card->mutex);
2594 return ret;
2595}
2596
Liam Girdwood01d75842012-04-25 12:12:49 +01002597static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
2598{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002599 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002600 struct snd_soc_dapm_widget_list *list;
2601 int ret;
2602 int stream = fe_substream->stream;
2603
2604 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2605 fe->dpcm[stream].runtime = fe_substream->runtime;
2606
Qiao Zhou8f70e512014-09-10 17:54:07 +08002607 ret = dpcm_path_get(fe, stream, &list);
2608 if (ret < 0) {
Kuninori Morimotocae06eb2020-02-17 17:28:11 +09002609 goto open_end;
Qiao Zhou8f70e512014-09-10 17:54:07 +08002610 } else if (ret == 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002611 dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002612 fe->dai_link->name, stream ? "capture" : "playback");
Liam Girdwood01d75842012-04-25 12:12:49 +01002613 }
2614
2615 /* calculate valid and active FE <-> BE dpcms */
2616 dpcm_process_paths(fe, stream, &list, 1);
2617
2618 ret = dpcm_fe_dai_startup(fe_substream);
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002619 if (ret < 0)
2620 dpcm_fe_dai_cleanup(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002621
2622 dpcm_clear_pending_state(fe, stream);
2623 dpcm_path_put(&list);
Kuninori Morimotocae06eb2020-02-17 17:28:11 +09002624open_end:
Liam Girdwood01d75842012-04-25 12:12:49 +01002625 mutex_unlock(&fe->card->mutex);
2626 return ret;
2627}
2628
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002629static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd,
2630 int *playback, int *capture)
Liam Girdwoodddee6272011-06-09 14:45:53 +01002631{
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002632 struct snd_soc_dai *codec_dai;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002633 struct snd_soc_dai *cpu_dai;
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002634 int stream;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002635 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002636
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002637 if (rtd->dai_link->dynamic && rtd->num_cpus > 1) {
2638 dev_err(rtd->dev,
2639 "DPCM doesn't support Multi CPU for Front-Ends yet\n");
2640 return -EINVAL;
2641 }
Stephan Gerhold9b5db052020-04-15 12:49:28 +02002642
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002643 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
2644 if (rtd->dai_link->dpcm_playback) {
2645 stream = SNDRV_PCM_STREAM_PLAYBACK;
2646
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002647 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
2648 if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002649 *playback = 1;
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002650 break;
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002651 }
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002652 }
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002653 if (!*playback) {
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002654 dev_err(rtd->card->dev,
2655 "No CPU DAIs support playback for stream %s\n",
2656 rtd->dai_link->stream_name);
2657 return -EINVAL;
2658 }
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002659 }
2660 if (rtd->dai_link->dpcm_capture) {
2661 stream = SNDRV_PCM_STREAM_CAPTURE;
2662
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002663 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
2664 if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002665 *capture = 1;
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002666 break;
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002667 }
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002668 }
2669
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002670 if (!*capture) {
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002671 dev_err(rtd->card->dev,
2672 "No CPU DAIs support capture for stream %s\n",
2673 rtd->dai_link->stream_name);
2674 return -EINVAL;
2675 }
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002676 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002677 } else {
Jerome Bruneta3420312019-07-25 18:59:47 +02002678 /* Adapt stream for codec2codec links */
Stephan Gerholda4877a62020-02-18 11:38:24 +01002679 int cpu_capture = rtd->dai_link->params ?
2680 SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
2681 int cpu_playback = rtd->dai_link->params ?
2682 SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
Jerome Bruneta3420312019-07-25 18:59:47 +02002683
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09002684 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002685 if (rtd->num_cpus == 1) {
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002686 cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002687 } else if (rtd->num_cpus == rtd->num_codecs) {
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002688 cpu_dai = asoc_rtd_to_cpu(rtd, i);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002689 } else {
2690 dev_err(rtd->card->dev,
2691 "N cpus to M codecs link is not supported yet\n");
2692 return -EINVAL;
2693 }
2694
Kuninori Morimoto467fece2019-07-22 10:36:16 +09002695 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
Stephan Gerholda4877a62020-02-18 11:38:24 +01002696 snd_soc_dai_stream_valid(cpu_dai, cpu_playback))
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002697 *playback = 1;
Kuninori Morimoto467fece2019-07-22 10:36:16 +09002698 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
Stephan Gerholda4877a62020-02-18 11:38:24 +01002699 snd_soc_dai_stream_valid(cpu_dai, cpu_capture))
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002700 *capture = 1;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002701 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002702 }
Sangsu Parka5002312012-01-02 17:15:10 +09002703
Fabio Estevamd6bead02013-08-29 10:32:13 -03002704 if (rtd->dai_link->playback_only) {
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002705 *playback = 1;
2706 *capture = 0;
Fabio Estevamd6bead02013-08-29 10:32:13 -03002707 }
2708
2709 if (rtd->dai_link->capture_only) {
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002710 *playback = 0;
2711 *capture = 1;
Fabio Estevamd6bead02013-08-29 10:32:13 -03002712 }
2713
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002714 return 0;
2715}
2716
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002717static int soc_create_pcm(struct snd_pcm **pcm,
2718 struct snd_soc_pcm_runtime *rtd,
2719 int playback, int capture, int num)
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002720{
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002721 char new_name[64];
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002722 int ret;
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002723
Liam Girdwood01d75842012-04-25 12:12:49 +01002724 /* create the PCM */
Jerome Bruneta3420312019-07-25 18:59:47 +02002725 if (rtd->dai_link->params) {
2726 snprintf(new_name, sizeof(new_name), "codec2codec(%s)",
2727 rtd->dai_link->stream_name);
2728
2729 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002730 playback, capture, pcm);
Jerome Bruneta3420312019-07-25 18:59:47 +02002731 } else if (rtd->dai_link->no_pcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002732 snprintf(new_name, sizeof(new_name), "(%s)",
2733 rtd->dai_link->stream_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002734
Liam Girdwood01d75842012-04-25 12:12:49 +01002735 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002736 playback, capture, pcm);
Liam Girdwood01d75842012-04-25 12:12:49 +01002737 } else {
2738 if (rtd->dai_link->dynamic)
2739 snprintf(new_name, sizeof(new_name), "%s (*)",
2740 rtd->dai_link->stream_name);
2741 else
2742 snprintf(new_name, sizeof(new_name), "%s %s-%d",
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002743 rtd->dai_link->stream_name,
2744 (rtd->num_codecs > 1) ?
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002745 "multicodec" : asoc_rtd_to_codec(rtd, 0)->name, num);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002746
Liam Girdwood01d75842012-04-25 12:12:49 +01002747 ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002748 capture, pcm);
Liam Girdwood01d75842012-04-25 12:12:49 +01002749 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01002750 if (ret < 0) {
Pierre-Louis Bossart799827a2020-06-12 15:40:49 -05002751 dev_err(rtd->card->dev, "ASoC: can't create pcm %s for dailink %s: %d\n",
2752 new_name, rtd->dai_link->name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002753 return ret;
2754 }
Liam Girdwood103d84a2012-11-19 14:39:15 +00002755 dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002756
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002757 return 0;
2758}
2759
2760/* create a new pcm */
2761int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
2762{
2763 struct snd_soc_component *component;
2764 struct snd_pcm *pcm;
2765 int ret = 0, playback = 0, capture = 0;
2766 int i;
2767
2768 ret = soc_get_playback_capture(rtd, &playback, &capture);
2769 if (ret < 0)
2770 return ret;
2771
2772 ret = soc_create_pcm(&pcm, rtd, playback, capture, num);
2773 if (ret < 0)
2774 return ret;
2775
Liam Girdwoodddee6272011-06-09 14:45:53 +01002776 /* DAPM dai link stream work */
Jerome Bruneta3420312019-07-25 18:59:47 +02002777 if (rtd->dai_link->params)
Curtis Malainey4bf2e382019-12-03 09:30:07 -08002778 rtd->close_delayed_work_func = codec2codec_close_delayed_work;
Jerome Bruneta3420312019-07-25 18:59:47 +02002779 else
Kuninori Morimoto83f94a22020-01-10 11:36:17 +09002780 rtd->close_delayed_work_func = snd_soc_close_delayed_work;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002781
2782 rtd->pcm = pcm;
Kuninori Morimotoe04e7b82021-01-22 10:13:32 +09002783 pcm->nonatomic = rtd->dai_link->nonatomic;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002784 pcm->private_data = rtd;
Liam Girdwood01d75842012-04-25 12:12:49 +01002785
Jerome Bruneta3420312019-07-25 18:59:47 +02002786 if (rtd->dai_link->no_pcm || rtd->dai_link->params) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002787 if (playback)
2788 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
2789 if (capture)
2790 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
2791 goto out;
2792 }
2793
2794 /* ASoC PCM operations */
2795 if (rtd->dai_link->dynamic) {
2796 rtd->ops.open = dpcm_fe_dai_open;
2797 rtd->ops.hw_params = dpcm_fe_dai_hw_params;
2798 rtd->ops.prepare = dpcm_fe_dai_prepare;
2799 rtd->ops.trigger = dpcm_fe_dai_trigger;
2800 rtd->ops.hw_free = dpcm_fe_dai_hw_free;
2801 rtd->ops.close = dpcm_fe_dai_close;
2802 rtd->ops.pointer = soc_pcm_pointer;
2803 } else {
2804 rtd->ops.open = soc_pcm_open;
2805 rtd->ops.hw_params = soc_pcm_hw_params;
2806 rtd->ops.prepare = soc_pcm_prepare;
2807 rtd->ops.trigger = soc_pcm_trigger;
2808 rtd->ops.hw_free = soc_pcm_hw_free;
2809 rtd->ops.close = soc_pcm_close;
2810 rtd->ops.pointer = soc_pcm_pointer;
2811 }
2812
Kuninori Morimoto613fb502020-01-10 11:35:21 +09002813 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto2b544dd2019-10-15 12:59:31 +09002814 const struct snd_soc_component_driver *drv = component->driver;
Kuninori Morimotob8135862017-10-11 01:37:23 +00002815
Takashi Iwai3b1c9522019-11-21 20:07:08 +01002816 if (drv->ioctl)
2817 rtd->ops.ioctl = snd_soc_pcm_component_ioctl;
Takashi Iwai1e5ddb62019-11-21 20:07:09 +01002818 if (drv->sync_stop)
2819 rtd->ops.sync_stop = snd_soc_pcm_component_sync_stop;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002820 if (drv->copy_user)
Kuninori Morimoto82d81f52019-07-26 13:51:56 +09002821 rtd->ops.copy_user = snd_soc_pcm_component_copy_user;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002822 if (drv->page)
Kuninori Morimoto9c712e42019-07-26 13:52:00 +09002823 rtd->ops.page = snd_soc_pcm_component_page;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002824 if (drv->mmap)
Kuninori Morimoto205875e2019-07-26 13:52:04 +09002825 rtd->ops.mmap = snd_soc_pcm_component_mmap;
Kuninori Morimotob8135862017-10-11 01:37:23 +00002826 }
2827
Liam Girdwoodddee6272011-06-09 14:45:53 +01002828 if (playback)
Liam Girdwood01d75842012-04-25 12:12:49 +01002829 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002830
2831 if (capture)
Liam Girdwood01d75842012-04-25 12:12:49 +01002832 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002833
Kuninori Morimotob2b2afb2019-11-18 10:50:32 +09002834 ret = snd_soc_pcm_component_new(rtd);
Kuninori Morimoto74842912019-07-26 13:52:08 +09002835 if (ret < 0) {
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002836 dev_err(rtd->dev, "ASoC: pcm constructor failed for dailink %s: %d\n",
2837 rtd->dai_link->name, ret);
Kuninori Morimoto74842912019-07-26 13:52:08 +09002838 return ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002839 }
Johan Hovoldc641e5b2017-07-12 17:55:29 +02002840
Takashi Iwai3d21ef02019-01-11 15:58:39 +01002841 pcm->no_device_suspend = true;
Liam Girdwood01d75842012-04-25 12:12:49 +01002842out:
Pierre-Louis Bossart1d5cd522020-06-12 15:40:50 -05002843 dev_dbg(rtd->card->dev, "%s <-> %s mapping ok\n",
2844 (rtd->num_codecs > 1) ? "multicodec" : asoc_rtd_to_codec(rtd, 0)->name,
2845 (rtd->num_cpus > 1) ? "multicpu" : asoc_rtd_to_cpu(rtd, 0)->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002846 return ret;
2847}
Liam Girdwood01d75842012-04-25 12:12:49 +01002848
2849/* is the current PCM operation for this FE ? */
2850int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream)
2851{
2852 if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE)
2853 return 1;
2854 return 0;
2855}
2856EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update);
2857
2858/* is the current PCM operation for this BE ? */
2859int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
2860 struct snd_soc_pcm_runtime *be, int stream)
2861{
2862 if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) ||
2863 ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) &&
2864 be->dpcm[stream].runtime_update))
2865 return 1;
2866 return 0;
2867}
2868EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update);
2869
2870/* get the substream for this BE */
2871struct snd_pcm_substream *
2872 snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream)
2873{
2874 return be->pcm->streams[stream].substream;
2875}
2876EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream);
2877
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002878static int snd_soc_dpcm_check_state(struct snd_soc_pcm_runtime *fe,
2879 struct snd_soc_pcm_runtime *be,
2880 int stream,
2881 const enum snd_soc_dpcm_state *states,
2882 int num_states)
Liam Girdwood01d75842012-04-25 12:12:49 +01002883{
2884 struct snd_soc_dpcm *dpcm;
2885 int state;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002886 int ret = 1;
2887 unsigned long flags;
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002888 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01002889
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002890 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00002891 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002892
2893 if (dpcm->fe == fe)
2894 continue;
2895
2896 state = dpcm->fe->dpcm[stream].state;
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002897 for (i = 0; i < num_states; i++) {
2898 if (state == states[i]) {
2899 ret = 0;
2900 break;
2901 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002902 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002903 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002904 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01002905
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002906 /* it's safe to do this BE DAI */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002907 return ret;
Liam Girdwood01d75842012-04-25 12:12:49 +01002908}
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002909
2910/*
2911 * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE
2912 * are not running, paused or suspended for the specified stream direction.
2913 */
2914int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
2915 struct snd_soc_pcm_runtime *be, int stream)
2916{
2917 const enum snd_soc_dpcm_state state[] = {
2918 SND_SOC_DPCM_STATE_START,
2919 SND_SOC_DPCM_STATE_PAUSED,
2920 SND_SOC_DPCM_STATE_SUSPEND,
2921 };
2922
2923 return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
2924}
Liam Girdwood01d75842012-04-25 12:12:49 +01002925EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop);
2926
2927/*
2928 * We can only change hw params a BE DAI if any of it's FE are not prepared,
2929 * running, paused or suspended for the specified stream direction.
2930 */
2931int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
2932 struct snd_soc_pcm_runtime *be, int stream)
2933{
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002934 const enum snd_soc_dpcm_state state[] = {
2935 SND_SOC_DPCM_STATE_START,
2936 SND_SOC_DPCM_STATE_PAUSED,
2937 SND_SOC_DPCM_STATE_SUSPEND,
2938 SND_SOC_DPCM_STATE_PREPARE,
2939 };
Liam Girdwood01d75842012-04-25 12:12:49 +01002940
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002941 return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
Liam Girdwood01d75842012-04-25 12:12:49 +01002942}
2943EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);