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