blob: 10afa8efde2a64ee98ed4960acbc964445f699a5 [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);
Bicycle Tsaic82dbcb2021-09-06 11:50:47 +08001277 struct snd_soc_card_ext *card_ext;
Liam Girdwood01d75842012-04-25 12:12:49 +01001278 int paths;
1279
Bard Liao6e1276a2020-02-25 21:39:16 +08001280 if (fe->num_cpus > 1) {
1281 dev_err(fe->dev,
1282 "%s doesn't support Multi CPU yet\n", __func__);
1283 return -EINVAL;
1284 }
1285
Bicycle Tsaic82dbcb2021-09-06 11:50:47 +08001286 card_ext = container_of(fe->card, struct snd_soc_card_ext, card);
1287
Liam Girdwood01d75842012-04-25 12:12:49 +01001288 /* get number of valid DAI paths and their widgets */
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001289 paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list,
Bicycle Tsaic82dbcb2021-09-06 11:50:47 +08001290 card_ext->component_chaining ?
1291 NULL : dpcm_end_walk_at_be);
Liam Girdwood01d75842012-04-25 12:12:49 +01001292
Liam Girdwood103d84a2012-11-19 14:39:15 +00001293 dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths,
Liam Girdwood01d75842012-04-25 12:12:49 +01001294 stream ? "capture" : "playback");
1295
Liam Girdwood01d75842012-04-25 12:12:49 +01001296 return paths;
1297}
1298
Kuninori Morimoto52645e332020-02-19 15:56:52 +09001299void dpcm_path_put(struct snd_soc_dapm_widget_list **list)
1300{
1301 snd_soc_dapm_dai_free_widgets(list);
1302}
1303
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001304static bool dpcm_be_is_active(struct snd_soc_dpcm *dpcm, int stream,
1305 struct snd_soc_dapm_widget_list *list)
Liam Girdwood01d75842012-04-25 12:12:49 +01001306{
Liam Girdwood01d75842012-04-25 12:12:49 +01001307 struct snd_soc_dapm_widget *widget;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001308 struct snd_soc_dai *dai;
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001309 unsigned int i;
1310
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001311 /* is there a valid DAI widget for this BE */
1312 for_each_rtd_dais(dpcm->be, i, dai) {
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001313 widget = snd_soc_dai_get_widget(dai, stream);
1314
1315 /*
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001316 * The BE is pruned only if none of the dai
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001317 * widgets are in the active list.
1318 */
1319 if (widget && widget_in_list(list, widget))
1320 return true;
1321 }
1322
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001323 return false;
1324}
1325
1326static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
1327 struct snd_soc_dapm_widget_list **list_)
1328{
1329 struct snd_soc_dpcm *dpcm;
Liam Girdwood01d75842012-04-25 12:12:49 +01001330 int prune = 0;
1331
1332 /* Destroy any old FE <--> BE connections */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001333 for_each_dpcm_be(fe, stream, dpcm) {
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001334 if (dpcm_be_is_active(dpcm, stream, *list_))
Kuninori Morimotobed646d2019-10-15 12:59:38 +09001335 continue;
Liam Girdwood01d75842012-04-25 12:12:49 +01001336
Liam Girdwood103d84a2012-11-19 14:39:15 +00001337 dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001338 stream ? "capture" : "playback",
1339 dpcm->be->dai_link->name, fe->dai_link->name);
1340 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
1341 dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1342 prune++;
1343 }
1344
Liam Girdwood103d84a2012-11-19 14:39:15 +00001345 dev_dbg(fe->dev, "ASoC: found %d old BE paths for pruning\n", prune);
Liam Girdwood01d75842012-04-25 12:12:49 +01001346 return prune;
1347}
1348
1349static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
1350 struct snd_soc_dapm_widget_list **list_)
1351{
1352 struct snd_soc_card *card = fe->card;
1353 struct snd_soc_dapm_widget_list *list = *list_;
1354 struct snd_soc_pcm_runtime *be;
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001355 struct snd_soc_dapm_widget *widget;
Liam Girdwood01d75842012-04-25 12:12:49 +01001356 int i, new = 0, err;
1357
1358 /* Create any new FE <--> BE connections */
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001359 for_each_dapm_widgets(list, i, widget) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001360
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001361 switch (widget->id) {
Mark Brown46162742013-06-05 19:36:11 +01001362 case snd_soc_dapm_dai_in:
Koro Chenc5b85402015-07-06 10:02:10 +08001363 if (stream != SNDRV_PCM_STREAM_PLAYBACK)
1364 continue;
1365 break;
Mark Brown46162742013-06-05 19:36:11 +01001366 case snd_soc_dapm_dai_out:
Koro Chenc5b85402015-07-06 10:02:10 +08001367 if (stream != SNDRV_PCM_STREAM_CAPTURE)
1368 continue;
Mark Brown46162742013-06-05 19:36:11 +01001369 break;
1370 default:
Liam Girdwood01d75842012-04-25 12:12:49 +01001371 continue;
Mark Brown46162742013-06-05 19:36:11 +01001372 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001373
1374 /* is there a valid BE rtd for this widget */
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001375 be = dpcm_get_be(card, widget, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001376 if (!be) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001377 dev_err(fe->dev, "ASoC: no BE found for %s\n",
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001378 widget->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001379 continue;
1380 }
1381
Liam Girdwood01d75842012-04-25 12:12:49 +01001382 /* don't connect if FE is not running */
Liam Girdwood23607022014-01-17 17:03:55 +00001383 if (!fe->dpcm[stream].runtime && !fe->fe_compr)
Liam Girdwood01d75842012-04-25 12:12:49 +01001384 continue;
1385
1386 /* newly connected FE and BE */
1387 err = dpcm_be_connect(fe, be, stream);
1388 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001389 dev_err(fe->dev, "ASoC: can't connect %s\n",
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001390 widget->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001391 break;
1392 } else if (err == 0) /* already connected */
1393 continue;
1394
1395 /* new */
1396 be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1397 new++;
1398 }
1399
Liam Girdwood103d84a2012-11-19 14:39:15 +00001400 dev_dbg(fe->dev, "ASoC: found %d new BE paths\n", new);
Liam Girdwood01d75842012-04-25 12:12:49 +01001401 return new;
1402}
1403
1404/*
1405 * Find the corresponding BE DAIs that source or sink audio to this
1406 * FE substream.
1407 */
Liam Girdwood23607022014-01-17 17:03:55 +00001408int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
Liam Girdwood01d75842012-04-25 12:12:49 +01001409 int stream, struct snd_soc_dapm_widget_list **list, int new)
1410{
1411 if (new)
1412 return dpcm_add_paths(fe, stream, list);
1413 else
1414 return dpcm_prune_paths(fe, stream, list);
1415}
1416
Liam Girdwood23607022014-01-17 17:03:55 +00001417void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001418{
1419 struct snd_soc_dpcm *dpcm;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001420 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001421
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001422 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001423 for_each_dpcm_be(fe, stream, dpcm)
Liam Girdwood01d75842012-04-25 12:12:49 +01001424 dpcm->be->dpcm[stream].runtime_update =
1425 SND_SOC_DPCM_UPDATE_NO;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001426 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001427}
1428
1429static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe,
1430 int stream)
1431{
1432 struct snd_soc_dpcm *dpcm;
1433
1434 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001435 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001436
1437 struct snd_soc_pcm_runtime *be = dpcm->be;
1438 struct snd_pcm_substream *be_substream =
1439 snd_soc_dpcm_get_substream(be, stream);
1440
1441 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001442 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001443 stream ? "capture" : "playback",
1444 be->dpcm[stream].state);
1445
1446 if (--be->dpcm[stream].users != 0)
1447 continue;
1448
1449 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1450 continue;
1451
1452 soc_pcm_close(be_substream);
1453 be_substream->runtime = NULL;
1454 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1455 }
1456}
1457
Liam Girdwood23607022014-01-17 17:03:55 +00001458int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001459{
1460 struct snd_soc_dpcm *dpcm;
1461 int err, count = 0;
1462
1463 /* only startup BE DAIs that are either sinks or sources to this FE DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001464 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001465
1466 struct snd_soc_pcm_runtime *be = dpcm->be;
1467 struct snd_pcm_substream *be_substream =
1468 snd_soc_dpcm_get_substream(be, stream);
1469
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001470 if (!be_substream) {
1471 dev_err(be->dev, "ASoC: no backend %s stream\n",
1472 stream ? "capture" : "playback");
1473 continue;
1474 }
1475
Liam Girdwood01d75842012-04-25 12:12:49 +01001476 /* is this op for this BE ? */
1477 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1478 continue;
1479
1480 /* first time the dpcm is open ? */
1481 if (be->dpcm[stream].users == DPCM_MAX_BE_USERS)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001482 dev_err(be->dev, "ASoC: too many users %s at open %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001483 stream ? "capture" : "playback",
1484 be->dpcm[stream].state);
1485
1486 if (be->dpcm[stream].users++ != 0)
1487 continue;
1488
1489 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
1490 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
1491 continue;
1492
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001493 dev_dbg(be->dev, "ASoC: open %s BE %s\n",
1494 stream ? "capture" : "playback", be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001495
1496 be_substream->runtime = be->dpcm[stream].runtime;
1497 err = soc_pcm_open(be_substream);
1498 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001499 dev_err(be->dev, "ASoC: BE open failed %d\n", err);
Liam Girdwood01d75842012-04-25 12:12:49 +01001500 be->dpcm[stream].users--;
1501 if (be->dpcm[stream].users < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001502 dev_err(be->dev, "ASoC: no users %s at unwind %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001503 stream ? "capture" : "playback",
1504 be->dpcm[stream].state);
1505
1506 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1507 goto unwind;
1508 }
1509
1510 be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1511 count++;
1512 }
1513
1514 return count;
1515
1516unwind:
1517 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001518 for_each_dpcm_be_rollback(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001519 struct snd_soc_pcm_runtime *be = dpcm->be;
1520 struct snd_pcm_substream *be_substream =
1521 snd_soc_dpcm_get_substream(be, stream);
1522
1523 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1524 continue;
1525
1526 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001527 dev_err(be->dev, "ASoC: no users %s at close %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001528 stream ? "capture" : "playback",
1529 be->dpcm[stream].state);
1530
1531 if (--be->dpcm[stream].users != 0)
1532 continue;
1533
1534 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1535 continue;
1536
1537 soc_pcm_close(be_substream);
1538 be_substream->runtime = NULL;
1539 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1540 }
1541
1542 return err;
1543}
1544
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001545static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
Jerome Brunet435ffb72018-07-05 12:13:48 +02001546 struct snd_soc_pcm_stream *stream)
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001547{
1548 runtime->hw.rate_min = stream->rate_min;
Charles Keepaxe33ffbd9c2018-08-27 14:26:47 +01001549 runtime->hw.rate_max = min_not_zero(stream->rate_max, UINT_MAX);
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001550 runtime->hw.channels_min = stream->channels_min;
1551 runtime->hw.channels_max = stream->channels_max;
Lars-Peter Clausen002220a2014-01-06 14:19:07 +01001552 if (runtime->hw.formats)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001553 runtime->hw.formats &= stream->formats;
Lars-Peter Clausen002220a2014-01-06 14:19:07 +01001554 else
Jerome Brunet435ffb72018-07-05 12:13:48 +02001555 runtime->hw.formats = stream->formats;
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001556 runtime->hw.rates = stream->rates;
1557}
1558
Jerome Brunet435ffb72018-07-05 12:13:48 +02001559static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream,
1560 u64 *formats)
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001561{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001562 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001563 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001564 struct snd_soc_dai *dai;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001565 int stream = substream->stream;
1566
1567 if (!fe->dai_link->dpcm_merged_format)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001568 return;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001569
1570 /*
1571 * It returns merged BE codec format
1572 * if FE want to use it (= dpcm_merged_format)
1573 */
1574
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001575 for_each_dpcm_be(fe, stream, dpcm) {
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001576 struct snd_soc_pcm_runtime *be = dpcm->be;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001577 struct snd_soc_pcm_stream *codec_stream;
1578 int i;
1579
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001580 for_each_rtd_codec_dais(be, i, dai) {
Jerome Brunet4febced2018-06-27 17:36:38 +02001581 /*
1582 * Skip CODECs which don't support the current stream
1583 * type. See soc_pcm_init_runtime_hw() for more details
1584 */
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001585 if (!snd_soc_dai_stream_valid(dai, stream))
Jerome Brunet4febced2018-06-27 17:36:38 +02001586 continue;
1587
Kuninori Morimotoacf253c2020-02-19 15:56:30 +09001588 codec_stream = snd_soc_dai_get_pcm_stream(dai, stream);
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001589
Jerome Brunet435ffb72018-07-05 12:13:48 +02001590 *formats &= codec_stream->formats;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001591 }
1592 }
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001593}
1594
Jerome Brunet435ffb72018-07-05 12:13:48 +02001595static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream,
1596 unsigned int *channels_min,
1597 unsigned int *channels_max)
Jiada Wangf4c277b2018-06-20 18:25:20 +09001598{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001599 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Jiada Wangf4c277b2018-06-20 18:25:20 +09001600 struct snd_soc_dpcm *dpcm;
1601 int stream = substream->stream;
1602
1603 if (!fe->dai_link->dpcm_merged_chan)
1604 return;
1605
Jiada Wangf4c277b2018-06-20 18:25:20 +09001606 /*
1607 * It returns merged BE codec channel;
1608 * if FE want to use it (= dpcm_merged_chan)
1609 */
1610
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001611 for_each_dpcm_be(fe, stream, dpcm) {
Jiada Wangf4c277b2018-06-20 18:25:20 +09001612 struct snd_soc_pcm_runtime *be = dpcm->be;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001613 struct snd_soc_pcm_stream *codec_stream;
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001614 struct snd_soc_pcm_stream *cpu_stream;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001615 struct snd_soc_dai *dai;
1616 int i;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001617
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001618 for_each_rtd_cpu_dais(be, i, dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001619 /*
1620 * Skip CPUs which don't support the current stream
1621 * type. See soc_pcm_init_runtime_hw() for more details
1622 */
1623 if (!snd_soc_dai_stream_valid(dai, stream))
1624 continue;
1625
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001626 cpu_stream = snd_soc_dai_get_pcm_stream(dai, stream);
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001627
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001628 *channels_min = max(*channels_min,
1629 cpu_stream->channels_min);
1630 *channels_max = min(*channels_max,
1631 cpu_stream->channels_max);
1632 }
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001633
1634 /*
1635 * chan min/max cannot be enforced if there are multiple CODEC
1636 * DAIs connected to a single CPU DAI, use CPU DAI's directly
1637 */
1638 if (be->num_codecs == 1) {
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09001639 codec_stream = snd_soc_dai_get_pcm_stream(asoc_rtd_to_codec(be, 0), stream);
Jiada Wangf4c277b2018-06-20 18:25:20 +09001640
1641 *channels_min = max(*channels_min,
1642 codec_stream->channels_min);
1643 *channels_max = min(*channels_max,
1644 codec_stream->channels_max);
1645 }
1646 }
1647}
1648
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001649static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream,
1650 unsigned int *rates,
1651 unsigned int *rate_min,
1652 unsigned int *rate_max)
1653{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001654 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001655 struct snd_soc_dpcm *dpcm;
1656 int stream = substream->stream;
1657
1658 if (!fe->dai_link->dpcm_merged_rate)
1659 return;
1660
1661 /*
1662 * It returns merged BE codec channel;
1663 * if FE want to use it (= dpcm_merged_chan)
1664 */
1665
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001666 for_each_dpcm_be(fe, stream, dpcm) {
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001667 struct snd_soc_pcm_runtime *be = dpcm->be;
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001668 struct snd_soc_pcm_stream *pcm;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001669 struct snd_soc_dai *dai;
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001670 int i;
1671
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001672 for_each_rtd_dais(be, i, dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001673 /*
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001674 * Skip DAIs which don't support the current stream
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001675 * type. See soc_pcm_init_runtime_hw() for more details
1676 */
1677 if (!snd_soc_dai_stream_valid(dai, stream))
1678 continue;
1679
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001680 pcm = snd_soc_dai_get_pcm_stream(dai, stream);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001681
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001682 *rate_min = max(*rate_min, pcm->rate_min);
1683 *rate_max = min_not_zero(*rate_max, pcm->rate_max);
1684 *rates = snd_pcm_rate_mask_intersect(*rates, pcm->rates);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001685 }
1686 }
1687}
1688
Mark Brown45c0a182012-05-09 21:46:27 +01001689static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001690{
1691 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001692 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001693 struct snd_soc_dai *cpu_dai;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001694 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01001695
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001696 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001697 /*
1698 * Skip CPUs which don't support the current stream
1699 * type. See soc_pcm_init_runtime_hw() for more details
1700 */
1701 if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream))
1702 continue;
1703
Kuninori Morimoto0c9ba722020-03-06 10:09:54 +09001704 dpcm_init_runtime_hw(runtime,
1705 snd_soc_dai_get_pcm_stream(cpu_dai,
1706 substream->stream));
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001707 }
Jiada Wangf4c277b2018-06-20 18:25:20 +09001708
Jerome Brunet435ffb72018-07-05 12:13:48 +02001709 dpcm_runtime_merge_format(substream, &runtime->hw.formats);
1710 dpcm_runtime_merge_chan(substream, &runtime->hw.channels_min,
1711 &runtime->hw.channels_max);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001712 dpcm_runtime_merge_rate(substream, &runtime->hw.rates,
1713 &runtime->hw.rate_min, &runtime->hw.rate_max);
Liam Girdwood01d75842012-04-25 12:12:49 +01001714}
1715
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001716static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
1717
1718/* Set FE's runtime_update state; the state is protected via PCM stream lock
1719 * for avoiding the race with trigger callback.
1720 * If the state is unset and a trigger is pending while the previous operation,
1721 * process the pending trigger action here.
1722 */
1723static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
1724 int stream, enum snd_soc_dpcm_update state)
1725{
1726 struct snd_pcm_substream *substream =
1727 snd_soc_dpcm_get_substream(fe, stream);
1728
1729 snd_pcm_stream_lock_irq(substream);
1730 if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) {
1731 dpcm_fe_dai_do_trigger(substream,
1732 fe->dpcm[stream].trigger_pending - 1);
1733 fe->dpcm[stream].trigger_pending = 0;
1734 }
1735 fe->dpcm[stream].runtime_update = state;
1736 snd_pcm_stream_unlock_irq(substream);
1737}
1738
PC Liao906c7d62015-12-11 11:33:51 +08001739static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
1740 int stream)
1741{
1742 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001743 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001744 struct snd_soc_dai *fe_cpu_dai;
PC Liao906c7d62015-12-11 11:33:51 +08001745 int err;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001746 int i;
PC Liao906c7d62015-12-11 11:33:51 +08001747
1748 /* apply symmetry for FE */
1749 if (soc_pcm_has_symmetry(fe_substream))
1750 fe_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1751
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001752 for_each_rtd_cpu_dais (fe, i, fe_cpu_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001753 /* Symmetry only applies if we've got an active stream. */
Kuninori Morimotob3dea622020-05-15 09:46:51 +09001754 if (snd_soc_dai_active(fe_cpu_dai)) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001755 err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai);
1756 if (err < 0)
1757 return err;
1758 }
PC Liao906c7d62015-12-11 11:33:51 +08001759 }
1760
1761 /* apply symmetry for BE */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001762 for_each_dpcm_be(fe, stream, dpcm) {
PC Liao906c7d62015-12-11 11:33:51 +08001763 struct snd_soc_pcm_runtime *be = dpcm->be;
1764 struct snd_pcm_substream *be_substream =
1765 snd_soc_dpcm_get_substream(be, stream);
Jerome Brunet6246f282019-04-01 15:03:54 +02001766 struct snd_soc_pcm_runtime *rtd;
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001767 struct snd_soc_dai *dai;
PC Liao906c7d62015-12-11 11:33:51 +08001768 int i;
1769
Jerome Brunet6246f282019-04-01 15:03:54 +02001770 /* A backend may not have the requested substream */
1771 if (!be_substream)
1772 continue;
1773
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001774 rtd = asoc_substream_to_rtd(be_substream);
Jeeja KPf1176612016-09-06 14:17:55 +05301775 if (rtd->dai_link->be_hw_params_fixup)
1776 continue;
1777
PC Liao906c7d62015-12-11 11:33:51 +08001778 if (soc_pcm_has_symmetry(be_substream))
1779 be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1780
1781 /* Symmetry only applies if we've got an active stream. */
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001782 for_each_rtd_dais(rtd, i, dai) {
Kuninori Morimotob3dea622020-05-15 09:46:51 +09001783 if (snd_soc_dai_active(dai)) {
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001784 err = soc_pcm_apply_symmetry(fe_substream, dai);
PC Liao906c7d62015-12-11 11:33:51 +08001785 if (err < 0)
1786 return err;
1787 }
1788 }
1789 }
1790
1791 return 0;
1792}
1793
Liam Girdwood01d75842012-04-25 12:12:49 +01001794static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
1795{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001796 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001797 struct snd_pcm_runtime *runtime = fe_substream->runtime;
1798 int stream = fe_substream->stream, ret = 0;
1799
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001800 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001801
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09001802 ret = dpcm_be_dai_startup(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001803 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001804 dev_err(fe->dev,"ASoC: failed to start some BEs %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001805 goto be_err;
1806 }
1807
Liam Girdwood103d84a2012-11-19 14:39:15 +00001808 dev_dbg(fe->dev, "ASoC: open FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001809
1810 /* start the DAI frontend */
1811 ret = soc_pcm_open(fe_substream);
1812 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001813 dev_err(fe->dev,"ASoC: failed to start FE %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001814 goto unwind;
1815 }
1816
1817 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1818
1819 dpcm_set_fe_runtime(fe_substream);
1820 snd_pcm_limit_hw_rates(runtime);
1821
PC Liao906c7d62015-12-11 11:33:51 +08001822 ret = dpcm_apply_symmetry(fe_substream, stream);
Kuninori Morimoto8a01fbf2020-03-06 10:09:59 +09001823 if (ret < 0)
PC Liao906c7d62015-12-11 11:33:51 +08001824 dev_err(fe->dev, "ASoC: failed to apply dpcm symmetry %d\n",
1825 ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001826
1827unwind:
Kuninori Morimoto8a01fbf2020-03-06 10:09:59 +09001828 if (ret < 0)
1829 dpcm_be_dai_startup_unwind(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001830be_err:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001831 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001832 return ret;
1833}
1834
Liam Girdwood23607022014-01-17 17:03:55 +00001835int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001836{
1837 struct snd_soc_dpcm *dpcm;
1838
1839 /* only shutdown BEs that are either sinks or sources to this FE DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001840 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001841
1842 struct snd_soc_pcm_runtime *be = dpcm->be;
1843 struct snd_pcm_substream *be_substream =
1844 snd_soc_dpcm_get_substream(be, stream);
1845
1846 /* is this op for this BE ? */
1847 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1848 continue;
1849
1850 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001851 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001852 stream ? "capture" : "playback",
1853 be->dpcm[stream].state);
1854
1855 if (--be->dpcm[stream].users != 0)
1856 continue;
1857
1858 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Kai Chieh Chuang9c0ac702018-05-28 10:18:18 +08001859 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) {
1860 soc_pcm_hw_free(be_substream);
1861 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1862 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001863
Liam Girdwood103d84a2012-11-19 14:39:15 +00001864 dev_dbg(be->dev, "ASoC: close BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001865 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001866
1867 soc_pcm_close(be_substream);
1868 be_substream->runtime = NULL;
1869
1870 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1871 }
1872 return 0;
1873}
1874
1875static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
1876{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001877 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001878 int stream = substream->stream;
1879
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001880 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001881
1882 /* shutdown the BEs */
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09001883 dpcm_be_dai_shutdown(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001884
Liam Girdwood103d84a2012-11-19 14:39:15 +00001885 dev_dbg(fe->dev, "ASoC: close FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001886
1887 /* now shutdown the frontend */
1888 soc_pcm_close(substream);
1889
1890 /* run the stream event for each BE */
Kuninori Morimoto1c531232020-02-21 10:25:18 +09001891 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
Liam Girdwood01d75842012-04-25 12:12:49 +01001892
1893 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001894 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001895 return 0;
1896}
1897
Liam Girdwood23607022014-01-17 17:03:55 +00001898int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001899{
1900 struct snd_soc_dpcm *dpcm;
1901
1902 /* only hw_params backends that are either sinks or sources
1903 * to this frontend DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001904 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001905
1906 struct snd_soc_pcm_runtime *be = dpcm->be;
1907 struct snd_pcm_substream *be_substream =
1908 snd_soc_dpcm_get_substream(be, stream);
1909
1910 /* is this op for this BE ? */
1911 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1912 continue;
1913
1914 /* only free hw when no longer used - check all FEs */
1915 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1916 continue;
1917
Qiao Zhou36fba622014-12-03 10:13:43 +08001918 /* do not free hw if this BE is used by other FE */
1919 if (be->dpcm[stream].users > 1)
1920 continue;
1921
Liam Girdwood01d75842012-04-25 12:12:49 +01001922 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1923 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
1924 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Patrick Lai08b27842012-12-19 19:36:02 -08001925 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
Vinod Koul5e82d2b2016-02-01 22:26:40 +05301926 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
1927 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
Liam Girdwood01d75842012-04-25 12:12:49 +01001928 continue;
1929
Liam Girdwood103d84a2012-11-19 14:39:15 +00001930 dev_dbg(be->dev, "ASoC: hw_free BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001931 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001932
1933 soc_pcm_hw_free(be_substream);
1934
1935 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1936 }
1937
1938 return 0;
1939}
1940
Mark Brown45c0a182012-05-09 21:46:27 +01001941static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001942{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001943 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001944 int err, stream = substream->stream;
1945
1946 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001947 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001948
Liam Girdwood103d84a2012-11-19 14:39:15 +00001949 dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001950
1951 /* call hw_free on the frontend */
1952 err = soc_pcm_hw_free(substream);
1953 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001954 dev_err(fe->dev,"ASoC: hw_free FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001955 fe->dai_link->name);
1956
1957 /* only hw_params backends that are either sinks or sources
1958 * to this frontend DAI */
1959 err = dpcm_be_dai_hw_free(fe, stream);
1960
1961 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001962 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001963
1964 mutex_unlock(&fe->card->mutex);
1965 return 0;
1966}
1967
Liam Girdwood23607022014-01-17 17:03:55 +00001968int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001969{
1970 struct snd_soc_dpcm *dpcm;
1971 int ret;
1972
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001973 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001974
1975 struct snd_soc_pcm_runtime *be = dpcm->be;
1976 struct snd_pcm_substream *be_substream =
1977 snd_soc_dpcm_get_substream(be, stream);
1978
1979 /* is this op for this BE ? */
1980 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1981 continue;
1982
Liam Girdwood01d75842012-04-25 12:12:49 +01001983 /* copy params for each dpcm */
1984 memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params,
1985 sizeof(struct snd_pcm_hw_params));
1986
1987 /* perform any hw_params fixups */
Kuninori Morimoto0cbbf8a2020-05-25 09:57:36 +09001988 ret = snd_soc_link_be_hw_params_fixup(be, &dpcm->hw_params);
1989 if (ret < 0)
1990 goto unwind;
Liam Girdwood01d75842012-04-25 12:12:49 +01001991
Libin Yangae061d22019-04-19 09:53:12 +08001992 /* copy the fixed-up hw params for BE dai */
1993 memcpy(&be->dpcm[stream].hw_params, &dpcm->hw_params,
1994 sizeof(struct snd_pcm_hw_params));
1995
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00001996 /* only allow hw_params() if no connected FEs are running */
1997 if (!snd_soc_dpcm_can_be_params(fe, be, stream))
1998 continue;
1999
2000 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
2001 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2002 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE))
2003 continue;
2004
2005 dev_dbg(be->dev, "ASoC: hw_params BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002006 be->dai_link->name);
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00002007
Liam Girdwood01d75842012-04-25 12:12:49 +01002008 ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params);
2009 if (ret < 0) {
2010 dev_err(dpcm->be->dev,
Liam Girdwood103d84a2012-11-19 14:39:15 +00002011 "ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002012 goto unwind;
2013 }
2014
2015 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2016 }
2017 return 0;
2018
2019unwind:
2020 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002021 for_each_dpcm_be_rollback(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002022 struct snd_soc_pcm_runtime *be = dpcm->be;
2023 struct snd_pcm_substream *be_substream =
2024 snd_soc_dpcm_get_substream(be, stream);
2025
2026 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2027 continue;
2028
2029 /* only allow hw_free() if no connected FEs are running */
2030 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2031 continue;
2032
2033 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
2034 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2035 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
2036 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
2037 continue;
2038
2039 soc_pcm_hw_free(be_substream);
2040 }
2041
2042 return ret;
2043}
2044
Mark Brown45c0a182012-05-09 21:46:27 +01002045static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
2046 struct snd_pcm_hw_params *params)
Liam Girdwood01d75842012-04-25 12:12:49 +01002047{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002048 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002049 int ret, stream = substream->stream;
2050
2051 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002052 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002053
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09002054 memcpy(&fe->dpcm[stream].hw_params, params,
Liam Girdwood01d75842012-04-25 12:12:49 +01002055 sizeof(struct snd_pcm_hw_params));
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09002056 ret = dpcm_be_dai_hw_params(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002057 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002058 dev_err(fe->dev,"ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002059 goto out;
2060 }
2061
Liam Girdwood103d84a2012-11-19 14:39:15 +00002062 dev_dbg(fe->dev, "ASoC: hw_params FE %s rate %d chan %x fmt %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002063 fe->dai_link->name, params_rate(params),
2064 params_channels(params), params_format(params));
2065
2066 /* call hw_params on the frontend */
2067 ret = soc_pcm_hw_params(substream, params);
2068 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002069 dev_err(fe->dev,"ASoC: hw_params FE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002070 dpcm_be_dai_hw_free(fe, stream);
2071 } else
2072 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2073
2074out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002075 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002076 mutex_unlock(&fe->card->mutex);
2077 return ret;
2078}
2079
2080static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm,
2081 struct snd_pcm_substream *substream, int cmd)
2082{
2083 int ret;
2084
Liam Girdwood103d84a2012-11-19 14:39:15 +00002085 dev_dbg(dpcm->be->dev, "ASoC: trigger BE %s cmd %d\n",
彭东林94d215c2016-09-26 08:29:31 +00002086 dpcm->be->dai_link->name, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002087
2088 ret = soc_pcm_trigger(substream, cmd);
2089 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002090 dev_err(dpcm->be->dev,"ASoC: trigger BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002091
2092 return ret;
2093}
2094
Liam Girdwood23607022014-01-17 17:03:55 +00002095int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
Mark Brown45c0a182012-05-09 21:46:27 +01002096 int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002097{
2098 struct snd_soc_dpcm *dpcm;
2099 int ret = 0;
2100
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002101 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002102
2103 struct snd_soc_pcm_runtime *be = dpcm->be;
2104 struct snd_pcm_substream *be_substream =
2105 snd_soc_dpcm_get_substream(be, stream);
2106
2107 /* is this op for this BE ? */
2108 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2109 continue;
2110
2111 switch (cmd) {
2112 case SNDRV_PCM_TRIGGER_START:
2113 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
이경택21fca8b2020-04-01 10:04:21 +09002114 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
2115 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Liam Girdwood01d75842012-04-25 12:12:49 +01002116 continue;
2117
2118 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2119 if (ret)
2120 return ret;
2121
2122 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2123 break;
2124 case SNDRV_PCM_TRIGGER_RESUME:
2125 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
2126 continue;
2127
2128 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2129 if (ret)
2130 return ret;
2131
2132 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2133 break;
2134 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2135 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
2136 continue;
2137
2138 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2139 if (ret)
2140 return ret;
2141
2142 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2143 break;
2144 case SNDRV_PCM_TRIGGER_STOP:
이경택21fca8b2020-04-01 10:04:21 +09002145 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) &&
2146 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Liam Girdwood01d75842012-04-25 12:12:49 +01002147 continue;
2148
2149 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2150 continue;
2151
2152 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2153 if (ret)
2154 return ret;
2155
2156 be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2157 break;
2158 case SNDRV_PCM_TRIGGER_SUSPEND:
Nicolin Chen868a6ca2014-05-12 20:12:05 +08002159 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
Liam Girdwood01d75842012-04-25 12:12:49 +01002160 continue;
2161
2162 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2163 continue;
2164
2165 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2166 if (ret)
2167 return ret;
2168
2169 be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND;
2170 break;
2171 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2172 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2173 continue;
2174
2175 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2176 continue;
2177
2178 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2179 if (ret)
2180 return ret;
2181
2182 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2183 break;
2184 }
2185 }
2186
2187 return ret;
2188}
2189EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
2190
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002191static int dpcm_dai_trigger_fe_be(struct snd_pcm_substream *substream,
2192 int cmd, bool fe_first)
2193{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002194 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002195 int ret;
2196
2197 /* call trigger on the frontend before the backend. */
2198 if (fe_first) {
2199 dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n",
2200 fe->dai_link->name, cmd);
2201
2202 ret = soc_pcm_trigger(substream, cmd);
2203 if (ret < 0)
2204 return ret;
2205
2206 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2207 return ret;
2208 }
2209
2210 /* call trigger on the frontend after the backend. */
2211 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2212 if (ret < 0)
2213 return ret;
2214
2215 dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n",
2216 fe->dai_link->name, cmd);
2217
2218 ret = soc_pcm_trigger(substream, cmd);
2219
2220 return ret;
2221}
2222
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002223static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002224{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002225 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002226 int stream = substream->stream;
2227 int ret = 0;
Liam Girdwood01d75842012-04-25 12:12:49 +01002228 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
2229
2230 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
2231
2232 switch (trigger) {
2233 case SND_SOC_DPCM_TRIGGER_PRE:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002234 switch (cmd) {
2235 case SNDRV_PCM_TRIGGER_START:
2236 case SNDRV_PCM_TRIGGER_RESUME:
2237 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Cezary Rojewski332a2c32020-10-26 11:01:29 +01002238 case SNDRV_PCM_TRIGGER_DRAIN:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002239 ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
2240 break;
2241 case SNDRV_PCM_TRIGGER_STOP:
2242 case SNDRV_PCM_TRIGGER_SUSPEND:
2243 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2244 ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
2245 break;
2246 default:
2247 ret = -EINVAL;
2248 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002249 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002250 break;
2251 case SND_SOC_DPCM_TRIGGER_POST:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002252 switch (cmd) {
2253 case SNDRV_PCM_TRIGGER_START:
2254 case SNDRV_PCM_TRIGGER_RESUME:
2255 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Cezary Rojewski332a2c32020-10-26 11:01:29 +01002256 case SNDRV_PCM_TRIGGER_DRAIN:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002257 ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
2258 break;
2259 case SNDRV_PCM_TRIGGER_STOP:
2260 case SNDRV_PCM_TRIGGER_SUSPEND:
2261 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2262 ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
2263 break;
2264 default:
2265 ret = -EINVAL;
2266 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002267 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002268 break;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002269 case SND_SOC_DPCM_TRIGGER_BESPOKE:
2270 /* bespoke trigger() - handles both FE and BEs */
2271
Liam Girdwood103d84a2012-11-19 14:39:15 +00002272 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd %d\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002273 fe->dai_link->name, cmd);
2274
Kuninori Morimoto308193582020-04-24 08:15:09 +09002275 ret = snd_soc_pcm_dai_bespoke_trigger(substream, cmd);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002276 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002277 default:
Liam Girdwood103d84a2012-11-19 14:39:15 +00002278 dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd,
Liam Girdwood01d75842012-04-25 12:12:49 +01002279 fe->dai_link->name);
2280 ret = -EINVAL;
2281 goto out;
2282 }
2283
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002284 if (ret < 0) {
2285 dev_err(fe->dev, "ASoC: trigger FE cmd: %d failed: %d\n",
2286 cmd, ret);
2287 goto out;
2288 }
2289
Liam Girdwood01d75842012-04-25 12:12:49 +01002290 switch (cmd) {
2291 case SNDRV_PCM_TRIGGER_START:
2292 case SNDRV_PCM_TRIGGER_RESUME:
2293 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2294 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2295 break;
2296 case SNDRV_PCM_TRIGGER_STOP:
2297 case SNDRV_PCM_TRIGGER_SUSPEND:
Liam Girdwood01d75842012-04-25 12:12:49 +01002298 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2299 break;
Patrick Lai9f169b92016-12-31 22:44:39 -08002300 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2301 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2302 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002303 }
2304
2305out:
2306 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
2307 return ret;
2308}
2309
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002310static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
2311{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002312 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002313 int stream = substream->stream;
2314
2315 /* if FE's runtime_update is already set, we're in race;
2316 * process this trigger later at exit
2317 */
2318 if (fe->dpcm[stream].runtime_update != SND_SOC_DPCM_UPDATE_NO) {
2319 fe->dpcm[stream].trigger_pending = cmd + 1;
2320 return 0; /* delayed, assuming it's successful */
2321 }
2322
2323 /* we're alone, let's trigger */
2324 return dpcm_fe_dai_do_trigger(substream, cmd);
2325}
2326
Liam Girdwood23607022014-01-17 17:03:55 +00002327int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002328{
2329 struct snd_soc_dpcm *dpcm;
2330 int ret = 0;
2331
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002332 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002333
2334 struct snd_soc_pcm_runtime *be = dpcm->be;
2335 struct snd_pcm_substream *be_substream =
2336 snd_soc_dpcm_get_substream(be, stream);
2337
2338 /* is this op for this BE ? */
2339 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2340 continue;
2341
2342 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
Koro Chen95f444d2015-10-28 10:15:34 +08002343 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
Libin Yang5087a8f2019-05-08 10:32:41 +08002344 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND) &&
2345 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Liam Girdwood01d75842012-04-25 12:12:49 +01002346 continue;
2347
Liam Girdwood103d84a2012-11-19 14:39:15 +00002348 dev_dbg(be->dev, "ASoC: prepare BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002349 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002350
2351 ret = soc_pcm_prepare(be_substream);
2352 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002353 dev_err(be->dev, "ASoC: backend prepare failed %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002354 ret);
2355 break;
2356 }
2357
2358 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2359 }
2360 return ret;
2361}
2362
Mark Brown45c0a182012-05-09 21:46:27 +01002363static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002364{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002365 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002366 int stream = substream->stream, ret = 0;
2367
2368 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2369
Liam Girdwood103d84a2012-11-19 14:39:15 +00002370 dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002371
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002372 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002373
2374 /* there is no point preparing this FE if there are no BEs */
2375 if (list_empty(&fe->dpcm[stream].be_clients)) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002376 dev_err(fe->dev, "ASoC: no backend DAIs enabled for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002377 fe->dai_link->name);
2378 ret = -EINVAL;
2379 goto out;
2380 }
2381
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09002382 ret = dpcm_be_dai_prepare(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002383 if (ret < 0)
2384 goto out;
2385
2386 /* call prepare on the frontend */
2387 ret = soc_pcm_prepare(substream);
2388 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002389 dev_err(fe->dev,"ASoC: prepare FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002390 fe->dai_link->name);
2391 goto out;
2392 }
2393
2394 /* run the stream event for each BE */
2395 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
2396 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2397
2398out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002399 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002400 mutex_unlock(&fe->card->mutex);
2401
2402 return ret;
2403}
2404
Liam Girdwood618dae12012-04-25 12:12:51 +01002405static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
2406{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002407 struct snd_pcm_substream *substream =
2408 snd_soc_dpcm_get_substream(fe, stream);
2409 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01002410 int err;
Liam Girdwood01d75842012-04-25 12:12:49 +01002411
Liam Girdwood103d84a2012-11-19 14:39:15 +00002412 dev_dbg(fe->dev, "ASoC: runtime %s close on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002413 stream ? "capture" : "playback", fe->dai_link->name);
2414
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002415 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2416 /* call bespoke trigger - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002417 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002418 fe->dai_link->name);
2419
Kuninori Morimoto308193582020-04-24 08:15:09 +09002420 err = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002421 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002422 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002423 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002424 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002425 fe->dai_link->name);
2426
2427 err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
2428 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002429 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002430 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002431
2432 err = dpcm_be_dai_hw_free(fe, stream);
2433 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002434 dev_err(fe->dev,"ASoC: hw_free FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002435
2436 err = dpcm_be_dai_shutdown(fe, stream);
2437 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002438 dev_err(fe->dev,"ASoC: shutdown FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002439
2440 /* run the stream event for each BE */
2441 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2442
2443 return 0;
2444}
2445
2446static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
2447{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002448 struct snd_pcm_substream *substream =
2449 snd_soc_dpcm_get_substream(fe, stream);
Liam Girdwood618dae12012-04-25 12:12:51 +01002450 struct snd_soc_dpcm *dpcm;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002451 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01002452 int ret;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002453 unsigned long flags;
Liam Girdwood618dae12012-04-25 12:12:51 +01002454
Liam Girdwood103d84a2012-11-19 14:39:15 +00002455 dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002456 stream ? "capture" : "playback", fe->dai_link->name);
2457
2458 /* Only start the BE if the FE is ready */
2459 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
2460 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE)
2461 return -EINVAL;
2462
2463 /* startup must always be called for new BEs */
2464 ret = dpcm_be_dai_startup(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002465 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002466 goto disconnect;
Liam Girdwood618dae12012-04-25 12:12:51 +01002467
2468 /* keep going if FE state is > open */
2469 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN)
2470 return 0;
2471
2472 ret = dpcm_be_dai_hw_params(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002473 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002474 goto close;
Liam Girdwood618dae12012-04-25 12:12:51 +01002475
2476 /* keep going if FE state is > hw_params */
2477 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS)
2478 return 0;
2479
2480
2481 ret = dpcm_be_dai_prepare(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002482 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002483 goto hw_free;
Liam Girdwood618dae12012-04-25 12:12:51 +01002484
2485 /* run the stream event for each BE */
2486 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2487
2488 /* keep going if FE state is > prepare */
2489 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE ||
2490 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP)
2491 return 0;
2492
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002493 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2494 /* call trigger on the frontend - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002495 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002496 fe->dai_link->name);
Liam Girdwood618dae12012-04-25 12:12:51 +01002497
Kuninori Morimoto308193582020-04-24 08:15:09 +09002498 ret = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002499 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002500 dev_err(fe->dev,"ASoC: bespoke trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002501 goto hw_free;
2502 }
2503 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002504 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002505 fe->dai_link->name);
2506
2507 ret = dpcm_be_dai_trigger(fe, stream,
2508 SNDRV_PCM_TRIGGER_START);
2509 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002510 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002511 goto hw_free;
2512 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002513 }
2514
2515 return 0;
2516
2517hw_free:
2518 dpcm_be_dai_hw_free(fe, stream);
2519close:
2520 dpcm_be_dai_shutdown(fe, stream);
2521disconnect:
朱灿灿68f8043e2020-05-29 18:12:44 +08002522 /* disconnect any closed BEs */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002523 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002524 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood618dae12012-04-25 12:12:51 +01002525 struct snd_soc_pcm_runtime *be = dpcm->be;
朱灿灿68f8043e2020-05-29 18:12:44 +08002526 if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE)
2527 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
Liam Girdwood618dae12012-04-25 12:12:51 +01002528 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002529 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood618dae12012-04-25 12:12:51 +01002530
2531 return ret;
2532}
2533
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002534static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
2535{
2536 struct snd_soc_dapm_widget_list *list;
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002537 int stream;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002538 int count, paths;
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002539 int ret;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002540
Pierre-Louis Bossart96bf62f2020-06-12 15:35:07 -05002541 if (!fe->dai_link->dynamic)
2542 return 0;
2543
Bard Liao6e1276a2020-02-25 21:39:16 +08002544 if (fe->num_cpus > 1) {
2545 dev_err(fe->dev,
2546 "%s doesn't support Multi CPU yet\n", __func__);
2547 return -EINVAL;
2548 }
2549
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002550 /* only check active links */
Kuninori Morimotob3dea622020-05-15 09:46:51 +09002551 if (!snd_soc_dai_active(asoc_rtd_to_cpu(fe, 0)))
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002552 return 0;
2553
2554 /* DAPM sync will call this to update DSP paths */
2555 dev_dbg(fe->dev, "ASoC: DPCM %s runtime update for FE %s\n",
2556 new ? "new" : "old", fe->dai_link->name);
2557
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002558 for_each_pcm_streams(stream) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002559
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002560 /* skip if FE doesn't have playback/capture capability */
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002561 if (!snd_soc_dai_stream_valid(asoc_rtd_to_cpu(fe, 0), stream) ||
2562 !snd_soc_dai_stream_valid(asoc_rtd_to_codec(fe, 0), stream))
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002563 continue;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002564
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002565 /* skip if FE isn't currently playing/capturing */
Kuninori Morimotob3dea622020-05-15 09:46:51 +09002566 if (!snd_soc_dai_stream_active(asoc_rtd_to_cpu(fe, 0), stream) ||
2567 !snd_soc_dai_stream_active(asoc_rtd_to_codec(fe, 0), stream))
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002568 continue;
2569
2570 paths = dpcm_path_get(fe, stream, &list);
2571 if (paths < 0) {
2572 dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
2573 fe->dai_link->name,
2574 stream == SNDRV_PCM_STREAM_PLAYBACK ?
2575 "playback" : "capture");
2576 return paths;
2577 }
2578
2579 /* update any playback/capture paths */
2580 count = dpcm_process_paths(fe, stream, &list, new);
2581 if (count) {
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002582 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002583 if (new)
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002584 ret = dpcm_run_update_startup(fe, stream);
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002585 else
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002586 ret = dpcm_run_update_shutdown(fe, stream);
2587 if (ret < 0)
2588 dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n");
2589 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002590
2591 dpcm_clear_pending_state(fe, stream);
2592 dpcm_be_disconnect(fe, stream);
2593 }
2594
2595 dpcm_path_put(&list);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002596 }
2597
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002598 return 0;
2599}
2600
Liam Girdwood618dae12012-04-25 12:12:51 +01002601/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
2602 * any DAI links.
2603 */
Guennadi Liakhovetskif17a1472020-03-12 10:52:14 +01002604int snd_soc_dpcm_runtime_update(struct snd_soc_card *card)
Liam Girdwood618dae12012-04-25 12:12:51 +01002605{
Mengdong Lin1a497982015-11-18 02:34:11 -05002606 struct snd_soc_pcm_runtime *fe;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002607 int ret = 0;
Liam Girdwood618dae12012-04-25 12:12:51 +01002608
Liam Girdwood618dae12012-04-25 12:12:51 +01002609 mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002610 /* shutdown all old paths first */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002611 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002612 ret = soc_dpcm_fe_runtime_update(fe, 0);
2613 if (ret)
2614 goto out;
Liam Girdwood618dae12012-04-25 12:12:51 +01002615 }
2616
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002617 /* bring new paths up */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002618 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002619 ret = soc_dpcm_fe_runtime_update(fe, 1);
2620 if (ret)
2621 goto out;
2622 }
2623
2624out:
Liam Girdwood618dae12012-04-25 12:12:51 +01002625 mutex_unlock(&card->mutex);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002626 return ret;
Liam Girdwood618dae12012-04-25 12:12:51 +01002627}
Guennadi Liakhovetskif17a1472020-03-12 10:52:14 +01002628EXPORT_SYMBOL_GPL(snd_soc_dpcm_runtime_update);
Liam Girdwood01d75842012-04-25 12:12:49 +01002629
Kuninori Morimoto265694b62020-03-06 10:09:49 +09002630static void dpcm_fe_dai_cleanup(struct snd_pcm_substream *fe_substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002631{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002632 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002633 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto265694b62020-03-06 10:09:49 +09002634 int stream = fe_substream->stream;
Kuninori Morimoto30fca262020-03-06 10:09:44 +09002635
2636 /* mark FE's links ready to prune */
2637 for_each_dpcm_be(fe, stream, dpcm)
2638 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2639
2640 dpcm_be_disconnect(fe, stream);
2641
2642 fe->dpcm[stream].runtime = NULL;
Kuninori Morimoto265694b62020-03-06 10:09:49 +09002643}
2644
2645static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
2646{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002647 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Kuninori Morimoto265694b62020-03-06 10:09:49 +09002648 int ret;
2649
2650 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2651 ret = dpcm_fe_dai_shutdown(fe_substream);
2652
2653 dpcm_fe_dai_cleanup(fe_substream);
2654
Kuninori Morimoto30fca262020-03-06 10:09:44 +09002655 mutex_unlock(&fe->card->mutex);
2656 return ret;
2657}
2658
Liam Girdwood01d75842012-04-25 12:12:49 +01002659static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
2660{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002661 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002662 struct snd_soc_dapm_widget_list *list;
2663 int ret;
2664 int stream = fe_substream->stream;
2665
2666 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2667 fe->dpcm[stream].runtime = fe_substream->runtime;
2668
Qiao Zhou8f70e512014-09-10 17:54:07 +08002669 ret = dpcm_path_get(fe, stream, &list);
2670 if (ret < 0) {
Kuninori Morimotocae06eb2020-02-17 17:28:11 +09002671 goto open_end;
Qiao Zhou8f70e512014-09-10 17:54:07 +08002672 } else if (ret == 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002673 dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002674 fe->dai_link->name, stream ? "capture" : "playback");
Liam Girdwood01d75842012-04-25 12:12:49 +01002675 }
2676
2677 /* calculate valid and active FE <-> BE dpcms */
2678 dpcm_process_paths(fe, stream, &list, 1);
2679
2680 ret = dpcm_fe_dai_startup(fe_substream);
Kuninori Morimoto265694b62020-03-06 10:09:49 +09002681 if (ret < 0)
2682 dpcm_fe_dai_cleanup(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002683
2684 dpcm_clear_pending_state(fe, stream);
2685 dpcm_path_put(&list);
Kuninori Morimotocae06eb2020-02-17 17:28:11 +09002686open_end:
Liam Girdwood01d75842012-04-25 12:12:49 +01002687 mutex_unlock(&fe->card->mutex);
2688 return ret;
2689}
2690
Liam Girdwoodddee6272011-06-09 14:45:53 +01002691/* create a new pcm */
2692int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
2693{
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002694 struct snd_soc_dai *codec_dai;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002695 struct snd_soc_dai *cpu_dai;
Kuninori Morimoto2b544dd2019-10-15 12:59:31 +09002696 struct snd_soc_component *component;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002697 struct snd_pcm *pcm;
2698 char new_name[64];
2699 int ret = 0, playback = 0, capture = 0;
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002700 int stream;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002701 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002702
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002703 if (rtd->dai_link->dynamic && rtd->num_cpus > 1) {
2704 dev_err(rtd->dev,
2705 "DPCM doesn't support Multi CPU for Front-Ends yet\n");
2706 return -EINVAL;
2707 }
Stephan Gerhold9b5db052020-04-15 12:49:28 +02002708
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002709 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
2710 if (rtd->dai_link->dpcm_playback) {
2711 stream = SNDRV_PCM_STREAM_PLAYBACK;
2712
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002713 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
2714 if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
2715 playback = 1;
2716 break;
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002717 }
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002718 }
2719
2720 if (!playback) {
2721 dev_err(rtd->card->dev,
2722 "No CPU DAIs support playback for stream %s\n",
2723 rtd->dai_link->stream_name);
2724 return -EINVAL;
2725 }
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002726 }
2727 if (rtd->dai_link->dpcm_capture) {
2728 stream = SNDRV_PCM_STREAM_CAPTURE;
2729
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002730 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
2731 if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
2732 capture = 1;
2733 break;
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002734 }
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002735 }
2736
2737 if (!capture) {
2738 dev_err(rtd->card->dev,
2739 "No CPU DAIs support capture for stream %s\n",
2740 rtd->dai_link->stream_name);
2741 return -EINVAL;
2742 }
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002743 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002744 } else {
Jerome Bruneta3420312019-07-25 18:59:47 +02002745 /* Adapt stream for codec2codec links */
Stephan Gerholda4877a62020-02-18 11:38:24 +01002746 int cpu_capture = rtd->dai_link->params ?
2747 SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
2748 int cpu_playback = rtd->dai_link->params ?
2749 SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
Jerome Bruneta3420312019-07-25 18:59:47 +02002750
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09002751 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002752 if (rtd->num_cpus == 1) {
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002753 cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002754 } else if (rtd->num_cpus == rtd->num_codecs) {
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002755 cpu_dai = asoc_rtd_to_cpu(rtd, i);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002756 } else {
2757 dev_err(rtd->card->dev,
2758 "N cpus to M codecs link is not supported yet\n");
2759 return -EINVAL;
2760 }
2761
Kuninori Morimoto467fece2019-07-22 10:36:16 +09002762 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
Stephan Gerholda4877a62020-02-18 11:38:24 +01002763 snd_soc_dai_stream_valid(cpu_dai, cpu_playback))
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002764 playback = 1;
Kuninori Morimoto467fece2019-07-22 10:36:16 +09002765 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
Stephan Gerholda4877a62020-02-18 11:38:24 +01002766 snd_soc_dai_stream_valid(cpu_dai, cpu_capture))
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002767 capture = 1;
2768 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002769 }
Sangsu Parka5002312012-01-02 17:15:10 +09002770
Fabio Estevamd6bead02013-08-29 10:32:13 -03002771 if (rtd->dai_link->playback_only) {
2772 playback = 1;
2773 capture = 0;
2774 }
2775
2776 if (rtd->dai_link->capture_only) {
2777 playback = 0;
2778 capture = 1;
2779 }
2780
Liam Girdwood01d75842012-04-25 12:12:49 +01002781 /* create the PCM */
Jerome Bruneta3420312019-07-25 18:59:47 +02002782 if (rtd->dai_link->params) {
2783 snprintf(new_name, sizeof(new_name), "codec2codec(%s)",
2784 rtd->dai_link->stream_name);
2785
2786 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
2787 playback, capture, &pcm);
2788 } else if (rtd->dai_link->no_pcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002789 snprintf(new_name, sizeof(new_name), "(%s)",
2790 rtd->dai_link->stream_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002791
Liam Girdwood01d75842012-04-25 12:12:49 +01002792 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
2793 playback, capture, &pcm);
2794 } else {
2795 if (rtd->dai_link->dynamic)
2796 snprintf(new_name, sizeof(new_name), "%s (*)",
2797 rtd->dai_link->stream_name);
2798 else
2799 snprintf(new_name, sizeof(new_name), "%s %s-%d",
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002800 rtd->dai_link->stream_name,
2801 (rtd->num_codecs > 1) ?
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002802 "multicodec" : asoc_rtd_to_codec(rtd, 0)->name, num);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002803
Liam Girdwood01d75842012-04-25 12:12:49 +01002804 ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
2805 capture, &pcm);
2806 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01002807 if (ret < 0) {
Pierre-Louis Bossart799827a2020-06-12 15:40:49 -05002808 dev_err(rtd->card->dev, "ASoC: can't create pcm %s for dailink %s: %d\n",
2809 new_name, rtd->dai_link->name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002810 return ret;
2811 }
Liam Girdwood103d84a2012-11-19 14:39:15 +00002812 dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002813
2814 /* DAPM dai link stream work */
Jerome Bruneta3420312019-07-25 18:59:47 +02002815 if (rtd->dai_link->params)
Curtis Malainey4bf2e382019-12-03 09:30:07 -08002816 rtd->close_delayed_work_func = codec2codec_close_delayed_work;
Jerome Bruneta3420312019-07-25 18:59:47 +02002817 else
Kuninori Morimoto83f94a22020-01-10 11:36:17 +09002818 rtd->close_delayed_work_func = snd_soc_close_delayed_work;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002819
Vinod Koul48c76992015-02-12 09:59:53 +05302820 pcm->nonatomic = rtd->dai_link->nonatomic;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002821 rtd->pcm = pcm;
2822 pcm->private_data = rtd;
Liam Girdwood01d75842012-04-25 12:12:49 +01002823
Jerome Bruneta3420312019-07-25 18:59:47 +02002824 if (rtd->dai_link->no_pcm || rtd->dai_link->params) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002825 if (playback)
2826 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
2827 if (capture)
2828 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
2829 goto out;
2830 }
2831
2832 /* ASoC PCM operations */
2833 if (rtd->dai_link->dynamic) {
2834 rtd->ops.open = dpcm_fe_dai_open;
2835 rtd->ops.hw_params = dpcm_fe_dai_hw_params;
2836 rtd->ops.prepare = dpcm_fe_dai_prepare;
2837 rtd->ops.trigger = dpcm_fe_dai_trigger;
2838 rtd->ops.hw_free = dpcm_fe_dai_hw_free;
2839 rtd->ops.close = dpcm_fe_dai_close;
2840 rtd->ops.pointer = soc_pcm_pointer;
2841 } else {
2842 rtd->ops.open = soc_pcm_open;
2843 rtd->ops.hw_params = soc_pcm_hw_params;
2844 rtd->ops.prepare = soc_pcm_prepare;
2845 rtd->ops.trigger = soc_pcm_trigger;
2846 rtd->ops.hw_free = soc_pcm_hw_free;
2847 rtd->ops.close = soc_pcm_close;
2848 rtd->ops.pointer = soc_pcm_pointer;
2849 }
2850
Kuninori Morimoto613fb502020-01-10 11:35:21 +09002851 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto2b544dd2019-10-15 12:59:31 +09002852 const struct snd_soc_component_driver *drv = component->driver;
Kuninori Morimotob8135862017-10-11 01:37:23 +00002853
Takashi Iwai3b1c9522019-11-21 20:07:08 +01002854 if (drv->ioctl)
2855 rtd->ops.ioctl = snd_soc_pcm_component_ioctl;
Takashi Iwai1e5ddb62019-11-21 20:07:09 +01002856 if (drv->sync_stop)
2857 rtd->ops.sync_stop = snd_soc_pcm_component_sync_stop;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002858 if (drv->copy_user)
Kuninori Morimoto82d81f52019-07-26 13:51:56 +09002859 rtd->ops.copy_user = snd_soc_pcm_component_copy_user;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002860 if (drv->page)
Kuninori Morimoto9c712e42019-07-26 13:52:00 +09002861 rtd->ops.page = snd_soc_pcm_component_page;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002862 if (drv->mmap)
Kuninori Morimoto205875e2019-07-26 13:52:04 +09002863 rtd->ops.mmap = snd_soc_pcm_component_mmap;
Shengjiu Wang8451e2e2021-03-12 10:38:40 +08002864 if (drv->ack)
2865 rtd->ops.ack = snd_soc_pcm_component_ack;
Kuninori Morimotob8135862017-10-11 01:37:23 +00002866 }
2867
Liam Girdwoodddee6272011-06-09 14:45:53 +01002868 if (playback)
Liam Girdwood01d75842012-04-25 12:12:49 +01002869 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002870
2871 if (capture)
Liam Girdwood01d75842012-04-25 12:12:49 +01002872 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002873
Kuninori Morimotob2b2afb2019-11-18 10:50:32 +09002874 ret = snd_soc_pcm_component_new(rtd);
Kuninori Morimoto74842912019-07-26 13:52:08 +09002875 if (ret < 0) {
Pierre-Louis Bossart799827a2020-06-12 15:40:49 -05002876 dev_err(rtd->dev, "ASoC: pcm %s constructor failed for dailink %s: %d\n",
2877 new_name, rtd->dai_link->name, ret);
Kuninori Morimoto74842912019-07-26 13:52:08 +09002878 return ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002879 }
Johan Hovoldc641e5b2017-07-12 17:55:29 +02002880
Takashi Iwai3d21ef02019-01-11 15:58:39 +01002881 pcm->no_device_suspend = true;
Liam Girdwood01d75842012-04-25 12:12:49 +01002882out:
Pierre-Louis Bossart1d5cd522020-06-12 15:40:50 -05002883 dev_dbg(rtd->card->dev, "%s <-> %s mapping ok\n",
2884 (rtd->num_codecs > 1) ? "multicodec" : asoc_rtd_to_codec(rtd, 0)->name,
2885 (rtd->num_cpus > 1) ? "multicpu" : asoc_rtd_to_cpu(rtd, 0)->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002886 return ret;
2887}
Liam Girdwood01d75842012-04-25 12:12:49 +01002888
2889/* is the current PCM operation for this FE ? */
2890int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream)
2891{
2892 if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE)
2893 return 1;
2894 return 0;
2895}
2896EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update);
2897
2898/* is the current PCM operation for this BE ? */
2899int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
2900 struct snd_soc_pcm_runtime *be, int stream)
2901{
2902 if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) ||
2903 ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) &&
2904 be->dpcm[stream].runtime_update))
2905 return 1;
2906 return 0;
2907}
2908EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update);
2909
2910/* get the substream for this BE */
2911struct snd_pcm_substream *
2912 snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream)
2913{
2914 return be->pcm->streams[stream].substream;
2915}
2916EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream);
2917
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002918static int snd_soc_dpcm_check_state(struct snd_soc_pcm_runtime *fe,
2919 struct snd_soc_pcm_runtime *be,
2920 int stream,
2921 const enum snd_soc_dpcm_state *states,
2922 int num_states)
Liam Girdwood01d75842012-04-25 12:12:49 +01002923{
2924 struct snd_soc_dpcm *dpcm;
2925 int state;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002926 int ret = 1;
2927 unsigned long flags;
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002928 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01002929
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002930 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00002931 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002932
2933 if (dpcm->fe == fe)
2934 continue;
2935
2936 state = dpcm->fe->dpcm[stream].state;
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002937 for (i = 0; i < num_states; i++) {
2938 if (state == states[i]) {
2939 ret = 0;
2940 break;
2941 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002942 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002943 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002944 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01002945
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002946 /* it's safe to do this BE DAI */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002947 return ret;
Liam Girdwood01d75842012-04-25 12:12:49 +01002948}
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002949
2950/*
2951 * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE
2952 * are not running, paused or suspended for the specified stream direction.
2953 */
2954int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
2955 struct snd_soc_pcm_runtime *be, int stream)
2956{
2957 const enum snd_soc_dpcm_state state[] = {
2958 SND_SOC_DPCM_STATE_START,
2959 SND_SOC_DPCM_STATE_PAUSED,
2960 SND_SOC_DPCM_STATE_SUSPEND,
2961 };
2962
2963 return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
2964}
Liam Girdwood01d75842012-04-25 12:12:49 +01002965EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop);
2966
2967/*
2968 * We can only change hw params a BE DAI if any of it's FE are not prepared,
2969 * running, paused or suspended for the specified stream direction.
2970 */
2971int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
2972 struct snd_soc_pcm_runtime *be, int stream)
2973{
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002974 const enum snd_soc_dpcm_state state[] = {
2975 SND_SOC_DPCM_STATE_START,
2976 SND_SOC_DPCM_STATE_PAUSED,
2977 SND_SOC_DPCM_STATE_SUSPEND,
2978 SND_SOC_DPCM_STATE_PREPARE,
2979 };
Liam Girdwood01d75842012-04-25 12:12:49 +01002980
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002981 return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
Liam Girdwood01d75842012-04-25 12:12:49 +01002982}
2983EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);