blob: 7abfc48b26ca51997b8cffeb567392f8729f0701 [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
Takashi Iwaib7898392021-12-07 11:37:42 -060030static inline void snd_soc_dpcm_mutex_lock(struct snd_soc_pcm_runtime *rtd)
31{
32 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
33}
34
35static inline void snd_soc_dpcm_mutex_unlock(struct snd_soc_pcm_runtime *rtd)
36{
37 mutex_unlock(&rtd->card->pcm_mutex);
38}
39
40#define snd_soc_dpcm_mutex_assert_held(rtd) \
41 lockdep_assert_held(&(rtd)->card->pcm_mutex)
42
43static inline void snd_soc_dpcm_stream_lock_irq(struct snd_soc_pcm_runtime *rtd,
44 int stream)
45{
46 snd_pcm_stream_lock_irq(snd_soc_dpcm_get_substream(rtd, stream));
47}
48
Takashi Iwaib2ae8062021-12-07 11:37:43 -060049#define snd_soc_dpcm_stream_lock_irqsave(rtd, stream, flags) \
50 snd_pcm_stream_lock_irqsave(snd_soc_dpcm_get_substream(rtd, stream), flags)
51
Takashi Iwaib7898392021-12-07 11:37:42 -060052static inline void snd_soc_dpcm_stream_unlock_irq(struct snd_soc_pcm_runtime *rtd,
53 int stream)
54{
55 snd_pcm_stream_unlock_irq(snd_soc_dpcm_get_substream(rtd, stream));
56}
57
Takashi Iwaib2ae8062021-12-07 11:37:43 -060058#define snd_soc_dpcm_stream_unlock_irqrestore(rtd, stream, flags) \
59 snd_pcm_stream_unlock_irqrestore(snd_soc_dpcm_get_substream(rtd, stream), flags)
60
Liam Girdwood01d75842012-04-25 12:12:49 +010061#define DPCM_MAX_BE_USERS 8
62
Kuninori Morimoto6fb89442021-03-09 10:07:48 +090063static inline const char *soc_cpu_dai_name(struct snd_soc_pcm_runtime *rtd)
64{
65 return (rtd)->num_cpus == 1 ? asoc_rtd_to_cpu(rtd, 0)->name : "multicpu";
66}
67static inline const char *soc_codec_dai_name(struct snd_soc_pcm_runtime *rtd)
68{
69 return (rtd)->num_codecs == 1 ? asoc_rtd_to_codec(rtd, 0)->name : "multicodec";
70}
71
Kuninori Morimotoc3212822020-02-19 15:56:57 +090072#ifdef CONFIG_DEBUG_FS
73static const char *dpcm_state_string(enum snd_soc_dpcm_state state)
74{
75 switch (state) {
76 case SND_SOC_DPCM_STATE_NEW:
77 return "new";
78 case SND_SOC_DPCM_STATE_OPEN:
79 return "open";
80 case SND_SOC_DPCM_STATE_HW_PARAMS:
81 return "hw_params";
82 case SND_SOC_DPCM_STATE_PREPARE:
83 return "prepare";
84 case SND_SOC_DPCM_STATE_START:
85 return "start";
86 case SND_SOC_DPCM_STATE_STOP:
87 return "stop";
88 case SND_SOC_DPCM_STATE_SUSPEND:
89 return "suspend";
90 case SND_SOC_DPCM_STATE_PAUSED:
91 return "paused";
92 case SND_SOC_DPCM_STATE_HW_FREE:
93 return "hw_free";
94 case SND_SOC_DPCM_STATE_CLOSE:
95 return "close";
96 }
97
98 return "unknown";
99}
100
101static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
102 int stream, char *buf, size_t size)
103{
104 struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params;
105 struct snd_soc_dpcm *dpcm;
106 ssize_t offset = 0;
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900107
108 /* FE state */
Takashi Iwaid0c9abb2020-03-10 17:36:25 +0100109 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900110 "[%s - %s]\n", fe->dai_link->name,
111 stream ? "Capture" : "Playback");
112
Takashi Iwaid0c9abb2020-03-10 17:36:25 +0100113 offset += scnprintf(buf + offset, size - offset, "State: %s\n",
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900114 dpcm_state_string(fe->dpcm[stream].state));
115
116 if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
117 (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
Takashi Iwaid0c9abb2020-03-10 17:36:25 +0100118 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900119 "Hardware Params: "
120 "Format = %s, Channels = %d, Rate = %d\n",
121 snd_pcm_format_name(params_format(params)),
122 params_channels(params),
123 params_rate(params));
124
125 /* BEs state */
Takashi Iwaid0c9abb2020-03-10 17:36:25 +0100126 offset += scnprintf(buf + offset, size - offset, "Backends:\n");
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900127
128 if (list_empty(&fe->dpcm[stream].be_clients)) {
Takashi Iwaid0c9abb2020-03-10 17:36:25 +0100129 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900130 " No active DSP links\n");
131 goto out;
132 }
133
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900134 for_each_dpcm_be(fe, stream, dpcm) {
135 struct snd_soc_pcm_runtime *be = dpcm->be;
136 params = &dpcm->hw_params;
137
Takashi Iwaid0c9abb2020-03-10 17:36:25 +0100138 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900139 "- %s\n", be->dai_link->name);
140
Takashi Iwaid0c9abb2020-03-10 17:36:25 +0100141 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900142 " State: %s\n",
143 dpcm_state_string(be->dpcm[stream].state));
144
145 if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
146 (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
Takashi Iwaid0c9abb2020-03-10 17:36:25 +0100147 offset += scnprintf(buf + offset, size - offset,
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900148 " Hardware Params: "
149 "Format = %s, Channels = %d, Rate = %d\n",
150 snd_pcm_format_name(params_format(params)),
151 params_channels(params),
152 params_rate(params));
153 }
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900154out:
155 return offset;
156}
157
158static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf,
159 size_t count, loff_t *ppos)
160{
161 struct snd_soc_pcm_runtime *fe = file->private_data;
162 ssize_t out_count = PAGE_SIZE, offset = 0, ret = 0;
163 int stream;
164 char *buf;
165
Bard Liao6e1276a2020-02-25 21:39:16 +0800166 if (fe->num_cpus > 1) {
167 dev_err(fe->dev,
168 "%s doesn't support Multi CPU yet\n", __func__);
169 return -EINVAL;
170 }
171
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900172 buf = kmalloc(out_count, GFP_KERNEL);
173 if (!buf)
174 return -ENOMEM;
175
Takashi Iwaib7898392021-12-07 11:37:42 -0600176 snd_soc_dpcm_mutex_lock(fe);
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900177 for_each_pcm_streams(stream)
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900178 if (snd_soc_dai_stream_valid(asoc_rtd_to_cpu(fe, 0), stream))
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900179 offset += dpcm_show_state(fe, stream,
180 buf + offset,
181 out_count - offset);
Takashi Iwaib7898392021-12-07 11:37:42 -0600182 snd_soc_dpcm_mutex_unlock(fe);
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900183
184 ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
185
186 kfree(buf);
187 return ret;
188}
189
190static const struct file_operations dpcm_state_fops = {
191 .open = simple_open,
192 .read = dpcm_state_read_file,
193 .llseek = default_llseek,
194};
195
196void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
197{
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900198 if (!rtd->dai_link->dynamic)
199 return;
200
201 if (!rtd->card->debugfs_card_root)
202 return;
203
204 rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name,
205 rtd->card->debugfs_card_root);
206
207 debugfs_create_file("state", 0444, rtd->debugfs_dpcm_root,
208 rtd, &dpcm_state_fops);
209}
Kuninori Morimoto154dae82020-02-19 15:57:06 +0900210
211static void dpcm_create_debugfs_state(struct snd_soc_dpcm *dpcm, int stream)
212{
213 char *name;
214
215 name = kasprintf(GFP_KERNEL, "%s:%s", dpcm->be->dai_link->name,
216 stream ? "capture" : "playback");
217 if (name) {
218 dpcm->debugfs_state = debugfs_create_dir(
219 name, dpcm->fe->debugfs_dpcm_root);
220 debugfs_create_u32("state", 0644, dpcm->debugfs_state,
221 &dpcm->state);
222 kfree(name);
223 }
224}
225
226static void dpcm_remove_debugfs_state(struct snd_soc_dpcm *dpcm)
227{
228 debugfs_remove_recursive(dpcm->debugfs_state);
229}
230
231#else
232static inline void dpcm_create_debugfs_state(struct snd_soc_dpcm *dpcm,
233 int stream)
234{
235}
236
237static inline void dpcm_remove_debugfs_state(struct snd_soc_dpcm *dpcm)
238{
239}
Kuninori Morimotoc3212822020-02-19 15:56:57 +0900240#endif
241
Kuninori Morimoto9c6d7f92020-12-11 14:55:16 +0900242/* Set FE's runtime_update state; the state is protected via PCM stream lock
243 * for avoiding the race with trigger callback.
244 * If the state is unset and a trigger is pending while the previous operation,
245 * process the pending trigger action here.
246 */
247static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
248static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
249 int stream, enum snd_soc_dpcm_update state)
250{
251 struct snd_pcm_substream *substream =
252 snd_soc_dpcm_get_substream(fe, stream);
253
Takashi Iwaib7898392021-12-07 11:37:42 -0600254 snd_soc_dpcm_stream_lock_irq(fe, stream);
Kuninori Morimoto9c6d7f92020-12-11 14:55:16 +0900255 if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) {
256 dpcm_fe_dai_do_trigger(substream,
257 fe->dpcm[stream].trigger_pending - 1);
258 fe->dpcm[stream].trigger_pending = 0;
259 }
260 fe->dpcm[stream].runtime_update = state;
Takashi Iwaib7898392021-12-07 11:37:42 -0600261 snd_soc_dpcm_stream_unlock_irq(fe, stream);
Kuninori Morimoto9c6d7f92020-12-11 14:55:16 +0900262}
263
Kuninori Morimotoa7e204442020-12-11 14:55:22 +0900264static void dpcm_set_be_update_state(struct snd_soc_pcm_runtime *be,
265 int stream, enum snd_soc_dpcm_update state)
266{
267 be->dpcm[stream].runtime_update = state;
268}
269
Kuninori Morimotod9051d82020-05-15 09:46:21 +0900270/**
271 * snd_soc_runtime_action() - Increment/Decrement active count for
272 * PCM runtime components
273 * @rtd: ASoC PCM runtime that is activated
274 * @stream: Direction of the PCM stream
Colton Lewisb6d6e9e2020-06-26 05:40:24 +0000275 * @action: Activate stream if 1. Deactivate if -1.
Kuninori Morimotod9051d82020-05-15 09:46:21 +0900276 *
277 * Increments/Decrements the active count for all the DAIs and components
278 * attached to a PCM runtime.
279 * Should typically be called when a stream is opened.
280 *
281 * Must be called with the rtd->card->pcm_mutex being held
282 */
283void snd_soc_runtime_action(struct snd_soc_pcm_runtime *rtd,
284 int stream, int action)
Kuninori Morimoto7a5aaba2020-02-10 12:14:12 +0900285{
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900286 struct snd_soc_dai *dai;
Kuninori Morimoto7a5aaba2020-02-10 12:14:12 +0900287 int i;
288
Takashi Iwaib7898392021-12-07 11:37:42 -0600289 snd_soc_dpcm_mutex_assert_held(rtd);
Kuninori Morimoto7a5aaba2020-02-10 12:14:12 +0900290
Kuninori Morimotodc829102020-05-15 09:46:27 +0900291 for_each_rtd_dais(rtd, i, dai)
292 snd_soc_dai_action(dai, stream, action);
Kuninori Morimoto7a5aaba2020-02-10 12:14:12 +0900293}
Kuninori Morimotod9051d82020-05-15 09:46:21 +0900294EXPORT_SYMBOL_GPL(snd_soc_runtime_action);
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100295
296/**
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100297 * snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay
298 * @rtd: The ASoC PCM runtime that should be checked.
299 *
300 * This function checks whether the power down delay should be ignored for a
301 * specific PCM runtime. Returns true if the delay is 0, if it the DAI link has
302 * been configured to ignore the delay, or if none of the components benefits
303 * from having the delay.
304 */
305bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
306{
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000307 struct snd_soc_component *component;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200308 bool ignore = true;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900309 int i;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200310
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100311 if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
312 return true;
313
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900314 for_each_rtd_components(rtd, i, component)
Kuninori Morimoto72c38182018-01-19 05:21:19 +0000315 ignore &= !component->driver->use_pmdown_time;
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000316
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000317 return ignore;
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100318}
319
320/**
Lars-Peter Clausen90996f42013-05-14 11:05:30 +0200321 * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
322 * @substream: the pcm substream
323 * @hw: the hardware parameters
324 *
325 * Sets the substream runtime hardware parameters.
326 */
327int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
328 const struct snd_pcm_hardware *hw)
329{
Kuninori Morimoto56e749b2021-03-09 10:07:53 +0900330 substream->runtime->hw = *hw;
331
Lars-Peter Clausen90996f42013-05-14 11:05:30 +0200332 return 0;
333}
334EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
335
Liam Girdwood01d75842012-04-25 12:12:49 +0100336/* DPCM stream event, send event to FE and all active BEs. */
Liam Girdwood23607022014-01-17 17:03:55 +0000337int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
Liam Girdwood01d75842012-04-25 12:12:49 +0100338 int event)
339{
340 struct snd_soc_dpcm *dpcm;
341
Takashi Iwaib7898392021-12-07 11:37:42 -0600342 snd_soc_dpcm_mutex_assert_held(fe);
343
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +0000344 for_each_dpcm_be(fe, dir, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +0100345
346 struct snd_soc_pcm_runtime *be = dpcm->be;
347
Liam Girdwood103d84a2012-11-19 14:39:15 +0000348 dev_dbg(be->dev, "ASoC: BE %s event %d dir %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +0100349 be->dai_link->name, event, dir);
350
Banajit Goswamib1cd2e32017-07-14 23:15:05 -0700351 if ((event == SND_SOC_DAPM_STREAM_STOP) &&
352 (be->dpcm[dir].users >= 1))
353 continue;
354
Liam Girdwood01d75842012-04-25 12:12:49 +0100355 snd_soc_dapm_stream_event(be, dir, event);
356 }
357
358 snd_soc_dapm_stream_event(fe, dir, event);
359
360 return 0;
361}
362
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900363static void soc_pcm_set_dai_params(struct snd_soc_dai *dai,
364 struct snd_pcm_hw_params *params)
365{
366 if (params) {
367 dai->rate = params_rate(params);
368 dai->channels = params_channels(params);
369 dai->sample_bits = snd_pcm_format_physical_width(params_format(params));
370 } else {
371 dai->rate = 0;
372 dai->channels = 0;
373 dai->sample_bits = 0;
374 }
375}
376
Dong Aisheng17841022011-08-29 17:15:14 +0800377static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
378 struct snd_soc_dai *soc_dai)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100379{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900380 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100381 int ret;
382
Kuninori Morimotof8fc9ec2021-03-09 10:07:42 +0900383 if (!snd_soc_dai_active(soc_dai))
384 return 0;
385
Kuninori Morimotofac110c2021-01-15 13:56:35 +0900386#define __soc_pcm_apply_symmetry(name, NAME) \
387 if (soc_dai->name && (soc_dai->driver->symmetric_##name || \
388 rtd->dai_link->symmetric_##name)) { \
389 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %s to %d\n",\
390 #name, soc_dai->name); \
391 \
392 ret = snd_pcm_hw_constraint_single(substream->runtime, \
393 SNDRV_PCM_HW_PARAM_##NAME,\
394 soc_dai->name); \
395 if (ret < 0) { \
396 dev_err(soc_dai->dev, \
397 "ASoC: Unable to apply %s constraint: %d\n",\
398 #name, ret); \
399 return ret; \
400 } \
Liam Girdwoodddee6272011-06-09 14:45:53 +0100401 }
402
Kuninori Morimotofac110c2021-01-15 13:56:35 +0900403 __soc_pcm_apply_symmetry(rate, RATE);
404 __soc_pcm_apply_symmetry(channels, CHANNELS);
405 __soc_pcm_apply_symmetry(sample_bits, SAMPLE_BITS);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100406
407 return 0;
408}
409
Nicolin Chen3635bf02013-11-13 18:56:24 +0800410static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
411 struct snd_pcm_hw_params *params)
412{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900413 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900414 struct snd_soc_dai d;
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900415 struct snd_soc_dai *dai;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800416 struct snd_soc_dai *cpu_dai;
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900417 unsigned int symmetry, i;
Nicolin Chen3635bf02013-11-13 18:56:24 +0800418
Kuninori Morimotoee39d772021-04-16 11:00:11 +0900419 d.name = __func__;
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900420 soc_pcm_set_dai_params(&d, params);
Nicolin Chen3635bf02013-11-13 18:56:24 +0800421
Kuninori Morimoto1cacbac2021-04-16 10:59:48 +0900422#define __soc_pcm_params_symmetry(xxx) \
423 symmetry = rtd->dai_link->symmetric_##xxx; \
Kuninori Morimoto3a906722021-01-15 13:56:39 +0900424 for_each_rtd_dais(rtd, i, dai) \
Kuninori Morimoto1cacbac2021-04-16 10:59:48 +0900425 symmetry |= dai->driver->symmetric_##xxx; \
Kuninori Morimoto3a906722021-01-15 13:56:39 +0900426 \
427 if (symmetry) \
428 for_each_rtd_cpu_dais(rtd, i, cpu_dai) \
Kuninori Morimoto9c2ae362021-04-16 11:00:32 +0900429 if (!snd_soc_dai_is_dummy(cpu_dai) && \
430 cpu_dai->xxx && cpu_dai->xxx != d.xxx) { \
Kuninori Morimotoee39d772021-04-16 11:00:11 +0900431 dev_err(rtd->dev, "ASoC: unmatched %s symmetry: %s:%d - %s:%d\n", \
432 #xxx, cpu_dai->name, cpu_dai->xxx, d.name, d.xxx); \
Kuninori Morimoto3a906722021-01-15 13:56:39 +0900433 return -EINVAL; \
434 }
435
Nicolin Chen3635bf02013-11-13 18:56:24 +0800436 /* reject unmatched parameters when applying symmetry */
Kuninori Morimoto3a906722021-01-15 13:56:39 +0900437 __soc_pcm_params_symmetry(rate);
438 __soc_pcm_params_symmetry(channels);
439 __soc_pcm_params_symmetry(sample_bits);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100440
441 return 0;
442}
443
Kuninori Morimoto68cbc552021-03-09 10:07:57 +0900444static void soc_pcm_update_symmetry(struct snd_pcm_substream *substream)
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100445{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900446 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100447 struct snd_soc_dai_link *link = rtd->dai_link;
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900448 struct snd_soc_dai *dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200449 unsigned int symmetry, i;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100450
Kuninori Morimotof14654d2021-01-15 13:52:54 +0900451 symmetry = link->symmetric_rate ||
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800452 link->symmetric_channels ||
Kuninori Morimotof14654d2021-01-15 13:52:54 +0900453 link->symmetric_sample_bits;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800454
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900455 for_each_rtd_dais(rtd, i, dai)
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800456 symmetry = symmetry ||
Kuninori Morimotof14654d2021-01-15 13:52:54 +0900457 dai->driver->symmetric_rate ||
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900458 dai->driver->symmetric_channels ||
Kuninori Morimotof14654d2021-01-15 13:52:54 +0900459 dai->driver->symmetric_sample_bits;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200460
Kuninori Morimoto68cbc552021-03-09 10:07:57 +0900461 if (symmetry)
462 substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100463}
464
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200465static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits)
Mark Brown58ba9b22012-01-16 18:38:51 +0000466{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900467 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Takashi Iwaic6068d32014-12-31 17:10:34 +0100468 int ret;
Mark Brown58ba9b22012-01-16 18:38:51 +0000469
470 if (!bits)
471 return;
472
Lars-Peter Clausen0e2a3752014-12-29 18:43:38 +0100473 ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 0, bits);
474 if (ret != 0)
475 dev_warn(rtd->dev, "ASoC: Failed to set MSB %d: %d\n",
476 bits, ret);
Mark Brown58ba9b22012-01-16 18:38:51 +0000477}
478
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200479static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200480{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900481 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800482 struct snd_soc_dai *cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200483 struct snd_soc_dai *codec_dai;
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900484 int stream = substream->stream;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200485 int i;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800486 unsigned int bits = 0, cpu_bits = 0;
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200487
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900488 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Kuninori Morimoto2bc3e1f2021-07-27 11:05:34 +0900489 struct snd_soc_pcm_stream *pcm_codec = snd_soc_dai_get_pcm_stream(codec_dai, stream);
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900490
491 if (pcm_codec->sig_bits == 0) {
492 bits = 0;
493 break;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200494 }
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900495 bits = max(pcm_codec->sig_bits, bits);
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200496 }
497
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900498 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Kuninori Morimoto2bc3e1f2021-07-27 11:05:34 +0900499 struct snd_soc_pcm_stream *pcm_cpu = snd_soc_dai_get_pcm_stream(cpu_dai, stream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800500
501 if (pcm_cpu->sig_bits == 0) {
502 cpu_bits = 0;
503 break;
504 }
505 cpu_bits = max(pcm_cpu->sig_bits, cpu_bits);
506 }
Kuninori Morimoto57be9202020-02-19 15:56:36 +0900507
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200508 soc_pcm_set_msb(substream, bits);
509 soc_pcm_set_msb(substream, cpu_bits);
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200510}
511
Kuninori Morimotof6c04af2021-02-04 08:50:31 +0900512static void soc_pcm_hw_init(struct snd_pcm_hardware *hw)
513{
514 hw->rates = UINT_MAX;
515 hw->rate_min = 0;
516 hw->rate_max = UINT_MAX;
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900517 hw->channels_min = 0;
518 hw->channels_max = UINT_MAX;
Kuninori Morimotodebc71f2021-02-04 08:52:04 +0900519 hw->formats = ULLONG_MAX;
Kuninori Morimotof6c04af2021-02-04 08:50:31 +0900520}
521
522static void soc_pcm_hw_update_rate(struct snd_pcm_hardware *hw,
523 struct snd_soc_pcm_stream *p)
524{
525 hw->rates = snd_pcm_rate_mask_intersect(hw->rates, p->rates);
526
527 /* setup hw->rate_min/max via hw->rates first */
528 snd_pcm_hw_limit_rates(hw);
529
530 /* update hw->rate_min/max by snd_soc_pcm_stream */
531 hw->rate_min = max(hw->rate_min, p->rate_min);
532 hw->rate_max = min_not_zero(hw->rate_max, p->rate_max);
533}
534
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900535static void soc_pcm_hw_update_chan(struct snd_pcm_hardware *hw,
536 struct snd_soc_pcm_stream *p)
537{
538 hw->channels_min = max(hw->channels_min, p->channels_min);
539 hw->channels_max = min(hw->channels_max, p->channels_max);
540}
541
Kuninori Morimotodebc71f2021-02-04 08:52:04 +0900542static void soc_pcm_hw_update_format(struct snd_pcm_hardware *hw,
543 struct snd_soc_pcm_stream *p)
544{
545 hw->formats &= p->formats;
546}
547
Samuel Holland5854a462020-03-04 23:11:42 -0600548/**
549 * snd_soc_runtime_calc_hw() - Calculate hw limits for a PCM stream
550 * @rtd: ASoC PCM runtime
551 * @hw: PCM hardware parameters (output)
552 * @stream: Direction of the PCM stream
553 *
554 * Calculates the subset of stream parameters supported by all DAIs
555 * associated with the PCM stream.
556 */
557int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd,
558 struct snd_pcm_hardware *hw, int stream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200559{
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000560 struct snd_soc_dai *codec_dai;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800561 struct snd_soc_dai *cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200562 struct snd_soc_pcm_stream *codec_stream;
563 struct snd_soc_pcm_stream *cpu_stream;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800564 unsigned int cpu_chan_min = 0, cpu_chan_max = UINT_MAX;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200565 int i;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100566
Kuninori Morimotof6c04af2021-02-04 08:50:31 +0900567 soc_pcm_hw_init(hw);
568
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800569 /* first calculate min/max only for CPUs in the DAI link */
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900570 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800571
572 /*
573 * Skip CPUs which don't support the current stream type.
574 * Otherwise, since the rate, channel, and format values will
575 * zero in that case, we would have no usable settings left,
576 * causing the resulting setup to fail.
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800577 */
Samuel Holland5854a462020-03-04 23:11:42 -0600578 if (!snd_soc_dai_stream_valid(cpu_dai, stream))
Bard Liao0e9cf4c42020-02-25 21:39:17 +0800579 continue;
580
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800581 cpu_stream = snd_soc_dai_get_pcm_stream(cpu_dai, stream);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100582
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900583 soc_pcm_hw_update_chan(hw, cpu_stream);
Kuninori Morimotof6c04af2021-02-04 08:50:31 +0900584 soc_pcm_hw_update_rate(hw, cpu_stream);
Kuninori Morimotodebc71f2021-02-04 08:52:04 +0900585 soc_pcm_hw_update_format(hw, cpu_stream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800586 }
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900587 cpu_chan_min = hw->channels_min;
588 cpu_chan_max = hw->channels_max;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800589
590 /* second calculate min/max only for CODECs in the DAI link */
Kuninori Morimotoa4be4182020-03-09 13:08:04 +0900591 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200592
593 /*
594 * Skip CODECs which don't support the current stream type.
595 * Otherwise, since the rate, channel, and format values will
596 * zero in that case, we would have no usable settings left,
597 * causing the resulting setup to fail.
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200598 */
Kuninori Morimoto25c2f512020-02-27 10:54:38 +0900599 if (!snd_soc_dai_stream_valid(codec_dai, stream))
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200600 continue;
601
Kuninori Morimotoacf253c2020-02-19 15:56:30 +0900602 codec_stream = snd_soc_dai_get_pcm_stream(codec_dai, stream);
603
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900604 soc_pcm_hw_update_chan(hw, codec_stream);
Kuninori Morimotof6c04af2021-02-04 08:50:31 +0900605 soc_pcm_hw_update_rate(hw, codec_stream);
Kuninori Morimotodebc71f2021-02-04 08:52:04 +0900606 soc_pcm_hw_update_format(hw, codec_stream);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200607 }
608
Samuel Holland5854a462020-03-04 23:11:42 -0600609 /* Verify both a valid CPU DAI and a valid CODEC DAI were found */
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900610 if (!hw->channels_min)
Samuel Holland5854a462020-03-04 23:11:42 -0600611 return -EINVAL;
612
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200613 /*
614 * chan min/max cannot be enforced if there are multiple CODEC DAIs
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800615 * connected to CPU DAI(s), use CPU DAI's directly and let
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200616 * channel allocation be fixed up later
617 */
618 if (rtd->num_codecs > 1) {
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +0900619 hw->channels_min = cpu_chan_min;
620 hw->channels_max = cpu_chan_max;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200621 }
622
Samuel Holland5854a462020-03-04 23:11:42 -0600623 return 0;
624}
625EXPORT_SYMBOL_GPL(snd_soc_runtime_calc_hw);
626
627static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
628{
629 struct snd_pcm_hardware *hw = &substream->runtime->hw;
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900630 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Samuel Holland5854a462020-03-04 23:11:42 -0600631 u64 formats = hw->formats;
632
633 /*
634 * At least one CPU and one CODEC should match. Otherwise, we should
635 * have bailed out on a higher level, since there would be no CPU or
636 * CODEC to support the transfer direction in that case.
637 */
638 snd_soc_runtime_calc_hw(rtd, hw, substream->stream);
639
640 if (formats)
641 hw->formats &= formats;
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200642}
643
Kuninori Morimotodd039072020-02-10 12:14:37 +0900644static int soc_pcm_components_open(struct snd_pcm_substream *substream)
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900645{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900646 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900647 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900648 int i, ret = 0;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900649
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900650 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto51aff912020-09-28 09:01:04 +0900651 ret = snd_soc_component_module_get_when_open(component, substream);
Kuninori Morimotobcae16312020-09-28 09:01:36 +0900652 if (ret < 0)
Kai Vehmanend2aaa8d2020-02-20 11:49:55 +0200653 break;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900654
Kuninori Morimotoae2f4842019-07-26 13:50:01 +0900655 ret = snd_soc_component_open(component, substream);
Kuninori Morimotobcae16312020-09-28 09:01:36 +0900656 if (ret < 0)
Kai Vehmanend2aaa8d2020-02-20 11:49:55 +0200657 break;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900658 }
Kuninori Morimotodd039072020-02-10 12:14:37 +0900659
Kai Vehmanend2aaa8d2020-02-20 11:49:55 +0200660 return ret;
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900661}
662
Kuninori Morimoto51aff912020-09-28 09:01:04 +0900663static int soc_pcm_components_close(struct snd_pcm_substream *substream,
664 int rollback)
Charles Keepax244e2932018-06-19 16:22:09 +0100665{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +0900666 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Charles Keepax244e2932018-06-19 16:22:09 +0100667 struct snd_soc_component *component;
Kuninori Morimoto33be10b2021-07-27 11:05:38 +0900668 int i, ret = 0;
Charles Keepax244e2932018-06-19 16:22:09 +0100669
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900670 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto33be10b2021-07-27 11:05:38 +0900671 int r = snd_soc_component_close(component, substream, rollback);
Kuninori Morimotoe82ebff2020-02-10 12:14:26 +0900672 if (r < 0)
673 ret = r; /* use last ret */
674
Kuninori Morimoto51aff912020-09-28 09:01:04 +0900675 snd_soc_component_module_put_when_close(component, substream, rollback);
Charles Keepax244e2932018-06-19 16:22:09 +0100676 }
677
Kuninori Morimoto3672beb2019-07-26 13:50:07 +0900678 return ret;
Charles Keepax244e2932018-06-19 16:22:09 +0100679}
680
Takashi Iwaib7898392021-12-07 11:37:42 -0600681static int soc_pcm_clean(struct snd_soc_pcm_runtime *rtd,
682 struct snd_pcm_substream *substream, int rollback)
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900683{
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900684 struct snd_soc_component *component;
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900685 struct snd_soc_dai *dai;
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900686 int i;
687
Takashi Iwaib7898392021-12-07 11:37:42 -0600688 snd_soc_dpcm_mutex_assert_held(rtd);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900689
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900690 if (!rollback)
691 snd_soc_runtime_deactivate(rtd, substream->stream);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900692
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900693 for_each_rtd_dais(rtd, i, dai)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900694 snd_soc_dai_shutdown(dai, substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900695
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900696 snd_soc_link_shutdown(substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900697
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900698 soc_pcm_components_close(substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900699
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900700 snd_soc_pcm_component_pm_runtime_put(rtd, substream, rollback);
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900701
702 for_each_rtd_components(rtd, i, component)
Kuninori Morimotob3dea622020-05-15 09:46:51 +0900703 if (!snd_soc_component_active(component))
Kuninori Morimoto62c86d12020-02-10 12:14:41 +0900704 pinctrl_pm_select_sleep_state(component->dev);
705
706 return 0;
707}
708
709/*
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900710 * Called by ALSA when a PCM substream is closed. Private data can be
711 * freed here. The cpu DAI, codec DAI, machine and components are also
712 * shutdown.
713 */
Takashi Iwaib7898392021-12-07 11:37:42 -0600714static int __soc_pcm_close(struct snd_soc_pcm_runtime *rtd,
715 struct snd_pcm_substream *substream)
716{
717 return soc_pcm_clean(rtd, substream, 0);
718}
719
720/* PCM close ops for non-DPCM streams */
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900721static int soc_pcm_close(struct snd_pcm_substream *substream)
722{
Takashi Iwaib7898392021-12-07 11:37:42 -0600723 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
724
725 snd_soc_dpcm_mutex_lock(rtd);
726 soc_pcm_clean(rtd, substream, 0);
727 snd_soc_dpcm_mutex_unlock(rtd);
728 return 0;
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900729}
730
Kuninori Morimotoc3932812021-03-09 10:08:02 +0900731static int soc_hw_sanity_check(struct snd_pcm_substream *substream)
732{
733 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
734 struct snd_pcm_hardware *hw = &substream->runtime->hw;
735 const char *name_cpu = soc_cpu_dai_name(rtd);
736 const char *name_codec = soc_codec_dai_name(rtd);
737 const char *err_msg;
738 struct device *dev = rtd->dev;
739
740 err_msg = "rates";
741 if (!hw->rates)
742 goto config_err;
743
744 err_msg = "formats";
745 if (!hw->formats)
746 goto config_err;
747
748 err_msg = "channels";
749 if (!hw->channels_min || !hw->channels_max ||
750 hw->channels_min > hw->channels_max)
751 goto config_err;
752
753 dev_dbg(dev, "ASoC: %s <-> %s info:\n", name_codec,
754 name_cpu);
755 dev_dbg(dev, "ASoC: rate mask 0x%x\n", hw->rates);
756 dev_dbg(dev, "ASoC: ch min %d max %d\n", hw->channels_min,
757 hw->channels_max);
758 dev_dbg(dev, "ASoC: rate min %d max %d\n", hw->rate_min,
759 hw->rate_max);
760
761 return 0;
762
763config_err:
764 dev_err(dev, "ASoC: %s <-> %s No matching %s\n",
765 name_codec, name_cpu, err_msg);
766 return -EINVAL;
767}
768
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900769/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100770 * Called by ALSA when a PCM substream is opened, the runtime->hw record is
771 * then initialized and any private data can be allocated. This also calls
Charles Keepaxef050be2018-04-24 16:39:02 +0100772 * startup for the cpu DAI, component, machine and codec DAI.
Liam Girdwoodddee6272011-06-09 14:45:53 +0100773 */
Takashi Iwaib7898392021-12-07 11:37:42 -0600774static int __soc_pcm_open(struct snd_soc_pcm_runtime *rtd,
775 struct snd_pcm_substream *substream)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100776{
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000777 struct snd_soc_component *component;
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900778 struct snd_soc_dai *dai;
Charles Keepax244e2932018-06-19 16:22:09 +0100779 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100780
Takashi Iwaib7898392021-12-07 11:37:42 -0600781 snd_soc_dpcm_mutex_assert_held(rtd);
782
Kuninori Morimoto76c39e82020-01-10 11:36:13 +0900783 for_each_rtd_components(rtd, i, component)
784 pinctrl_pm_select_default_state(component->dev);
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000785
Kuninori Morimoto939a5cf2020-09-28 09:01:17 +0900786 ret = snd_soc_pcm_component_pm_runtime_get(rtd, substream);
787 if (ret < 0)
Takashi Iwaib7898392021-12-07 11:37:42 -0600788 goto err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100789
Kuninori Morimoto5d9fa032020-02-10 12:14:45 +0900790 ret = soc_pcm_components_open(substream);
791 if (ret < 0)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900792 goto err;
Kuninori Morimoto5d9fa032020-02-10 12:14:45 +0900793
Kuninori Morimoto7cf3c5b2020-05-25 09:57:31 +0900794 ret = snd_soc_link_startup(substream);
Kuninori Morimotoa5e6c102020-05-25 09:57:19 +0900795 if (ret < 0)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900796 goto err;
Kuninori Morimoto5d9fa032020-02-10 12:14:45 +0900797
Liam Girdwoodddee6272011-06-09 14:45:53 +0100798 /* startup the audio subsystem */
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900799 for_each_rtd_dais(rtd, i, dai) {
800 ret = snd_soc_dai_startup(dai, substream);
Kuninori Morimotoce820142020-09-28 09:01:29 +0900801 if (ret < 0)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900802 goto err;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200803
804 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900805 dai->tx_mask = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200806 else
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900807 dai->rx_mask = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100808 }
809
Liam Girdwood01d75842012-04-25 12:12:49 +0100810 /* Dynamic PCM DAI links compat checks use dynamic capabilities */
811 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm)
812 goto dynamic;
813
Liam Girdwoodddee6272011-06-09 14:45:53 +0100814 /* Check that the codec and cpu DAIs are compatible */
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200815 soc_pcm_init_runtime_hw(substream);
816
Kuninori Morimoto68cbc552021-03-09 10:07:57 +0900817 soc_pcm_update_symmetry(substream);
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100818
Kuninori Morimotoc3932812021-03-09 10:08:02 +0900819 ret = soc_hw_sanity_check(substream);
820 if (ret < 0)
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900821 goto err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100822
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200823 soc_pcm_apply_msb(substream);
Mark Brown58ba9b22012-01-16 18:38:51 +0000824
Liam Girdwoodddee6272011-06-09 14:45:53 +0100825 /* Symmetry only applies if we've already got an active stream. */
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900826 for_each_rtd_dais(rtd, i, dai) {
Kuninori Morimotof8fc9ec2021-03-09 10:07:42 +0900827 ret = soc_pcm_apply_symmetry(substream, dai);
828 if (ret != 0)
829 goto err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100830 }
Liam Girdwood01d75842012-04-25 12:12:49 +0100831dynamic:
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100832 snd_soc_runtime_activate(rtd, substream->stream);
Kuninori Morimoto8e7875a2020-10-01 14:07:41 +0900833 ret = 0;
Kuninori Morimoto140a4532020-09-28 09:01:24 +0900834err:
Kuninori Morimotoe4b044f2021-03-15 09:57:37 +0900835 if (ret < 0) {
Takashi Iwaib7898392021-12-07 11:37:42 -0600836 soc_pcm_clean(rtd, substream, 1);
Kuninori Morimotoe4b044f2021-03-15 09:57:37 +0900837 dev_err(rtd->dev, "%s() failed (%d)", __func__, ret);
838 }
Mark Brownd6652ef2011-12-03 20:14:31 +0000839
Liam Girdwoodddee6272011-06-09 14:45:53 +0100840 return ret;
841}
842
Takashi Iwaib7898392021-12-07 11:37:42 -0600843/* PCM open ops for non-DPCM streams */
844static int soc_pcm_open(struct snd_pcm_substream *substream)
845{
846 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
847 int ret;
848
849 snd_soc_dpcm_mutex_lock(rtd);
850 ret = __soc_pcm_open(rtd, substream);
851 snd_soc_dpcm_mutex_unlock(rtd);
852 return ret;
853}
854
Curtis Malainey4bf2e382019-12-03 09:30:07 -0800855static void codec2codec_close_delayed_work(struct snd_soc_pcm_runtime *rtd)
Jerome Bruneta3420312019-07-25 18:59:47 +0200856{
857 /*
858 * Currently nothing to do for c2c links
859 * Since c2c links are internal nodes in the DAPM graph and
860 * don't interface with the outside world or application layer
861 * we don't have to do any special handling on close.
862 */
863}
864
Liam Girdwoodddee6272011-06-09 14:45:53 +0100865/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100866 * Called by ALSA when the PCM substream is prepared, can set format, sample
867 * rate, etc. This function is non atomic and can be called multiple times,
868 * it can refer to the runtime info.
869 */
Takashi Iwaib7898392021-12-07 11:37:42 -0600870static int __soc_pcm_prepare(struct snd_soc_pcm_runtime *rtd,
871 struct snd_pcm_substream *substream)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100872{
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900873 struct snd_soc_dai *dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200874 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100875
Takashi Iwaib7898392021-12-07 11:37:42 -0600876 snd_soc_dpcm_mutex_assert_held(rtd);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100877
Kuninori Morimoto7cf3c5b2020-05-25 09:57:31 +0900878 ret = snd_soc_link_prepare(substream);
Kuninori Morimotoa5e6c102020-05-25 09:57:19 +0900879 if (ret < 0)
Kuninori Morimoto44c1a752020-01-22 09:44:44 +0900880 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100881
Kuninori Morimoto4f395142020-06-04 17:06:58 +0900882 ret = snd_soc_pcm_component_prepare(substream);
883 if (ret < 0)
884 goto out;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000885
Kuninori Morimotod108c7f2020-04-24 08:14:53 +0900886 ret = snd_soc_pcm_dai_prepare(substream);
Kuninori Morimoto62462e02021-03-15 09:58:37 +0900887 if (ret < 0)
Kuninori Morimotod108c7f2020-04-24 08:14:53 +0900888 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100889
890 /* cancel any delayed stream shutdown that is pending */
891 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600892 rtd->pop_wait) {
893 rtd->pop_wait = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100894 cancel_delayed_work(&rtd->delayed_work);
895 }
896
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000897 snd_soc_dapm_stream_event(rtd, substream->stream,
898 SND_SOC_DAPM_STREAM_START);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100899
Kuninori Morimotoc840f762020-03-16 15:37:14 +0900900 for_each_rtd_dais(rtd, i, dai)
901 snd_soc_dai_digital_mute(dai, 0, substream->stream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100902
903out:
Kuninori Morimotodab7eeb2021-03-15 09:57:48 +0900904 if (ret < 0)
905 dev_err(rtd->dev, "ASoC: %s() failed (%d)\n", __func__, ret);
906
Liam Girdwoodddee6272011-06-09 14:45:53 +0100907 return ret;
908}
909
Takashi Iwaib7898392021-12-07 11:37:42 -0600910/* PCM prepare ops for non-DPCM streams */
911static int soc_pcm_prepare(struct snd_pcm_substream *substream)
912{
913 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
914 int ret;
915
916 snd_soc_dpcm_mutex_lock(rtd);
917 ret = __soc_pcm_prepare(rtd, substream);
918 snd_soc_dpcm_mutex_unlock(rtd);
919 return ret;
920}
921
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200922static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params,
923 unsigned int mask)
924{
925 struct snd_interval *interval;
926 int channels = hweight_long(mask);
927
928 interval = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
929 interval->min = channels;
930 interval->max = channels;
931}
932
Takashi Iwaib7898392021-12-07 11:37:42 -0600933static int soc_pcm_hw_clean(struct snd_soc_pcm_runtime *rtd,
934 struct snd_pcm_substream *substream, int rollback)
Kuninori Morimotoab494362020-09-29 13:31:19 +0900935{
Kuninori Morimotoab494362020-09-29 13:31:19 +0900936 struct snd_soc_dai *dai;
937 int i;
938
Takashi Iwaib7898392021-12-07 11:37:42 -0600939 snd_soc_dpcm_mutex_assert_held(rtd);
Kuninori Morimotoab494362020-09-29 13:31:19 +0900940
941 /* clear the corresponding DAIs parameters when going to be inactive */
942 for_each_rtd_dais(rtd, i, dai) {
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +0900943 if (snd_soc_dai_active(dai) == 1)
944 soc_pcm_set_dai_params(dai, NULL);
Kuninori Morimotoab494362020-09-29 13:31:19 +0900945
Kuninori Morimoto86e4aef2021-10-18 11:05:05 +0900946 if (snd_soc_dai_stream_active(dai, substream->stream) == 1)
Kuninori Morimotoab494362020-09-29 13:31:19 +0900947 snd_soc_dai_digital_mute(dai, 1, substream->stream);
948 }
949
Ranjani Sridharana27b4212020-11-17 13:50:01 -0800950 /* run the stream event */
951 snd_soc_dapm_stream_stop(rtd, substream->stream);
952
Kuninori Morimotoab494362020-09-29 13:31:19 +0900953 /* free any machine hw params */
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900954 snd_soc_link_hw_free(substream, rollback);
Kuninori Morimotoab494362020-09-29 13:31:19 +0900955
956 /* free any component resources */
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900957 snd_soc_pcm_component_hw_free(substream, rollback);
Kuninori Morimotoab494362020-09-29 13:31:19 +0900958
959 /* now free hw params for the DAIs */
Kuninori Morimoto121966d2021-10-18 11:04:52 +0900960 for_each_rtd_dais(rtd, i, dai)
961 if (snd_soc_dai_stream_valid(dai, substream->stream))
962 snd_soc_dai_hw_free(dai, substream, rollback);
Kuninori Morimotoab494362020-09-29 13:31:19 +0900963
Kuninori Morimotoab494362020-09-29 13:31:19 +0900964 return 0;
965}
966
967/*
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900968 * Frees resources allocated by hw_params, can be called multiple times
969 */
Takashi Iwaib7898392021-12-07 11:37:42 -0600970static int __soc_pcm_hw_free(struct snd_soc_pcm_runtime *rtd,
971 struct snd_pcm_substream *substream)
972{
973 return soc_pcm_hw_clean(rtd, substream, 0);
974}
975
976/* hw_free PCM ops for non-DPCM streams */
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900977static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
978{
Takashi Iwaib7898392021-12-07 11:37:42 -0600979 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
980 int ret;
981
982 snd_soc_dpcm_mutex_lock(rtd);
983 ret = __soc_pcm_hw_free(rtd, substream);
984 snd_soc_dpcm_mutex_unlock(rtd);
985 return ret;
Kuninori Morimoto4662c592020-09-29 13:32:01 +0900986}
987
988/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100989 * Called by ALSA when the hardware params are set by application. This
990 * function can also be called multiple times and can allocate buffers
991 * (using snd_pcm_lib_* ). It's non-atomic.
992 */
Takashi Iwaib7898392021-12-07 11:37:42 -0600993static int __soc_pcm_hw_params(struct snd_soc_pcm_runtime *rtd,
994 struct snd_pcm_substream *substream,
995 struct snd_pcm_hw_params *params)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100996{
Shreyas NC19bdcc7a2020-02-25 21:39:13 +0800997 struct snd_soc_dai *cpu_dai;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000998 struct snd_soc_dai *codec_dai;
Charles Keepax244e2932018-06-19 16:22:09 +0100999 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001000
Takashi Iwaib7898392021-12-07 11:37:42 -06001001 snd_soc_dpcm_mutex_assert_held(rtd);
Shengjiu Wang5cca5952019-11-12 18:46:42 +08001002
1003 ret = soc_pcm_params_symmetry(substream, params);
1004 if (ret)
1005 goto out;
1006
Kuninori Morimoto7cf3c5b2020-05-25 09:57:31 +09001007 ret = snd_soc_link_hw_params(substream, params);
Kuninori Morimotoa5e6c102020-05-25 09:57:19 +09001008 if (ret < 0)
Kuninori Morimotode9ad992020-01-22 09:44:48 +09001009 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001010
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001011 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001012 struct snd_pcm_hw_params codec_params;
1013
Ricard Wanderlofcde79032015-08-24 14:16:51 +02001014 /*
1015 * Skip CODECs which don't support the current stream type,
1016 * the idea being that if a CODEC is not used for the currently
1017 * set up transfer direction, it should not need to be
1018 * configured, especially since the configuration used might
1019 * not even be supported by that CODEC. There may be cases
1020 * however where a CODEC needs to be set up although it is
1021 * actually not being used for the transfer, e.g. if a
1022 * capture-only CODEC is acting as an LRCLK and/or BCLK master
1023 * for the DAI link including a playback-only CODEC.
1024 * If this becomes necessary, we will have to augment the
1025 * machine driver setup with information on how to act, so
1026 * we can do the right thing here.
1027 */
1028 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
1029 continue;
1030
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001031 /* copy params for each codec */
1032 codec_params = *params;
1033
1034 /* fixup params based on TDM slot masks */
Rander Wang570f18b2019-03-08 16:38:57 +08001035 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
1036 codec_dai->tx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001037 soc_pcm_codec_params_fixup(&codec_params,
1038 codec_dai->tx_mask);
Rander Wang570f18b2019-03-08 16:38:57 +08001039
1040 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
1041 codec_dai->rx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001042 soc_pcm_codec_params_fixup(&codec_params,
1043 codec_dai->rx_mask);
1044
Kuninori Morimotoaa6166c2019-07-22 10:33:04 +09001045 ret = snd_soc_dai_hw_params(codec_dai, substream,
1046 &codec_params);
Benoit Cousson93e69582014-07-08 23:19:38 +02001047 if(ret < 0)
Kuninori Morimoto4662c592020-09-29 13:32:01 +09001048 goto out;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001049
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +09001050 soc_pcm_set_dai_params(codec_dai, &codec_params);
Charles Keepax078a85f2019-01-31 13:30:18 +00001051 snd_soc_dapm_update_dai(substream, &codec_params, codec_dai);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001052 }
1053
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001054 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001055 /*
1056 * Skip CPUs which don't support the current stream
1057 * type. See soc_pcm_init_runtime_hw() for more details
1058 */
1059 if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream))
1060 continue;
1061
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001062 ret = snd_soc_dai_hw_params(cpu_dai, substream, params);
1063 if (ret < 0)
Kuninori Morimoto4662c592020-09-29 13:32:01 +09001064 goto out;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001065
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001066 /* store the parameters for each DAI */
Kuninori Morimoto2805b8b2020-12-11 14:55:27 +09001067 soc_pcm_set_dai_params(cpu_dai, params);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001068 snd_soc_dapm_update_dai(substream, params, cpu_dai);
1069 }
Kuninori Morimotoca58221d2019-05-13 16:07:43 +09001070
Kuninori Morimoto3a36a642020-09-29 13:31:41 +09001071 ret = snd_soc_pcm_component_hw_params(substream, params);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001072out:
Kuninori Morimotocb11f792021-03-15 09:57:42 +09001073 if (ret < 0) {
Takashi Iwaib7898392021-12-07 11:37:42 -06001074 soc_pcm_hw_clean(rtd, substream, 1);
Kuninori Morimotocb11f792021-03-15 09:57:42 +09001075 dev_err(rtd->dev, "ASoC: %s() failed (%d)\n", __func__, ret);
1076 }
Kuninori Morimotob8135862017-10-11 01:37:23 +00001077
Liam Girdwoodddee6272011-06-09 14:45:53 +01001078 return ret;
1079}
1080
Takashi Iwaib7898392021-12-07 11:37:42 -06001081/* hw_params PCM ops for non-DPCM streams */
1082static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
1083 struct snd_pcm_hw_params *params)
1084{
1085 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
1086 int ret;
1087
1088 snd_soc_dpcm_mutex_lock(rtd);
1089 ret = __soc_pcm_hw_params(rtd, substream, params);
1090 snd_soc_dpcm_mutex_unlock(rtd);
1091 return ret;
1092}
1093
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001094static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1095{
Vijendar Mukunda59dd33f2021-07-16 18:00:12 +05301096 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001097 int ret = -EINVAL, _ret = 0;
1098 int rollback = 0;
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001099
1100 switch (cmd) {
1101 case SNDRV_PCM_TRIGGER_START:
1102 case SNDRV_PCM_TRIGGER_RESUME:
1103 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001104 ret = snd_soc_link_trigger(substream, cmd, 0);
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001105 if (ret < 0)
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001106 goto start_err;
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001107
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001108 ret = snd_soc_pcm_component_trigger(substream, cmd, 0);
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001109 if (ret < 0)
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001110 goto start_err;
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001111
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001112 ret = snd_soc_pcm_dai_trigger(substream, cmd, 0);
1113start_err:
1114 if (ret < 0)
1115 rollback = 1;
1116 }
1117
1118 if (rollback) {
1119 _ret = ret;
1120 switch (cmd) {
1121 case SNDRV_PCM_TRIGGER_START:
1122 cmd = SNDRV_PCM_TRIGGER_STOP;
1123 break;
1124 case SNDRV_PCM_TRIGGER_RESUME:
1125 cmd = SNDRV_PCM_TRIGGER_SUSPEND;
1126 break;
1127 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1128 cmd = SNDRV_PCM_TRIGGER_PAUSE_PUSH;
1129 break;
1130 }
1131 }
1132
1133 switch (cmd) {
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001134 case SNDRV_PCM_TRIGGER_STOP:
1135 case SNDRV_PCM_TRIGGER_SUSPEND:
1136 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
Vijendar Mukunda59dd33f2021-07-16 18:00:12 +05301137 if (rtd->dai_link->stop_dma_first) {
1138 ret = snd_soc_pcm_component_trigger(substream, cmd, rollback);
1139 if (ret < 0)
1140 break;
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001141
Vijendar Mukunda59dd33f2021-07-16 18:00:12 +05301142 ret = snd_soc_pcm_dai_trigger(substream, cmd, rollback);
1143 if (ret < 0)
1144 break;
1145 } else {
1146 ret = snd_soc_pcm_dai_trigger(substream, cmd, rollback);
1147 if (ret < 0)
1148 break;
Kuninori Morimoto836367b2020-06-04 17:08:12 +09001149
Vijendar Mukunda59dd33f2021-07-16 18:00:12 +05301150 ret = snd_soc_pcm_component_trigger(substream, cmd, rollback);
1151 if (ret < 0)
1152 break;
1153 }
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001154 ret = snd_soc_link_trigger(substream, cmd, rollback);
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001155 break;
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001156 }
1157
Kuninori Morimoto6374f492020-12-01 08:51:33 +09001158 if (_ret)
1159 ret = _ret;
1160
Peter Ujfalusi4378f1f2019-09-27 10:16:46 +03001161 return ret;
1162}
1163
Liam Girdwoodddee6272011-06-09 14:45:53 +01001164/*
1165 * soc level wrapper for pointer callback
Charles Keepaxef050be2018-04-24 16:39:02 +01001166 * If cpu_dai, codec_dai, component driver has the delay callback, then
Kuninori Morimotodd894f42021-11-16 16:45:34 +09001167 * the runtime->delay will be updated via snd_soc_pcm_component/dai_delay().
Liam Girdwoodddee6272011-06-09 14:45:53 +01001168 */
1169static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
1170{
Liam Girdwoodddee6272011-06-09 14:45:53 +01001171 struct snd_pcm_runtime *runtime = substream->runtime;
1172 snd_pcm_uframes_t offset = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001173 snd_pcm_sframes_t codec_delay = 0;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001174 snd_pcm_sframes_t cpu_delay = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001175
Kuninori Morimoto0035e252019-07-26 13:51:47 +09001176 offset = snd_soc_pcm_component_pointer(substream);
Kuninori Morimotob8135862017-10-11 01:37:23 +00001177
Kuninori Morimoto403f8302021-11-16 16:45:18 +09001178 /* should be called *after* snd_soc_pcm_component_pointer() */
Kuninori Morimoto8544f082021-11-16 16:45:12 +09001179 snd_soc_pcm_dai_delay(substream, &cpu_delay, &codec_delay);
Kuninori Morimoto403f8302021-11-16 16:45:18 +09001180 snd_soc_pcm_component_delay(substream, &cpu_delay, &codec_delay);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001181
Kuninori Morimotodd894f42021-11-16 16:45:34 +09001182 runtime->delay = cpu_delay + codec_delay;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001183
1184 return offset;
1185}
1186
Liam Girdwood01d75842012-04-25 12:12:49 +01001187/* connect a FE and BE */
1188static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
1189 struct snd_soc_pcm_runtime *be, int stream)
1190{
Pierre-Louis Bossartbbf7d3b2021-12-07 11:37:41 -06001191 struct snd_pcm_substream *fe_substream;
1192 struct snd_pcm_substream *be_substream;
Liam Girdwood01d75842012-04-25 12:12:49 +01001193 struct snd_soc_dpcm *dpcm;
Takashi Iwaib7898392021-12-07 11:37:42 -06001194
1195 snd_soc_dpcm_mutex_assert_held(fe);
Liam Girdwood01d75842012-04-25 12:12:49 +01001196
1197 /* only add new dpcms */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001198 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001199 if (dpcm->be == be && dpcm->fe == fe)
1200 return 0;
1201 }
1202
Pierre-Louis Bossartbbf7d3b2021-12-07 11:37:41 -06001203 fe_substream = snd_soc_dpcm_get_substream(fe, stream);
1204 be_substream = snd_soc_dpcm_get_substream(be, stream);
1205
1206 if (!fe_substream->pcm->nonatomic && be_substream->pcm->nonatomic) {
1207 dev_err(be->dev, "%s: FE is atomic but BE is nonatomic, invalid configuration\n",
1208 __func__);
1209 return -EINVAL;
1210 }
1211 if (fe_substream->pcm->nonatomic && !be_substream->pcm->nonatomic) {
1212 dev_warn(be->dev, "%s: FE is nonatomic but BE is not, forcing BE as nonatomic\n",
1213 __func__);
1214 be_substream->pcm->nonatomic = 1;
1215 }
1216
Pierre-Louis Bossartd8a9c6e2021-12-07 11:37:40 -06001217 dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_ATOMIC);
Liam Girdwood01d75842012-04-25 12:12:49 +01001218 if (!dpcm)
1219 return -ENOMEM;
1220
1221 dpcm->be = be;
1222 dpcm->fe = fe;
1223 be->dpcm[stream].runtime = fe->dpcm[stream].runtime;
1224 dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW;
Takashi Iwaib7898392021-12-07 11:37:42 -06001225 snd_soc_dpcm_stream_lock_irq(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001226 list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients);
1227 list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients);
Takashi Iwaib7898392021-12-07 11:37:42 -06001228 snd_soc_dpcm_stream_unlock_irq(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001229
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001230 dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001231 stream ? "capture" : "playback", fe->dai_link->name,
1232 stream ? "<-" : "->", be->dai_link->name);
1233
Kuninori Morimoto154dae82020-02-19 15:57:06 +09001234 dpcm_create_debugfs_state(dpcm, stream);
1235
Liam Girdwood01d75842012-04-25 12:12:49 +01001236 return 1;
1237}
1238
1239/* reparent a BE onto another FE */
1240static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
1241 struct snd_soc_pcm_runtime *be, int stream)
1242{
1243 struct snd_soc_dpcm *dpcm;
1244 struct snd_pcm_substream *fe_substream, *be_substream;
1245
1246 /* reparent if BE is connected to other FEs */
1247 if (!be->dpcm[stream].users)
1248 return;
1249
1250 be_substream = snd_soc_dpcm_get_substream(be, stream);
1251
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00001252 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001253 if (dpcm->fe == fe)
1254 continue;
1255
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001256 dev_dbg(fe->dev, "reparent %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001257 stream ? "capture" : "playback",
1258 dpcm->fe->dai_link->name,
1259 stream ? "<-" : "->", dpcm->be->dai_link->name);
1260
1261 fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, stream);
1262 be_substream->runtime = fe_substream->runtime;
1263 break;
1264 }
1265}
1266
1267/* disconnect a BE and FE */
Liam Girdwood23607022014-01-17 17:03:55 +00001268void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001269{
1270 struct snd_soc_dpcm *dpcm, *d;
1271
Takashi Iwaib7898392021-12-07 11:37:42 -06001272 snd_soc_dpcm_mutex_assert_held(fe);
1273
1274 snd_soc_dpcm_stream_lock_irq(fe, stream);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001275 for_each_dpcm_be_safe(fe, stream, dpcm, d) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001276 dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001277 stream ? "capture" : "playback",
1278 dpcm->be->dai_link->name);
1279
1280 if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE)
1281 continue;
1282
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001283 dev_dbg(fe->dev, "freed DSP %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001284 stream ? "capture" : "playback", fe->dai_link->name,
1285 stream ? "<-" : "->", dpcm->be->dai_link->name);
1286
1287 /* BEs still alive need new FE */
1288 dpcm_be_reparent(fe, dpcm->be, stream);
1289
Kuninori Morimoto154dae82020-02-19 15:57:06 +09001290 dpcm_remove_debugfs_state(dpcm);
1291
Liam Girdwood01d75842012-04-25 12:12:49 +01001292 list_del(&dpcm->list_be);
1293 list_del(&dpcm->list_fe);
1294 kfree(dpcm);
1295 }
Takashi Iwaib7898392021-12-07 11:37:42 -06001296 snd_soc_dpcm_stream_unlock_irq(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001297}
1298
1299/* get BE for DAI widget and stream */
1300static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
1301 struct snd_soc_dapm_widget *widget, int stream)
1302{
1303 struct snd_soc_pcm_runtime *be;
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001304 struct snd_soc_dapm_widget *w;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001305 struct snd_soc_dai *dai;
Mengdong Lin1a497982015-11-18 02:34:11 -05001306 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01001307
Liam Girdwood3c146462018-03-14 20:43:51 +00001308 dev_dbg(card->dev, "ASoC: find BE for widget %s\n", widget->name);
1309
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001310 for_each_card_rtds(card, be) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001311
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001312 if (!be->dai_link->no_pcm)
1313 continue;
Liam Girdwood35ea0652012-06-05 19:26:59 +01001314
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001315 for_each_rtd_dais(be, i, dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001316 w = snd_soc_dai_get_widget(dai, stream);
Liam Girdwood3c146462018-03-14 20:43:51 +00001317
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001318 dev_dbg(card->dev, "ASoC: try BE : %s\n",
1319 w ? w->name : "(not set)");
Kuninori Morimoto93597fa2020-02-17 17:27:43 +09001320
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001321 if (w == widget)
1322 return be;
1323 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001324 }
1325
Jerome Brunet9d6ee362020-02-19 12:50:48 +01001326 /* Widget provided is not a BE */
Liam Girdwood01d75842012-04-25 12:12:49 +01001327 return NULL;
1328}
1329
Liam Girdwood01d75842012-04-25 12:12:49 +01001330static int widget_in_list(struct snd_soc_dapm_widget_list *list,
1331 struct snd_soc_dapm_widget *widget)
1332{
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001333 struct snd_soc_dapm_widget *w;
Liam Girdwood01d75842012-04-25 12:12:49 +01001334 int i;
1335
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001336 for_each_dapm_widgets(list, i, w)
1337 if (widget == w)
Liam Girdwood01d75842012-04-25 12:12:49 +01001338 return 1;
Liam Girdwood01d75842012-04-25 12:12:49 +01001339
1340 return 0;
1341}
1342
Ranjani Sridharand1a7af02021-09-27 15:05:10 +03001343bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget, enum snd_soc_dapm_direction dir)
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001344{
1345 struct snd_soc_card *card = widget->dapm->card;
1346 struct snd_soc_pcm_runtime *rtd;
Kuninori Morimotoc2cd8212020-02-17 17:27:48 +09001347 int stream;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001348
Kuninori Morimotoc2cd8212020-02-17 17:27:48 +09001349 /* adjust dir to stream */
1350 if (dir == SND_SOC_DAPM_DIR_OUT)
1351 stream = SNDRV_PCM_STREAM_PLAYBACK;
1352 else
1353 stream = SNDRV_PCM_STREAM_CAPTURE;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001354
Kuninori Morimoto027a4832020-02-17 17:27:53 +09001355 rtd = dpcm_get_be(card, widget, stream);
1356 if (rtd)
1357 return true;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001358
1359 return false;
1360}
Ranjani Sridharand1a7af02021-09-27 15:05:10 +03001361EXPORT_SYMBOL_GPL(dpcm_end_walk_at_be);
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001362
Liam Girdwood23607022014-01-17 17:03:55 +00001363int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001364 int stream, struct snd_soc_dapm_widget_list **list)
Liam Girdwood01d75842012-04-25 12:12:49 +01001365{
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09001366 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
Liam Girdwood01d75842012-04-25 12:12:49 +01001367 int paths;
1368
Bard Liao6e1276a2020-02-25 21:39:16 +08001369 if (fe->num_cpus > 1) {
1370 dev_err(fe->dev,
1371 "%s doesn't support Multi CPU yet\n", __func__);
1372 return -EINVAL;
1373 }
1374
Liam Girdwood01d75842012-04-25 12:12:49 +01001375 /* get number of valid DAI paths and their widgets */
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001376 paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list,
Sameer Pujaraa293772020-11-02 20:40:09 +05301377 fe->card->component_chaining ?
1378 NULL : dpcm_end_walk_at_be);
Liam Girdwood01d75842012-04-25 12:12:49 +01001379
Kuninori Morimotod479f002021-03-15 09:57:52 +09001380 if (paths > 0)
1381 dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths,
Liam Girdwood01d75842012-04-25 12:12:49 +01001382 stream ? "capture" : "playback");
Kuninori Morimotod479f002021-03-15 09:57:52 +09001383 else if (paths == 0)
1384 dev_dbg(fe->dev, "ASoC: %s no valid %s path\n", fe->dai_link->name,
1385 stream ? "capture" : "playback");
Liam Girdwood01d75842012-04-25 12:12:49 +01001386
Liam Girdwood01d75842012-04-25 12:12:49 +01001387 return paths;
1388}
1389
Kuninori Morimoto52645e332020-02-19 15:56:52 +09001390void dpcm_path_put(struct snd_soc_dapm_widget_list **list)
1391{
1392 snd_soc_dapm_dai_free_widgets(list);
1393}
1394
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001395static bool dpcm_be_is_active(struct snd_soc_dpcm *dpcm, int stream,
1396 struct snd_soc_dapm_widget_list *list)
Liam Girdwood01d75842012-04-25 12:12:49 +01001397{
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001398 struct snd_soc_dai *dai;
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001399 unsigned int i;
1400
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001401 /* is there a valid DAI widget for this BE */
1402 for_each_rtd_dais(dpcm->be, i, dai) {
Kuninori Morimoto7931df92021-07-27 11:05:47 +09001403 struct snd_soc_dapm_widget *widget = snd_soc_dai_get_widget(dai, stream);
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001404
1405 /*
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001406 * The BE is pruned only if none of the dai
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001407 * widgets are in the active list.
1408 */
1409 if (widget && widget_in_list(list, widget))
1410 return true;
1411 }
1412
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001413 return false;
1414}
1415
1416static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
1417 struct snd_soc_dapm_widget_list **list_)
1418{
1419 struct snd_soc_dpcm *dpcm;
Liam Girdwood01d75842012-04-25 12:12:49 +01001420 int prune = 0;
1421
1422 /* Destroy any old FE <--> BE connections */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001423 for_each_dpcm_be(fe, stream, dpcm) {
Guennadi Liakhovetski8cce6562020-03-12 10:52:13 +01001424 if (dpcm_be_is_active(dpcm, stream, *list_))
Kuninori Morimotobed646d2019-10-15 12:59:38 +09001425 continue;
Liam Girdwood01d75842012-04-25 12:12:49 +01001426
Liam Girdwood103d84a2012-11-19 14:39:15 +00001427 dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001428 stream ? "capture" : "playback",
1429 dpcm->be->dai_link->name, fe->dai_link->name);
1430 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
Kuninori Morimotoa7e204442020-12-11 14:55:22 +09001431 dpcm_set_be_update_state(dpcm->be, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001432 prune++;
1433 }
1434
Liam Girdwood103d84a2012-11-19 14:39:15 +00001435 dev_dbg(fe->dev, "ASoC: found %d old BE paths for pruning\n", prune);
Liam Girdwood01d75842012-04-25 12:12:49 +01001436 return prune;
1437}
1438
1439static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
1440 struct snd_soc_dapm_widget_list **list_)
1441{
1442 struct snd_soc_card *card = fe->card;
1443 struct snd_soc_dapm_widget_list *list = *list_;
1444 struct snd_soc_pcm_runtime *be;
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001445 struct snd_soc_dapm_widget *widget;
Liam Girdwood01d75842012-04-25 12:12:49 +01001446 int i, new = 0, err;
1447
1448 /* Create any new FE <--> BE connections */
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001449 for_each_dapm_widgets(list, i, widget) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001450
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001451 switch (widget->id) {
Mark Brown46162742013-06-05 19:36:11 +01001452 case snd_soc_dapm_dai_in:
Koro Chenc5b85402015-07-06 10:02:10 +08001453 if (stream != SNDRV_PCM_STREAM_PLAYBACK)
1454 continue;
1455 break;
Mark Brown46162742013-06-05 19:36:11 +01001456 case snd_soc_dapm_dai_out:
Koro Chenc5b85402015-07-06 10:02:10 +08001457 if (stream != SNDRV_PCM_STREAM_CAPTURE)
1458 continue;
Mark Brown46162742013-06-05 19:36:11 +01001459 break;
1460 default:
Liam Girdwood01d75842012-04-25 12:12:49 +01001461 continue;
Mark Brown46162742013-06-05 19:36:11 +01001462 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001463
1464 /* is there a valid BE rtd for this widget */
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001465 be = dpcm_get_be(card, widget, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001466 if (!be) {
Shengjiu Wangb6eabd22021-02-08 16:12:45 +08001467 dev_dbg(fe->dev, "ASoC: no BE found for %s\n",
1468 widget->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001469 continue;
1470 }
1471
Liam Girdwood01d75842012-04-25 12:12:49 +01001472 /* don't connect if FE is not running */
Liam Girdwood23607022014-01-17 17:03:55 +00001473 if (!fe->dpcm[stream].runtime && !fe->fe_compr)
Liam Girdwood01d75842012-04-25 12:12:49 +01001474 continue;
1475
Pierre-Louis Bossart9609cfc2021-10-04 16:21:41 -05001476 /*
1477 * Filter for systems with 'component_chaining' enabled.
1478 * This helps to avoid unnecessary re-configuration of an
1479 * already active BE on such systems.
1480 */
1481 if (fe->card->component_chaining &&
1482 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
Sameer Pujar0c25db32021-09-13 22:12:09 +05301483 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
1484 continue;
1485
Liam Girdwood01d75842012-04-25 12:12:49 +01001486 /* newly connected FE and BE */
1487 err = dpcm_be_connect(fe, be, stream);
1488 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001489 dev_err(fe->dev, "ASoC: can't connect %s\n",
Kuninori Morimoto09e88f82020-02-10 12:14:22 +09001490 widget->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001491 break;
1492 } else if (err == 0) /* already connected */
1493 continue;
1494
1495 /* new */
Kuninori Morimotoa7e204442020-12-11 14:55:22 +09001496 dpcm_set_be_update_state(be, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001497 new++;
1498 }
1499
Liam Girdwood103d84a2012-11-19 14:39:15 +00001500 dev_dbg(fe->dev, "ASoC: found %d new BE paths\n", new);
Liam Girdwood01d75842012-04-25 12:12:49 +01001501 return new;
1502}
1503
1504/*
1505 * Find the corresponding BE DAIs that source or sink audio to this
1506 * FE substream.
1507 */
Liam Girdwood23607022014-01-17 17:03:55 +00001508int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
Liam Girdwood01d75842012-04-25 12:12:49 +01001509 int stream, struct snd_soc_dapm_widget_list **list, int new)
1510{
1511 if (new)
1512 return dpcm_add_paths(fe, stream, list);
1513 else
1514 return dpcm_prune_paths(fe, stream, list);
1515}
1516
Liam Girdwood23607022014-01-17 17:03:55 +00001517void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001518{
1519 struct snd_soc_dpcm *dpcm;
1520
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001521 for_each_dpcm_be(fe, stream, dpcm)
Kuninori Morimotoa7e204442020-12-11 14:55:22 +09001522 dpcm_set_be_update_state(dpcm->be, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001523}
1524
Kuninori Morimoto531590b2021-03-09 10:08:17 +09001525void dpcm_be_dai_stop(struct snd_soc_pcm_runtime *fe, int stream,
1526 int do_hw_free, struct snd_soc_dpcm *last)
Liam Girdwood01d75842012-04-25 12:12:49 +01001527{
1528 struct snd_soc_dpcm *dpcm;
1529
1530 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001531 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001532 struct snd_soc_pcm_runtime *be = dpcm->be;
1533 struct snd_pcm_substream *be_substream =
1534 snd_soc_dpcm_get_substream(be, stream);
1535
Kuninori Morimoto531590b2021-03-09 10:08:17 +09001536 if (dpcm == last)
1537 return;
1538
1539 /* is this op for this BE ? */
1540 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1541 continue;
1542
Kuninori Morimoto1db19c12021-03-09 10:08:08 +09001543 if (be->dpcm[stream].users == 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001544 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001545 stream ? "capture" : "playback",
1546 be->dpcm[stream].state);
Kuninori Morimoto1db19c12021-03-09 10:08:08 +09001547 continue;
1548 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001549
1550 if (--be->dpcm[stream].users != 0)
1551 continue;
1552
Kuninori Morimoto531590b2021-03-09 10:08:17 +09001553 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) {
1554 if (!do_hw_free)
1555 continue;
1556
1557 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) {
Takashi Iwaib7898392021-12-07 11:37:42 -06001558 __soc_pcm_hw_free(be, be_substream);
Kuninori Morimoto531590b2021-03-09 10:08:17 +09001559 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1560 }
1561 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001562
Takashi Iwaib7898392021-12-07 11:37:42 -06001563 __soc_pcm_close(be, be_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001564 be_substream->runtime = NULL;
1565 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1566 }
1567}
1568
Liam Girdwood23607022014-01-17 17:03:55 +00001569int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001570{
Kuninori Morimoto06aaeb82021-03-15 09:58:13 +09001571 struct snd_soc_pcm_runtime *be;
Liam Girdwood01d75842012-04-25 12:12:49 +01001572 struct snd_soc_dpcm *dpcm;
1573 int err, count = 0;
1574
1575 /* only startup BE DAIs that are either sinks or sources to this FE DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001576 for_each_dpcm_be(fe, stream, dpcm) {
Kuninori Morimoto06aaeb82021-03-15 09:58:13 +09001577 struct snd_pcm_substream *be_substream;
Liam Girdwood01d75842012-04-25 12:12:49 +01001578
Kuninori Morimoto06aaeb82021-03-15 09:58:13 +09001579 be = dpcm->be;
1580 be_substream = snd_soc_dpcm_get_substream(be, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001581
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001582 if (!be_substream) {
1583 dev_err(be->dev, "ASoC: no backend %s stream\n",
1584 stream ? "capture" : "playback");
1585 continue;
1586 }
1587
Liam Girdwood01d75842012-04-25 12:12:49 +01001588 /* is this op for this BE ? */
1589 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1590 continue;
1591
1592 /* first time the dpcm is open ? */
Kuninori Morimoto1db19c12021-03-09 10:08:08 +09001593 if (be->dpcm[stream].users == DPCM_MAX_BE_USERS) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001594 dev_err(be->dev, "ASoC: too many users %s at open %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001595 stream ? "capture" : "playback",
1596 be->dpcm[stream].state);
Kuninori Morimoto1db19c12021-03-09 10:08:08 +09001597 continue;
1598 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001599
1600 if (be->dpcm[stream].users++ != 0)
1601 continue;
1602
1603 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
1604 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
1605 continue;
1606
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001607 dev_dbg(be->dev, "ASoC: open %s BE %s\n",
1608 stream ? "capture" : "playback", be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001609
1610 be_substream->runtime = be->dpcm[stream].runtime;
Takashi Iwaib7898392021-12-07 11:37:42 -06001611 err = __soc_pcm_open(be, be_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001612 if (err < 0) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001613 be->dpcm[stream].users--;
1614 if (be->dpcm[stream].users < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001615 dev_err(be->dev, "ASoC: no users %s at unwind %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001616 stream ? "capture" : "playback",
1617 be->dpcm[stream].state);
1618
1619 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1620 goto unwind;
1621 }
Pierre-Louis Bossart848aedf2021-12-07 11:37:44 -06001622 be->dpcm[stream].be_start = 0;
Liam Girdwood01d75842012-04-25 12:12:49 +01001623 be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1624 count++;
1625 }
1626
1627 return count;
1628
1629unwind:
Kuninori Morimoto531590b2021-03-09 10:08:17 +09001630 dpcm_be_dai_startup_rollback(fe, stream, dpcm);
Liam Girdwood01d75842012-04-25 12:12:49 +01001631
Kuninori Morimoto06aaeb82021-03-15 09:58:13 +09001632 dev_err(fe->dev, "ASoC: %s() failed at %s (%d)\n",
1633 __func__, be->dai_link->name, err);
1634
Liam Girdwood01d75842012-04-25 12:12:49 +01001635 return err;
1636}
1637
Kuninori Morimoto5f538982021-02-22 09:47:26 +09001638static void dpcm_runtime_setup_fe(struct snd_pcm_substream *substream)
1639{
1640 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
1641 struct snd_pcm_runtime *runtime = substream->runtime;
1642 struct snd_pcm_hardware *hw = &runtime->hw;
1643 struct snd_soc_dai *dai;
1644 int stream = substream->stream;
1645 int i;
1646
1647 soc_pcm_hw_init(hw);
1648
1649 for_each_rtd_cpu_dais(fe, i, dai) {
1650 struct snd_soc_pcm_stream *cpu_stream;
1651
1652 /*
1653 * Skip CPUs which don't support the current stream
1654 * type. See soc_pcm_init_runtime_hw() for more details
1655 */
1656 if (!snd_soc_dai_stream_valid(dai, stream))
1657 continue;
1658
1659 cpu_stream = snd_soc_dai_get_pcm_stream(dai, stream);
1660
1661 soc_pcm_hw_update_rate(hw, cpu_stream);
1662 soc_pcm_hw_update_chan(hw, cpu_stream);
1663 soc_pcm_hw_update_format(hw, cpu_stream);
1664 }
1665
1666}
1667
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001668static void dpcm_runtime_setup_be_format(struct snd_pcm_substream *substream)
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001669{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001670 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001671 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto4b260f42021-01-22 10:13:48 +09001672 struct snd_pcm_hardware *hw = &runtime->hw;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001673 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001674 struct snd_soc_dai *dai;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001675 int stream = substream->stream;
1676
1677 if (!fe->dai_link->dpcm_merged_format)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001678 return;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001679
1680 /*
1681 * It returns merged BE codec format
1682 * if FE want to use it (= dpcm_merged_format)
1683 */
1684
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001685 for_each_dpcm_be(fe, stream, dpcm) {
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001686 struct snd_soc_pcm_runtime *be = dpcm->be;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001687 struct snd_soc_pcm_stream *codec_stream;
1688 int i;
1689
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001690 for_each_rtd_codec_dais(be, i, dai) {
Jerome Brunet4febced2018-06-27 17:36:38 +02001691 /*
1692 * Skip CODECs which don't support the current stream
1693 * type. See soc_pcm_init_runtime_hw() for more details
1694 */
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001695 if (!snd_soc_dai_stream_valid(dai, stream))
Jerome Brunet4febced2018-06-27 17:36:38 +02001696 continue;
1697
Kuninori Morimotoacf253c2020-02-19 15:56:30 +09001698 codec_stream = snd_soc_dai_get_pcm_stream(dai, stream);
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001699
Kuninori Morimotodebc71f2021-02-04 08:52:04 +09001700 soc_pcm_hw_update_format(hw, codec_stream);
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001701 }
1702 }
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001703}
1704
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001705static void dpcm_runtime_setup_be_chan(struct snd_pcm_substream *substream)
Jiada Wangf4c277b2018-06-20 18:25:20 +09001706{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001707 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001708 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto4b260f42021-01-22 10:13:48 +09001709 struct snd_pcm_hardware *hw = &runtime->hw;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001710 struct snd_soc_dpcm *dpcm;
1711 int stream = substream->stream;
1712
1713 if (!fe->dai_link->dpcm_merged_chan)
1714 return;
1715
Jiada Wangf4c277b2018-06-20 18:25:20 +09001716 /*
1717 * It returns merged BE codec channel;
1718 * if FE want to use it (= dpcm_merged_chan)
1719 */
1720
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001721 for_each_dpcm_be(fe, stream, dpcm) {
Jiada Wangf4c277b2018-06-20 18:25:20 +09001722 struct snd_soc_pcm_runtime *be = dpcm->be;
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001723 struct snd_soc_pcm_stream *cpu_stream;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001724 struct snd_soc_dai *dai;
1725 int i;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001726
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001727 for_each_rtd_cpu_dais(be, i, dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001728 /*
1729 * Skip CPUs which don't support the current stream
1730 * type. See soc_pcm_init_runtime_hw() for more details
1731 */
1732 if (!snd_soc_dai_stream_valid(dai, stream))
1733 continue;
1734
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001735 cpu_stream = snd_soc_dai_get_pcm_stream(dai, stream);
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001736
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +09001737 soc_pcm_hw_update_chan(hw, cpu_stream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001738 }
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001739
1740 /*
1741 * chan min/max cannot be enforced if there are multiple CODEC
1742 * DAIs connected to a single CPU DAI, use CPU DAI's directly
1743 */
1744 if (be->num_codecs == 1) {
Kuninori Morimoto9bdc5732021-07-27 11:05:51 +09001745 struct snd_soc_pcm_stream *codec_stream = snd_soc_dai_get_pcm_stream(
1746 asoc_rtd_to_codec(be, 0), stream);
Jiada Wangf4c277b2018-06-20 18:25:20 +09001747
Kuninori Morimoto6cb56a42021-02-04 08:51:49 +09001748 soc_pcm_hw_update_chan(hw, codec_stream);
Jiada Wangf4c277b2018-06-20 18:25:20 +09001749 }
1750 }
1751}
1752
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001753static void dpcm_runtime_setup_be_rate(struct snd_pcm_substream *substream)
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001754{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001755 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Kuninori Morimoto1b8cb122021-02-22 09:47:34 +09001756 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto4b260f42021-01-22 10:13:48 +09001757 struct snd_pcm_hardware *hw = &runtime->hw;
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001758 struct snd_soc_dpcm *dpcm;
1759 int stream = substream->stream;
1760
1761 if (!fe->dai_link->dpcm_merged_rate)
1762 return;
1763
1764 /*
1765 * It returns merged BE codec channel;
1766 * if FE want to use it (= dpcm_merged_chan)
1767 */
1768
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001769 for_each_dpcm_be(fe, stream, dpcm) {
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001770 struct snd_soc_pcm_runtime *be = dpcm->be;
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001771 struct snd_soc_pcm_stream *pcm;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001772 struct snd_soc_dai *dai;
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001773 int i;
1774
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001775 for_each_rtd_dais(be, i, dai) {
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001776 /*
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001777 * Skip DAIs which don't support the current stream
Bard Liao0e9cf4c42020-02-25 21:39:17 +08001778 * type. See soc_pcm_init_runtime_hw() for more details
1779 */
1780 if (!snd_soc_dai_stream_valid(dai, stream))
1781 continue;
1782
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001783 pcm = snd_soc_dai_get_pcm_stream(dai, stream);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001784
Kuninori Morimotof6c04af2021-02-04 08:50:31 +09001785 soc_pcm_hw_update_rate(hw, pcm);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001786 }
1787 }
1788}
1789
PC Liao906c7d62015-12-11 11:33:51 +08001790static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
1791 int stream)
1792{
1793 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001794 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001795 struct snd_soc_dai *fe_cpu_dai;
Jaroslav Kysela12ffd722021-06-14 09:17:46 +02001796 int err = 0;
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001797 int i;
PC Liao906c7d62015-12-11 11:33:51 +08001798
1799 /* apply symmetry for FE */
Kuninori Morimoto68cbc552021-03-09 10:07:57 +09001800 soc_pcm_update_symmetry(fe_substream);
PC Liao906c7d62015-12-11 11:33:51 +08001801
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09001802 for_each_rtd_cpu_dais (fe, i, fe_cpu_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08001803 /* Symmetry only applies if we've got an active stream. */
Kuninori Morimotof8fc9ec2021-03-09 10:07:42 +09001804 err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai);
1805 if (err < 0)
Kuninori Morimotobbd2bac2021-03-15 09:58:02 +09001806 goto error;
PC Liao906c7d62015-12-11 11:33:51 +08001807 }
1808
1809 /* apply symmetry for BE */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001810 for_each_dpcm_be(fe, stream, dpcm) {
PC Liao906c7d62015-12-11 11:33:51 +08001811 struct snd_soc_pcm_runtime *be = dpcm->be;
1812 struct snd_pcm_substream *be_substream =
1813 snd_soc_dpcm_get_substream(be, stream);
Jerome Brunet6246f282019-04-01 15:03:54 +02001814 struct snd_soc_pcm_runtime *rtd;
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001815 struct snd_soc_dai *dai;
PC Liao906c7d62015-12-11 11:33:51 +08001816
Jerome Brunet6246f282019-04-01 15:03:54 +02001817 /* A backend may not have the requested substream */
1818 if (!be_substream)
1819 continue;
1820
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001821 rtd = asoc_substream_to_rtd(be_substream);
Jeeja KPf1176612016-09-06 14:17:55 +05301822 if (rtd->dai_link->be_hw_params_fixup)
1823 continue;
1824
Kuninori Morimoto68cbc552021-03-09 10:07:57 +09001825 soc_pcm_update_symmetry(be_substream);
PC Liao906c7d62015-12-11 11:33:51 +08001826
1827 /* Symmetry only applies if we've got an active stream. */
Kuninori Morimotoc840f762020-03-16 15:37:14 +09001828 for_each_rtd_dais(rtd, i, dai) {
Kuninori Morimotof8fc9ec2021-03-09 10:07:42 +09001829 err = soc_pcm_apply_symmetry(fe_substream, dai);
1830 if (err < 0)
Kuninori Morimotobbd2bac2021-03-15 09:58:02 +09001831 goto error;
PC Liao906c7d62015-12-11 11:33:51 +08001832 }
1833 }
Kuninori Morimotobbd2bac2021-03-15 09:58:02 +09001834error:
1835 if (err < 0)
1836 dev_err(fe->dev, "ASoC: %s failed (%d)\n", __func__, err);
PC Liao906c7d62015-12-11 11:33:51 +08001837
Kuninori Morimotobbd2bac2021-03-15 09:58:02 +09001838 return err;
PC Liao906c7d62015-12-11 11:33:51 +08001839}
1840
Liam Girdwood01d75842012-04-25 12:12:49 +01001841static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
1842{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001843 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001844 int stream = fe_substream->stream, ret = 0;
1845
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001846 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001847
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09001848 ret = dpcm_be_dai_startup(fe, stream);
Kuninori Morimoto06aaeb82021-03-15 09:58:13 +09001849 if (ret < 0)
Liam Girdwood01d75842012-04-25 12:12:49 +01001850 goto be_err;
Liam Girdwood01d75842012-04-25 12:12:49 +01001851
Liam Girdwood103d84a2012-11-19 14:39:15 +00001852 dev_dbg(fe->dev, "ASoC: open FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001853
1854 /* start the DAI frontend */
Takashi Iwaib7898392021-12-07 11:37:42 -06001855 ret = __soc_pcm_open(fe, fe_substream);
Kuninori Morimotoe4b044f2021-03-15 09:57:37 +09001856 if (ret < 0)
Liam Girdwood01d75842012-04-25 12:12:49 +01001857 goto unwind;
Liam Girdwood01d75842012-04-25 12:12:49 +01001858
1859 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1860
Kuninori Morimoto4fe28462021-02-22 09:47:36 +09001861 dpcm_runtime_setup_fe(fe_substream);
1862
1863 dpcm_runtime_setup_be_format(fe_substream);
1864 dpcm_runtime_setup_be_chan(fe_substream);
1865 dpcm_runtime_setup_be_rate(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001866
PC Liao906c7d62015-12-11 11:33:51 +08001867 ret = dpcm_apply_symmetry(fe_substream, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001868
1869unwind:
Kuninori Morimoto8a01fbf2020-03-06 10:09:59 +09001870 if (ret < 0)
1871 dpcm_be_dai_startup_unwind(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001872be_err:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001873 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Kuninori Morimoto06aaeb82021-03-15 09:58:13 +09001874
1875 if (ret < 0)
1876 dev_err(fe->dev, "%s() failed (%d)\n", __func__, ret);
1877
Liam Girdwood01d75842012-04-25 12:12:49 +01001878 return ret;
1879}
1880
Liam Girdwood01d75842012-04-25 12:12:49 +01001881static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
1882{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001883 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001884 int stream = substream->stream;
1885
Takashi Iwaib7898392021-12-07 11:37:42 -06001886 snd_soc_dpcm_mutex_assert_held(fe);
1887
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001888 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001889
1890 /* shutdown the BEs */
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09001891 dpcm_be_dai_shutdown(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001892
Liam Girdwood103d84a2012-11-19 14:39:15 +00001893 dev_dbg(fe->dev, "ASoC: close FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001894
1895 /* now shutdown the frontend */
Takashi Iwaib7898392021-12-07 11:37:42 -06001896 __soc_pcm_close(fe, substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001897
Ranjani Sridharanbb9dd3c2020-12-02 11:33:43 -08001898 /* run the stream stop event */
1899 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
1900
Liam Girdwood01d75842012-04-25 12:12:49 +01001901 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001902 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001903 return 0;
1904}
1905
Kuninori Morimotof52366e2021-03-15 09:58:32 +09001906void dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001907{
1908 struct snd_soc_dpcm *dpcm;
1909
1910 /* only hw_params backends that are either sinks or sources
1911 * to this frontend DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001912 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001913
1914 struct snd_soc_pcm_runtime *be = dpcm->be;
1915 struct snd_pcm_substream *be_substream =
1916 snd_soc_dpcm_get_substream(be, stream);
1917
1918 /* is this op for this BE ? */
1919 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1920 continue;
1921
1922 /* only free hw when no longer used - check all FEs */
1923 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1924 continue;
1925
Qiao Zhou36fba622014-12-03 10:13:43 +08001926 /* do not free hw if this BE is used by other FE */
1927 if (be->dpcm[stream].users > 1)
1928 continue;
1929
Liam Girdwood01d75842012-04-25 12:12:49 +01001930 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1931 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
1932 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Patrick Lai08b27842012-12-19 19:36:02 -08001933 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
Vinod Koul5e82d2b2016-02-01 22:26:40 +05301934 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
1935 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
Liam Girdwood01d75842012-04-25 12:12:49 +01001936 continue;
1937
Liam Girdwood103d84a2012-11-19 14:39:15 +00001938 dev_dbg(be->dev, "ASoC: hw_free BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001939 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001940
Takashi Iwaib7898392021-12-07 11:37:42 -06001941 __soc_pcm_hw_free(be, be_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001942
1943 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1944 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001945}
1946
Mark Brown45c0a182012-05-09 21:46:27 +01001947static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001948{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09001949 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Kuninori Morimotof52366e2021-03-15 09:58:32 +09001950 int stream = substream->stream;
Liam Girdwood01d75842012-04-25 12:12:49 +01001951
Takashi Iwaib7898392021-12-07 11:37:42 -06001952 snd_soc_dpcm_mutex_lock(fe);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001953 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001954
Liam Girdwood103d84a2012-11-19 14:39:15 +00001955 dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001956
1957 /* call hw_free on the frontend */
Takashi Iwaib7898392021-12-07 11:37:42 -06001958 soc_pcm_hw_clean(fe, substream, 0);
Liam Girdwood01d75842012-04-25 12:12:49 +01001959
1960 /* only hw_params backends that are either sinks or sources
1961 * to this frontend DAI */
Kuninori Morimotof52366e2021-03-15 09:58:32 +09001962 dpcm_be_dai_hw_free(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001963
1964 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001965 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001966
Takashi Iwaib7898392021-12-07 11:37:42 -06001967 snd_soc_dpcm_mutex_unlock(fe);
Liam Girdwood01d75842012-04-25 12:12:49 +01001968 return 0;
1969}
1970
Liam Girdwood23607022014-01-17 17:03:55 +00001971int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001972{
Kuninori Morimoto33b6b942021-03-15 09:58:18 +09001973 struct snd_soc_pcm_runtime *be;
1974 struct snd_pcm_substream *be_substream;
Liam Girdwood01d75842012-04-25 12:12:49 +01001975 struct snd_soc_dpcm *dpcm;
1976 int ret;
1977
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001978 for_each_dpcm_be(fe, stream, dpcm) {
Kuninori Morimoto33b6b942021-03-15 09:58:18 +09001979 be = dpcm->be;
1980 be_substream = snd_soc_dpcm_get_substream(be, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001981
1982 /* is this op for this BE ? */
1983 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1984 continue;
1985
Liam Girdwood01d75842012-04-25 12:12:49 +01001986 /* copy params for each dpcm */
1987 memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params,
1988 sizeof(struct snd_pcm_hw_params));
1989
1990 /* perform any hw_params fixups */
Kuninori Morimoto0cbbf8a2020-05-25 09:57:36 +09001991 ret = snd_soc_link_be_hw_params_fixup(be, &dpcm->hw_params);
1992 if (ret < 0)
1993 goto unwind;
Liam Girdwood01d75842012-04-25 12:12:49 +01001994
Libin Yangae061d22019-04-19 09:53:12 +08001995 /* copy the fixed-up hw params for BE dai */
1996 memcpy(&be->dpcm[stream].hw_params, &dpcm->hw_params,
1997 sizeof(struct snd_pcm_hw_params));
1998
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00001999 /* only allow hw_params() if no connected FEs are running */
2000 if (!snd_soc_dpcm_can_be_params(fe, be, stream))
2001 continue;
2002
2003 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
2004 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2005 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE))
2006 continue;
2007
2008 dev_dbg(be->dev, "ASoC: hw_params BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002009 be->dai_link->name);
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00002010
Takashi Iwaib7898392021-12-07 11:37:42 -06002011 ret = __soc_pcm_hw_params(be, be_substream, &dpcm->hw_params);
Kuninori Morimotocb11f792021-03-15 09:57:42 +09002012 if (ret < 0)
Liam Girdwood01d75842012-04-25 12:12:49 +01002013 goto unwind;
Liam Girdwood01d75842012-04-25 12:12:49 +01002014
2015 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2016 }
2017 return 0;
2018
2019unwind:
Kuninori Morimoto33b6b942021-03-15 09:58:18 +09002020 dev_dbg(fe->dev, "ASoC: %s() failed at %s (%d)\n",
2021 __func__, be->dai_link->name, ret);
2022
Liam Girdwood01d75842012-04-25 12:12:49 +01002023 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002024 for_each_dpcm_be_rollback(fe, stream, dpcm) {
Kuninori Morimoto33b6b942021-03-15 09:58:18 +09002025 be = dpcm->be;
2026 be_substream = snd_soc_dpcm_get_substream(be, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002027
2028 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2029 continue;
2030
2031 /* only allow hw_free() if no connected FEs are running */
2032 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2033 continue;
2034
2035 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
2036 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2037 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
2038 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
2039 continue;
2040
Takashi Iwaib7898392021-12-07 11:37:42 -06002041 __soc_pcm_hw_free(be, be_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002042 }
2043
2044 return ret;
2045}
2046
Mark Brown45c0a182012-05-09 21:46:27 +01002047static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
2048 struct snd_pcm_hw_params *params)
Liam Girdwood01d75842012-04-25 12:12:49 +01002049{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002050 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002051 int ret, stream = substream->stream;
2052
Takashi Iwaib7898392021-12-07 11:37:42 -06002053 snd_soc_dpcm_mutex_lock(fe);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002054 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002055
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09002056 memcpy(&fe->dpcm[stream].hw_params, params,
Liam Girdwood01d75842012-04-25 12:12:49 +01002057 sizeof(struct snd_pcm_hw_params));
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09002058 ret = dpcm_be_dai_hw_params(fe, stream);
Kuninori Morimoto33b6b942021-03-15 09:58:18 +09002059 if (ret < 0)
Liam Girdwood01d75842012-04-25 12:12:49 +01002060 goto out;
Liam Girdwood01d75842012-04-25 12:12:49 +01002061
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 */
Takashi Iwaib7898392021-12-07 11:37:42 -06002067 ret = __soc_pcm_hw_params(fe, substream, params);
Kuninori Morimotocb11f792021-03-15 09:57:42 +09002068 if (ret < 0)
Liam Girdwood01d75842012-04-25 12:12:49 +01002069 dpcm_be_dai_hw_free(fe, stream);
Kuninori Morimotocb11f792021-03-15 09:57:42 +09002070 else
Liam Girdwood01d75842012-04-25 12:12:49 +01002071 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2072
2073out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002074 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Takashi Iwaib7898392021-12-07 11:37:42 -06002075 snd_soc_dpcm_mutex_unlock(fe);
Kuninori Morimoto33b6b942021-03-15 09:58:18 +09002076
2077 if (ret < 0)
2078 dev_err(fe->dev, "ASoC: %s failed (%d)\n", __func__, ret);
2079
Liam Girdwood01d75842012-04-25 12:12:49 +01002080 return ret;
2081}
2082
Liam Girdwood23607022014-01-17 17:03:55 +00002083int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
Mark Brown45c0a182012-05-09 21:46:27 +01002084 int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002085{
Kuninori Morimotodb3aa392021-03-15 09:57:57 +09002086 struct snd_soc_pcm_runtime *be;
Liam Girdwood01d75842012-04-25 12:12:49 +01002087 struct snd_soc_dpcm *dpcm;
Takashi Iwaib2ae8062021-12-07 11:37:43 -06002088 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01002089 int ret = 0;
2090
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002091 for_each_dpcm_be(fe, stream, dpcm) {
Kuninori Morimotodb3aa392021-03-15 09:57:57 +09002092 struct snd_pcm_substream *be_substream;
Liam Girdwood01d75842012-04-25 12:12:49 +01002093
Kuninori Morimotodb3aa392021-03-15 09:57:57 +09002094 be = dpcm->be;
2095 be_substream = snd_soc_dpcm_get_substream(be, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002096
Takashi Iwaib2ae8062021-12-07 11:37:43 -06002097 snd_soc_dpcm_stream_lock_irqsave(be, stream, flags);
2098
Liam Girdwood01d75842012-04-25 12:12:49 +01002099 /* is this op for this BE ? */
2100 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
Takashi Iwaib2ae8062021-12-07 11:37:43 -06002101 goto next;
Liam Girdwood01d75842012-04-25 12:12:49 +01002102
Kuninori Morimotoa9faca12020-12-01 08:51:25 +09002103 dev_dbg(be->dev, "ASoC: trigger BE %s cmd %d\n",
2104 be->dai_link->name, cmd);
2105
Liam Girdwood01d75842012-04-25 12:12:49 +01002106 switch (cmd) {
2107 case SNDRV_PCM_TRIGGER_START:
Pierre-Louis Bossart848aedf2021-12-07 11:37:44 -06002108 if (!be->dpcm[stream].be_start &&
2109 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
이경택21fca8b2020-04-01 10:04:21 +09002110 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
Mark Brown3202e2f2021-08-30 12:13:46 +01002111 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Takashi Iwaib2ae8062021-12-07 11:37:43 -06002112 goto next;
Pierre-Louis Bossart6479f752021-08-17 11:40:54 -05002113
Pierre-Louis Bossart848aedf2021-12-07 11:37:44 -06002114 be->dpcm[stream].be_start++;
2115 if (be->dpcm[stream].be_start != 1)
Takashi Iwaib2ae8062021-12-07 11:37:43 -06002116 goto next;
Liam Girdwood01d75842012-04-25 12:12:49 +01002117
Pierre-Louis Bossart848aedf2021-12-07 11:37:44 -06002118 ret = soc_pcm_trigger(be_substream, cmd);
2119 if (ret) {
2120 be->dpcm[stream].be_start--;
2121 goto next;
2122 }
2123
Mark Brown3202e2f2021-08-30 12:13:46 +01002124 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
Liam Girdwood01d75842012-04-25 12:12:49 +01002125 break;
2126 case SNDRV_PCM_TRIGGER_RESUME:
Mark Brown3202e2f2021-08-30 12:13:46 +01002127 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
Takashi Iwaib2ae8062021-12-07 11:37:43 -06002128 goto next;
Pierre-Louis Bossart6479f752021-08-17 11:40:54 -05002129
Pierre-Louis Bossart848aedf2021-12-07 11:37:44 -06002130 be->dpcm[stream].be_start++;
2131 if (be->dpcm[stream].be_start != 1)
Takashi Iwaib2ae8062021-12-07 11:37:43 -06002132 goto next;
Liam Girdwood01d75842012-04-25 12:12:49 +01002133
Pierre-Louis Bossart848aedf2021-12-07 11:37:44 -06002134 ret = soc_pcm_trigger(be_substream, cmd);
2135 if (ret) {
2136 be->dpcm[stream].be_start--;
2137 goto next;
2138 }
2139
Mark Brown3202e2f2021-08-30 12:13:46 +01002140 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
Liam Girdwood01d75842012-04-25 12:12:49 +01002141 break;
2142 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Pierre-Louis Bossart3aa1e962021-12-07 11:37:45 -06002143 if (!be->dpcm[stream].be_start &&
2144 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) &&
2145 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
2146 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Takashi Iwaib2ae8062021-12-07 11:37:43 -06002147 goto next;
Pierre-Louis Bossart6479f752021-08-17 11:40:54 -05002148
Pierre-Louis Bossart848aedf2021-12-07 11:37:44 -06002149 be->dpcm[stream].be_start++;
2150 if (be->dpcm[stream].be_start != 1)
Takashi Iwaib2ae8062021-12-07 11:37:43 -06002151 goto next;
Liam Girdwood01d75842012-04-25 12:12:49 +01002152
Pierre-Louis Bossart848aedf2021-12-07 11:37:44 -06002153 ret = soc_pcm_trigger(be_substream, cmd);
2154 if (ret) {
2155 be->dpcm[stream].be_start--;
2156 goto next;
2157 }
2158
Mark Brown3202e2f2021-08-30 12:13:46 +01002159 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
Liam Girdwood01d75842012-04-25 12:12:49 +01002160 break;
2161 case SNDRV_PCM_TRIGGER_STOP:
이경택21fca8b2020-04-01 10:04:21 +09002162 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) &&
Mark Brown3202e2f2021-08-30 12:13:46 +01002163 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Takashi Iwaib2ae8062021-12-07 11:37:43 -06002164 goto next;
Liam Girdwood01d75842012-04-25 12:12:49 +01002165
Pierre-Louis Bossart848aedf2021-12-07 11:37:44 -06002166 if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_START)
2167 be->dpcm[stream].be_start--;
2168
2169 if (be->dpcm[stream].be_start != 0)
Takashi Iwaib2ae8062021-12-07 11:37:43 -06002170 goto next;
Pierre-Louis Bossart0c75fc72021-08-17 11:40:53 -05002171
2172 ret = soc_pcm_trigger(be_substream, cmd);
Pierre-Louis Bossart848aedf2021-12-07 11:37:44 -06002173 if (ret) {
2174 if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_START)
2175 be->dpcm[stream].be_start++;
Takashi Iwaib2ae8062021-12-07 11:37:43 -06002176 goto next;
Pierre-Louis Bossart848aedf2021-12-07 11:37:44 -06002177 }
Pierre-Louis Bossart0c75fc72021-08-17 11:40:53 -05002178
Mark Brown3202e2f2021-08-30 12:13:46 +01002179 be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
Liam Girdwood01d75842012-04-25 12:12:49 +01002180 break;
2181 case SNDRV_PCM_TRIGGER_SUSPEND:
Mark Brown3202e2f2021-08-30 12:13:46 +01002182 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
Takashi Iwaib2ae8062021-12-07 11:37:43 -06002183 goto next;
Liam Girdwood01d75842012-04-25 12:12:49 +01002184
Pierre-Louis Bossart848aedf2021-12-07 11:37:44 -06002185 be->dpcm[stream].be_start--;
2186 if (be->dpcm[stream].be_start != 0)
Takashi Iwaib2ae8062021-12-07 11:37:43 -06002187 goto next;
Liam Girdwood01d75842012-04-25 12:12:49 +01002188
Pierre-Louis Bossart0c75fc72021-08-17 11:40:53 -05002189 ret = soc_pcm_trigger(be_substream, cmd);
Pierre-Louis Bossart848aedf2021-12-07 11:37:44 -06002190 if (ret) {
2191 be->dpcm[stream].be_start++;
Takashi Iwaib2ae8062021-12-07 11:37:43 -06002192 goto next;
Pierre-Louis Bossart848aedf2021-12-07 11:37:44 -06002193 }
Pierre-Louis Bossart0c75fc72021-08-17 11:40:53 -05002194
Mark Brown3202e2f2021-08-30 12:13:46 +01002195 be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND;
Liam Girdwood01d75842012-04-25 12:12:49 +01002196 break;
2197 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
Mark Brown3202e2f2021-08-30 12:13:46 +01002198 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
Takashi Iwaib2ae8062021-12-07 11:37:43 -06002199 goto next;
Liam Girdwood01d75842012-04-25 12:12:49 +01002200
Pierre-Louis Bossart848aedf2021-12-07 11:37:44 -06002201 be->dpcm[stream].be_start--;
2202 if (be->dpcm[stream].be_start != 0)
Takashi Iwaib2ae8062021-12-07 11:37:43 -06002203 goto next;
Pierre-Louis Bossart0c75fc72021-08-17 11:40:53 -05002204
2205 ret = soc_pcm_trigger(be_substream, cmd);
Pierre-Louis Bossart848aedf2021-12-07 11:37:44 -06002206 if (ret) {
2207 be->dpcm[stream].be_start++;
Takashi Iwaib2ae8062021-12-07 11:37:43 -06002208 goto next;
Pierre-Louis Bossart848aedf2021-12-07 11:37:44 -06002209 }
Pierre-Louis Bossart0c75fc72021-08-17 11:40:53 -05002210
Mark Brown3202e2f2021-08-30 12:13:46 +01002211 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
Liam Girdwood01d75842012-04-25 12:12:49 +01002212 break;
2213 }
Takashi Iwaib2ae8062021-12-07 11:37:43 -06002214next:
2215 snd_soc_dpcm_stream_unlock_irqrestore(be, stream, flags);
2216 if (ret)
2217 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002218 }
Kuninori Morimotodb3aa392021-03-15 09:57:57 +09002219 if (ret < 0)
2220 dev_err(fe->dev, "ASoC: %s() failed at %s (%d)\n",
2221 __func__, be->dai_link->name, ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002222 return ret;
2223}
2224EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
2225
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002226static int dpcm_dai_trigger_fe_be(struct snd_pcm_substream *substream,
2227 int cmd, bool fe_first)
2228{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002229 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002230 int ret;
2231
2232 /* call trigger on the frontend before the backend. */
2233 if (fe_first) {
2234 dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n",
2235 fe->dai_link->name, cmd);
2236
2237 ret = soc_pcm_trigger(substream, cmd);
2238 if (ret < 0)
2239 return ret;
2240
2241 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2242 return ret;
2243 }
2244
2245 /* call trigger on the frontend after the backend. */
2246 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2247 if (ret < 0)
2248 return ret;
2249
2250 dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n",
2251 fe->dai_link->name, cmd);
2252
2253 ret = soc_pcm_trigger(substream, cmd);
2254
2255 return ret;
2256}
2257
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002258static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002259{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002260 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002261 int stream = substream->stream;
2262 int ret = 0;
Liam Girdwood01d75842012-04-25 12:12:49 +01002263 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
2264
2265 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
2266
2267 switch (trigger) {
2268 case SND_SOC_DPCM_TRIGGER_PRE:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002269 switch (cmd) {
2270 case SNDRV_PCM_TRIGGER_START:
2271 case SNDRV_PCM_TRIGGER_RESUME:
2272 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Cezary Rojewski4c22b802020-10-26 11:01:29 +01002273 case SNDRV_PCM_TRIGGER_DRAIN:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002274 ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
2275 break;
2276 case SNDRV_PCM_TRIGGER_STOP:
2277 case SNDRV_PCM_TRIGGER_SUSPEND:
2278 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2279 ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
2280 break;
2281 default:
2282 ret = -EINVAL;
2283 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002284 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002285 break;
2286 case SND_SOC_DPCM_TRIGGER_POST:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002287 switch (cmd) {
2288 case SNDRV_PCM_TRIGGER_START:
2289 case SNDRV_PCM_TRIGGER_RESUME:
2290 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Cezary Rojewski4c22b802020-10-26 11:01:29 +01002291 case SNDRV_PCM_TRIGGER_DRAIN:
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002292 ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
2293 break;
2294 case SNDRV_PCM_TRIGGER_STOP:
2295 case SNDRV_PCM_TRIGGER_SUSPEND:
2296 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2297 ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
2298 break;
2299 default:
2300 ret = -EINVAL;
2301 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002302 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002303 break;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002304 case SND_SOC_DPCM_TRIGGER_BESPOKE:
2305 /* bespoke trigger() - handles both FE and BEs */
2306
Liam Girdwood103d84a2012-11-19 14:39:15 +00002307 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd %d\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002308 fe->dai_link->name, cmd);
2309
Kuninori Morimoto308193582020-04-24 08:15:09 +09002310 ret = snd_soc_pcm_dai_bespoke_trigger(substream, cmd);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002311 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002312 default:
Liam Girdwood103d84a2012-11-19 14:39:15 +00002313 dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd,
Liam Girdwood01d75842012-04-25 12:12:49 +01002314 fe->dai_link->name);
2315 ret = -EINVAL;
2316 goto out;
2317 }
2318
Ranjani Sridharanacbf2772019-11-04 14:48:11 -08002319 if (ret < 0) {
2320 dev_err(fe->dev, "ASoC: trigger FE cmd: %d failed: %d\n",
2321 cmd, ret);
2322 goto out;
2323 }
2324
Liam Girdwood01d75842012-04-25 12:12:49 +01002325 switch (cmd) {
2326 case SNDRV_PCM_TRIGGER_START:
2327 case SNDRV_PCM_TRIGGER_RESUME:
2328 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2329 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2330 break;
2331 case SNDRV_PCM_TRIGGER_STOP:
2332 case SNDRV_PCM_TRIGGER_SUSPEND:
Liam Girdwood01d75842012-04-25 12:12:49 +01002333 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2334 break;
Patrick Lai9f169b92016-12-31 22:44:39 -08002335 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2336 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2337 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002338 }
2339
2340out:
2341 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
2342 return ret;
2343}
2344
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002345static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
2346{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002347 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002348 int stream = substream->stream;
2349
2350 /* if FE's runtime_update is already set, we're in race;
2351 * process this trigger later at exit
2352 */
2353 if (fe->dpcm[stream].runtime_update != SND_SOC_DPCM_UPDATE_NO) {
2354 fe->dpcm[stream].trigger_pending = cmd + 1;
2355 return 0; /* delayed, assuming it's successful */
2356 }
2357
2358 /* we're alone, let's trigger */
2359 return dpcm_fe_dai_do_trigger(substream, cmd);
2360}
2361
Liam Girdwood23607022014-01-17 17:03:55 +00002362int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002363{
2364 struct snd_soc_dpcm *dpcm;
2365 int ret = 0;
2366
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002367 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002368
2369 struct snd_soc_pcm_runtime *be = dpcm->be;
2370 struct snd_pcm_substream *be_substream =
2371 snd_soc_dpcm_get_substream(be, stream);
2372
2373 /* is this op for this BE ? */
2374 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2375 continue;
2376
2377 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
Koro Chen95f444d2015-10-28 10:15:34 +08002378 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
Libin Yang5087a8f2019-05-08 10:32:41 +08002379 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND) &&
2380 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Liam Girdwood01d75842012-04-25 12:12:49 +01002381 continue;
2382
Liam Girdwood103d84a2012-11-19 14:39:15 +00002383 dev_dbg(be->dev, "ASoC: prepare BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002384 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002385
Takashi Iwaib7898392021-12-07 11:37:42 -06002386 ret = __soc_pcm_prepare(be, be_substream);
Kuninori Morimotodab7eeb2021-03-15 09:57:48 +09002387 if (ret < 0)
Liam Girdwood01d75842012-04-25 12:12:49 +01002388 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002389
2390 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2391 }
Kuninori Morimoto273db972021-03-15 09:58:22 +09002392
2393 if (ret < 0)
2394 dev_err(fe->dev, "ASoC: %s() failed (%d)\n", __func__, ret);
2395
Liam Girdwood01d75842012-04-25 12:12:49 +01002396 return ret;
2397}
2398
Mark Brown45c0a182012-05-09 21:46:27 +01002399static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002400{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002401 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002402 int stream = substream->stream, ret = 0;
2403
Takashi Iwaib7898392021-12-07 11:37:42 -06002404 snd_soc_dpcm_mutex_lock(fe);
Liam Girdwood01d75842012-04-25 12:12:49 +01002405
Liam Girdwood103d84a2012-11-19 14:39:15 +00002406 dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002407
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002408 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002409
2410 /* there is no point preparing this FE if there are no BEs */
2411 if (list_empty(&fe->dpcm[stream].be_clients)) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002412 dev_err(fe->dev, "ASoC: no backend DAIs enabled for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002413 fe->dai_link->name);
2414 ret = -EINVAL;
2415 goto out;
2416 }
2417
Kuninori Morimoto25c2f512020-02-27 10:54:38 +09002418 ret = dpcm_be_dai_prepare(fe, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002419 if (ret < 0)
2420 goto out;
2421
2422 /* call prepare on the frontend */
Takashi Iwaib7898392021-12-07 11:37:42 -06002423 ret = __soc_pcm_prepare(fe, substream);
Kuninori Morimotodab7eeb2021-03-15 09:57:48 +09002424 if (ret < 0)
Liam Girdwood01d75842012-04-25 12:12:49 +01002425 goto out;
Liam Girdwood01d75842012-04-25 12:12:49 +01002426
Liam Girdwood01d75842012-04-25 12:12:49 +01002427 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2428
2429out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002430 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Takashi Iwaib7898392021-12-07 11:37:42 -06002431 snd_soc_dpcm_mutex_unlock(fe);
Liam Girdwood01d75842012-04-25 12:12:49 +01002432
Kuninori Morimoto273db972021-03-15 09:58:22 +09002433 if (ret < 0)
2434 dev_err(fe->dev, "ASoC: %s() failed (%d)\n", __func__, ret);
2435
Liam Girdwood01d75842012-04-25 12:12:49 +01002436 return ret;
2437}
2438
Liam Girdwood618dae12012-04-25 12:12:51 +01002439static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
2440{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002441 struct snd_pcm_substream *substream =
2442 snd_soc_dpcm_get_substream(fe, stream);
2443 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01002444 int err;
Liam Girdwood01d75842012-04-25 12:12:49 +01002445
Liam Girdwood103d84a2012-11-19 14:39:15 +00002446 dev_dbg(fe->dev, "ASoC: runtime %s close on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002447 stream ? "capture" : "playback", fe->dai_link->name);
2448
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002449 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2450 /* call bespoke trigger - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002451 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002452 fe->dai_link->name);
2453
Kuninori Morimoto308193582020-04-24 08:15:09 +09002454 err = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002455 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002456 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002457 fe->dai_link->name);
2458
2459 err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002460 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002461
Kuninori Morimotof52366e2021-03-15 09:58:32 +09002462 dpcm_be_dai_hw_free(fe, stream);
Liam Girdwood618dae12012-04-25 12:12:51 +01002463
Kuninori Morimoto531590b2021-03-09 10:08:17 +09002464 dpcm_be_dai_shutdown(fe, stream);
Liam Girdwood618dae12012-04-25 12:12:51 +01002465
2466 /* run the stream event for each BE */
2467 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2468
Kuninori Morimoto81c82a92021-03-15 09:58:08 +09002469 if (err < 0)
2470 dev_err(fe->dev, "ASoC: %s() failed (%d)\n", __func__, err);
2471
2472 return err;
Liam Girdwood618dae12012-04-25 12:12:51 +01002473}
2474
2475static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
2476{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002477 struct snd_pcm_substream *substream =
2478 snd_soc_dpcm_get_substream(fe, stream);
Liam Girdwood618dae12012-04-25 12:12:51 +01002479 struct snd_soc_dpcm *dpcm;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002480 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Souptick Joarder4eeed5f2021-01-09 09:15:01 +05302481 int ret = 0;
Liam Girdwood618dae12012-04-25 12:12:51 +01002482
Liam Girdwood103d84a2012-11-19 14:39:15 +00002483 dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002484 stream ? "capture" : "playback", fe->dai_link->name);
2485
2486 /* Only start the BE if the FE is ready */
2487 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
朱灿灿2c138282020-12-25 16:42:46 +08002488 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE) {
2489 dev_err(fe->dev, "ASoC: FE %s is not ready %d\n",
2490 fe->dai_link->name, fe->dpcm[stream].state);
Dan Carpentere91b65b2021-01-11 12:50:21 +03002491 ret = -EINVAL;
朱灿灿2c138282020-12-25 16:42:46 +08002492 goto disconnect;
2493 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002494
2495 /* startup must always be called for new BEs */
2496 ret = dpcm_be_dai_startup(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002497 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002498 goto disconnect;
Liam Girdwood618dae12012-04-25 12:12:51 +01002499
2500 /* keep going if FE state is > open */
2501 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN)
2502 return 0;
2503
2504 ret = dpcm_be_dai_hw_params(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002505 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002506 goto close;
Liam Girdwood618dae12012-04-25 12:12:51 +01002507
2508 /* keep going if FE state is > hw_params */
2509 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS)
2510 return 0;
2511
Liam Girdwood618dae12012-04-25 12:12:51 +01002512 ret = dpcm_be_dai_prepare(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002513 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002514 goto hw_free;
Liam Girdwood618dae12012-04-25 12:12:51 +01002515
2516 /* run the stream event for each BE */
2517 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2518
2519 /* keep going if FE state is > prepare */
2520 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE ||
2521 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP)
2522 return 0;
2523
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002524 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2525 /* call trigger on the frontend - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002526 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002527 fe->dai_link->name);
Liam Girdwood618dae12012-04-25 12:12:51 +01002528
Kuninori Morimoto308193582020-04-24 08:15:09 +09002529 ret = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
Kuninori Morimoto62462e02021-03-15 09:58:37 +09002530 if (ret < 0)
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002531 goto hw_free;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002532 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002533 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002534 fe->dai_link->name);
2535
2536 ret = dpcm_be_dai_trigger(fe, stream,
2537 SNDRV_PCM_TRIGGER_START);
Kuninori Morimotodb3aa392021-03-15 09:57:57 +09002538 if (ret < 0)
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002539 goto hw_free;
Liam Girdwood618dae12012-04-25 12:12:51 +01002540 }
2541
2542 return 0;
2543
2544hw_free:
2545 dpcm_be_dai_hw_free(fe, stream);
2546close:
2547 dpcm_be_dai_shutdown(fe, stream);
2548disconnect:
朱灿灿2c138282020-12-25 16:42:46 +08002549 /* disconnect any pending BEs */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002550 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood618dae12012-04-25 12:12:51 +01002551 struct snd_soc_pcm_runtime *be = dpcm->be;
朱灿灿2c138282020-12-25 16:42:46 +08002552
2553 /* is this op for this BE ? */
2554 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2555 continue;
2556
2557 if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE ||
2558 be->dpcm[stream].state == SND_SOC_DPCM_STATE_NEW)
2559 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
Liam Girdwood618dae12012-04-25 12:12:51 +01002560 }
2561
Kuninori Morimoto81c82a92021-03-15 09:58:08 +09002562 if (ret < 0)
2563 dev_err(fe->dev, "ASoC: %s() failed (%d)\n", __func__, ret);
2564
Liam Girdwood618dae12012-04-25 12:12:51 +01002565 return ret;
2566}
2567
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002568static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
2569{
2570 struct snd_soc_dapm_widget_list *list;
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002571 int stream;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002572 int count, paths;
2573
Pierre-Louis Bossart96bf62f2020-06-12 15:35:07 -05002574 if (!fe->dai_link->dynamic)
2575 return 0;
2576
Bard Liao6e1276a2020-02-25 21:39:16 +08002577 if (fe->num_cpus > 1) {
2578 dev_err(fe->dev,
2579 "%s doesn't support Multi CPU yet\n", __func__);
2580 return -EINVAL;
2581 }
2582
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002583 /* only check active links */
Kuninori Morimotob3dea622020-05-15 09:46:51 +09002584 if (!snd_soc_dai_active(asoc_rtd_to_cpu(fe, 0)))
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002585 return 0;
2586
2587 /* DAPM sync will call this to update DSP paths */
2588 dev_dbg(fe->dev, "ASoC: DPCM %s runtime update for FE %s\n",
2589 new ? "new" : "old", fe->dai_link->name);
2590
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002591 for_each_pcm_streams(stream) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002592
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002593 /* skip if FE doesn't have playback/capture capability */
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002594 if (!snd_soc_dai_stream_valid(asoc_rtd_to_cpu(fe, 0), stream) ||
2595 !snd_soc_dai_stream_valid(asoc_rtd_to_codec(fe, 0), stream))
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002596 continue;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002597
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002598 /* skip if FE isn't currently playing/capturing */
Kuninori Morimotob3dea622020-05-15 09:46:51 +09002599 if (!snd_soc_dai_stream_active(asoc_rtd_to_cpu(fe, 0), stream) ||
2600 !snd_soc_dai_stream_active(asoc_rtd_to_codec(fe, 0), stream))
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002601 continue;
2602
2603 paths = dpcm_path_get(fe, stream, &list);
Kuninori Morimotod479f002021-03-15 09:57:52 +09002604 if (paths < 0)
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002605 return paths;
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002606
2607 /* update any playback/capture paths */
2608 count = dpcm_process_paths(fe, stream, &list, new);
2609 if (count) {
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002610 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002611 if (new)
Kuninori Morimoto81c82a92021-03-15 09:58:08 +09002612 dpcm_run_update_startup(fe, stream);
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002613 else
Kuninori Morimoto81c82a92021-03-15 09:58:08 +09002614 dpcm_run_update_shutdown(fe, stream);
Kuninori Morimoto580dff32020-02-19 15:56:46 +09002615 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Kuninori Morimoto7083f8772020-02-17 17:28:28 +09002616
2617 dpcm_clear_pending_state(fe, stream);
2618 dpcm_be_disconnect(fe, stream);
2619 }
2620
2621 dpcm_path_put(&list);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002622 }
2623
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002624 return 0;
2625}
2626
Liam Girdwood618dae12012-04-25 12:12:51 +01002627/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
2628 * any DAI links.
2629 */
Guennadi Liakhovetskif17a1472020-03-12 10:52:14 +01002630int snd_soc_dpcm_runtime_update(struct snd_soc_card *card)
Liam Girdwood618dae12012-04-25 12:12:51 +01002631{
Mengdong Lin1a497982015-11-18 02:34:11 -05002632 struct snd_soc_pcm_runtime *fe;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002633 int ret = 0;
Liam Girdwood618dae12012-04-25 12:12:51 +01002634
Takashi Iwaib7898392021-12-07 11:37:42 -06002635 mutex_lock_nested(&card->pcm_mutex, card->pcm_subclass);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002636 /* shutdown all old paths first */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002637 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002638 ret = soc_dpcm_fe_runtime_update(fe, 0);
2639 if (ret)
2640 goto out;
Liam Girdwood618dae12012-04-25 12:12:51 +01002641 }
2642
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002643 /* bring new paths up */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002644 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002645 ret = soc_dpcm_fe_runtime_update(fe, 1);
2646 if (ret)
2647 goto out;
2648 }
2649
2650out:
Takashi Iwaib7898392021-12-07 11:37:42 -06002651 mutex_unlock(&card->pcm_mutex);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002652 return ret;
Liam Girdwood618dae12012-04-25 12:12:51 +01002653}
Guennadi Liakhovetskif17a1472020-03-12 10:52:14 +01002654EXPORT_SYMBOL_GPL(snd_soc_dpcm_runtime_update);
Liam Girdwood01d75842012-04-25 12:12:49 +01002655
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002656static void dpcm_fe_dai_cleanup(struct snd_pcm_substream *fe_substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002657{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002658 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002659 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002660 int stream = fe_substream->stream;
Kuninori Morimoto30fca262020-03-06 10:09:44 +09002661
Takashi Iwaib7898392021-12-07 11:37:42 -06002662 snd_soc_dpcm_mutex_assert_held(fe);
2663
Kuninori Morimoto30fca262020-03-06 10:09:44 +09002664 /* mark FE's links ready to prune */
2665 for_each_dpcm_be(fe, stream, dpcm)
2666 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2667
2668 dpcm_be_disconnect(fe, stream);
2669
2670 fe->dpcm[stream].runtime = NULL;
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002671}
2672
2673static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
2674{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002675 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002676 int ret;
2677
Takashi Iwaib7898392021-12-07 11:37:42 -06002678 snd_soc_dpcm_mutex_lock(fe);
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002679 ret = dpcm_fe_dai_shutdown(fe_substream);
2680
2681 dpcm_fe_dai_cleanup(fe_substream);
2682
Takashi Iwaib7898392021-12-07 11:37:42 -06002683 snd_soc_dpcm_mutex_unlock(fe);
Kuninori Morimoto30fca262020-03-06 10:09:44 +09002684 return ret;
2685}
2686
Liam Girdwood01d75842012-04-25 12:12:49 +01002687static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
2688{
Kuninori Morimoto0ceef682020-07-20 10:17:39 +09002689 struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002690 struct snd_soc_dapm_widget_list *list;
2691 int ret;
2692 int stream = fe_substream->stream;
2693
Takashi Iwaib7898392021-12-07 11:37:42 -06002694 snd_soc_dpcm_mutex_lock(fe);
Liam Girdwood01d75842012-04-25 12:12:49 +01002695 fe->dpcm[stream].runtime = fe_substream->runtime;
2696
Qiao Zhou8f70e512014-09-10 17:54:07 +08002697 ret = dpcm_path_get(fe, stream, &list);
Kuninori Morimotod479f002021-03-15 09:57:52 +09002698 if (ret < 0)
Kuninori Morimotocae06eb2020-02-17 17:28:11 +09002699 goto open_end;
Liam Girdwood01d75842012-04-25 12:12:49 +01002700
2701 /* calculate valid and active FE <-> BE dpcms */
2702 dpcm_process_paths(fe, stream, &list, 1);
2703
2704 ret = dpcm_fe_dai_startup(fe_substream);
Kuninori Morimoto265694b2020-03-06 10:09:49 +09002705 if (ret < 0)
2706 dpcm_fe_dai_cleanup(fe_substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01002707
2708 dpcm_clear_pending_state(fe, stream);
2709 dpcm_path_put(&list);
Kuninori Morimotocae06eb2020-02-17 17:28:11 +09002710open_end:
Takashi Iwaib7898392021-12-07 11:37:42 -06002711 snd_soc_dpcm_mutex_unlock(fe);
Liam Girdwood01d75842012-04-25 12:12:49 +01002712 return ret;
2713}
2714
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002715static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd,
2716 int *playback, int *capture)
Liam Girdwoodddee6272011-06-09 14:45:53 +01002717{
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002718 struct snd_soc_dai *cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002719 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002720
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002721 if (rtd->dai_link->dynamic && rtd->num_cpus > 1) {
2722 dev_err(rtd->dev,
2723 "DPCM doesn't support Multi CPU for Front-Ends yet\n");
2724 return -EINVAL;
2725 }
Stephan Gerhold9b5db052020-04-15 12:49:28 +02002726
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002727 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
Kuninori Morimoto940a1f42021-07-27 11:05:43 +09002728 int stream;
2729
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002730 if (rtd->dai_link->dpcm_playback) {
2731 stream = SNDRV_PCM_STREAM_PLAYBACK;
2732
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002733 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
2734 if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002735 *playback = 1;
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002736 break;
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002737 }
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002738 }
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002739 if (!*playback) {
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002740 dev_err(rtd->card->dev,
2741 "No CPU DAIs support playback for stream %s\n",
2742 rtd->dai_link->stream_name);
2743 return -EINVAL;
2744 }
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002745 }
2746 if (rtd->dai_link->dpcm_capture) {
2747 stream = SNDRV_PCM_STREAM_CAPTURE;
2748
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002749 for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
2750 if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002751 *capture = 1;
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002752 break;
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002753 }
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002754 }
2755
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002756 if (!*capture) {
Pierre-Louis Bossart4f872152020-07-23 13:05:33 -05002757 dev_err(rtd->card->dev,
2758 "No CPU DAIs support capture for stream %s\n",
2759 rtd->dai_link->stream_name);
2760 return -EINVAL;
2761 }
Pierre-Louis Bossartb73287f2020-06-08 14:44:12 -05002762 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002763 } else {
Kuninori Morimoto940a1f42021-07-27 11:05:43 +09002764 struct snd_soc_dai *codec_dai;
2765
Jerome Bruneta3420312019-07-25 18:59:47 +02002766 /* Adapt stream for codec2codec links */
Stephan Gerholda4877a62020-02-18 11:38:24 +01002767 int cpu_capture = rtd->dai_link->params ?
2768 SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
2769 int cpu_playback = rtd->dai_link->params ?
2770 SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
Jerome Bruneta3420312019-07-25 18:59:47 +02002771
Kuninori Morimotoa4be4182020-03-09 13:08:04 +09002772 for_each_rtd_codec_dais(rtd, i, codec_dai) {
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002773 if (rtd->num_cpus == 1) {
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002774 cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002775 } else if (rtd->num_cpus == rtd->num_codecs) {
Kuninori Morimotoc2233a22020-03-30 10:47:37 +09002776 cpu_dai = asoc_rtd_to_cpu(rtd, i);
Shreyas NC19bdcc7a2020-02-25 21:39:13 +08002777 } else {
2778 dev_err(rtd->card->dev,
2779 "N cpus to M codecs link is not supported yet\n");
2780 return -EINVAL;
2781 }
2782
Kuninori Morimoto467fece2019-07-22 10:36:16 +09002783 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
Stephan Gerholda4877a62020-02-18 11:38:24 +01002784 snd_soc_dai_stream_valid(cpu_dai, cpu_playback))
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002785 *playback = 1;
Kuninori Morimoto467fece2019-07-22 10:36:16 +09002786 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
Stephan Gerholda4877a62020-02-18 11:38:24 +01002787 snd_soc_dai_stream_valid(cpu_dai, cpu_capture))
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002788 *capture = 1;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002789 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002790 }
Sangsu Parka5002312012-01-02 17:15:10 +09002791
Fabio Estevamd6bead02013-08-29 10:32:13 -03002792 if (rtd->dai_link->playback_only) {
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002793 *playback = 1;
2794 *capture = 0;
Fabio Estevamd6bead02013-08-29 10:32:13 -03002795 }
2796
2797 if (rtd->dai_link->capture_only) {
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002798 *playback = 0;
2799 *capture = 1;
Fabio Estevamd6bead02013-08-29 10:32:13 -03002800 }
2801
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002802 return 0;
2803}
2804
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002805static int soc_create_pcm(struct snd_pcm **pcm,
2806 struct snd_soc_pcm_runtime *rtd,
2807 int playback, int capture, int num)
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002808{
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002809 char new_name[64];
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002810 int ret;
Kuninori Morimoto7fc6beb2021-01-22 10:13:38 +09002811
Liam Girdwood01d75842012-04-25 12:12:49 +01002812 /* create the PCM */
Jerome Bruneta3420312019-07-25 18:59:47 +02002813 if (rtd->dai_link->params) {
2814 snprintf(new_name, sizeof(new_name), "codec2codec(%s)",
2815 rtd->dai_link->stream_name);
2816
2817 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002818 playback, capture, pcm);
Jerome Bruneta3420312019-07-25 18:59:47 +02002819 } else if (rtd->dai_link->no_pcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002820 snprintf(new_name, sizeof(new_name), "(%s)",
2821 rtd->dai_link->stream_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002822
Liam Girdwood01d75842012-04-25 12:12:49 +01002823 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002824 playback, capture, pcm);
Liam Girdwood01d75842012-04-25 12:12:49 +01002825 } else {
2826 if (rtd->dai_link->dynamic)
2827 snprintf(new_name, sizeof(new_name), "%s (*)",
2828 rtd->dai_link->stream_name);
2829 else
2830 snprintf(new_name, sizeof(new_name), "%s %s-%d",
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002831 rtd->dai_link->stream_name,
Kuninori Morimoto6fb89442021-03-09 10:07:48 +09002832 soc_codec_dai_name(rtd), num);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002833
Liam Girdwood01d75842012-04-25 12:12:49 +01002834 ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002835 capture, pcm);
Liam Girdwood01d75842012-04-25 12:12:49 +01002836 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01002837 if (ret < 0) {
Pierre-Louis Bossart799827a2020-06-12 15:40:49 -05002838 dev_err(rtd->card->dev, "ASoC: can't create pcm %s for dailink %s: %d\n",
2839 new_name, rtd->dai_link->name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002840 return ret;
2841 }
Liam Girdwood103d84a2012-11-19 14:39:15 +00002842 dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002843
Kuninori Morimoto2b391232021-01-22 10:13:43 +09002844 return 0;
2845}
2846
2847/* create a new pcm */
2848int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
2849{
2850 struct snd_soc_component *component;
2851 struct snd_pcm *pcm;
2852 int ret = 0, playback = 0, capture = 0;
2853 int i;
2854
2855 ret = soc_get_playback_capture(rtd, &playback, &capture);
2856 if (ret < 0)
2857 return ret;
2858
2859 ret = soc_create_pcm(&pcm, rtd, playback, capture, num);
2860 if (ret < 0)
2861 return ret;
2862
Liam Girdwoodddee6272011-06-09 14:45:53 +01002863 /* DAPM dai link stream work */
Jerome Bruneta3420312019-07-25 18:59:47 +02002864 if (rtd->dai_link->params)
Curtis Malainey4bf2e382019-12-03 09:30:07 -08002865 rtd->close_delayed_work_func = codec2codec_close_delayed_work;
Jerome Bruneta3420312019-07-25 18:59:47 +02002866 else
Kuninori Morimoto83f94a22020-01-10 11:36:17 +09002867 rtd->close_delayed_work_func = snd_soc_close_delayed_work;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002868
2869 rtd->pcm = pcm;
Kuninori Morimotoe04e7b82021-01-22 10:13:32 +09002870 pcm->nonatomic = rtd->dai_link->nonatomic;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002871 pcm->private_data = rtd;
Liam Girdwood01d75842012-04-25 12:12:49 +01002872
Jerome Bruneta3420312019-07-25 18:59:47 +02002873 if (rtd->dai_link->no_pcm || rtd->dai_link->params) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002874 if (playback)
2875 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
2876 if (capture)
2877 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
2878 goto out;
2879 }
2880
2881 /* ASoC PCM operations */
2882 if (rtd->dai_link->dynamic) {
2883 rtd->ops.open = dpcm_fe_dai_open;
2884 rtd->ops.hw_params = dpcm_fe_dai_hw_params;
2885 rtd->ops.prepare = dpcm_fe_dai_prepare;
2886 rtd->ops.trigger = dpcm_fe_dai_trigger;
2887 rtd->ops.hw_free = dpcm_fe_dai_hw_free;
2888 rtd->ops.close = dpcm_fe_dai_close;
2889 rtd->ops.pointer = soc_pcm_pointer;
2890 } else {
2891 rtd->ops.open = soc_pcm_open;
2892 rtd->ops.hw_params = soc_pcm_hw_params;
2893 rtd->ops.prepare = soc_pcm_prepare;
2894 rtd->ops.trigger = soc_pcm_trigger;
2895 rtd->ops.hw_free = soc_pcm_hw_free;
2896 rtd->ops.close = soc_pcm_close;
2897 rtd->ops.pointer = soc_pcm_pointer;
2898 }
2899
Kuninori Morimoto613fb502020-01-10 11:35:21 +09002900 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto2b544dd2019-10-15 12:59:31 +09002901 const struct snd_soc_component_driver *drv = component->driver;
Kuninori Morimotob8135862017-10-11 01:37:23 +00002902
Takashi Iwai3b1c9522019-11-21 20:07:08 +01002903 if (drv->ioctl)
2904 rtd->ops.ioctl = snd_soc_pcm_component_ioctl;
Takashi Iwai1e5ddb62019-11-21 20:07:09 +01002905 if (drv->sync_stop)
2906 rtd->ops.sync_stop = snd_soc_pcm_component_sync_stop;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002907 if (drv->copy_user)
Kuninori Morimoto82d81f52019-07-26 13:51:56 +09002908 rtd->ops.copy_user = snd_soc_pcm_component_copy_user;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002909 if (drv->page)
Kuninori Morimoto9c712e42019-07-26 13:52:00 +09002910 rtd->ops.page = snd_soc_pcm_component_page;
Kuninori Morimotoe9067bb2019-10-02 14:35:13 +09002911 if (drv->mmap)
Kuninori Morimoto205875e2019-07-26 13:52:04 +09002912 rtd->ops.mmap = snd_soc_pcm_component_mmap;
Shengjiu Wang8bdfc042021-03-12 10:38:40 +08002913 if (drv->ack)
2914 rtd->ops.ack = snd_soc_pcm_component_ack;
Kuninori Morimotob8135862017-10-11 01:37:23 +00002915 }
2916
Liam Girdwoodddee6272011-06-09 14:45:53 +01002917 if (playback)
Liam Girdwood01d75842012-04-25 12:12:49 +01002918 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002919
2920 if (capture)
Liam Girdwood01d75842012-04-25 12:12:49 +01002921 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002922
Kuninori Morimotob2b2afb2019-11-18 10:50:32 +09002923 ret = snd_soc_pcm_component_new(rtd);
Kuninori Morimoto60adbd82021-03-15 09:58:41 +09002924 if (ret < 0)
Kuninori Morimoto74842912019-07-26 13:52:08 +09002925 return ret;
Johan Hovoldc641e5b2017-07-12 17:55:29 +02002926
Takashi Iwai3d21ef02019-01-11 15:58:39 +01002927 pcm->no_device_suspend = true;
Liam Girdwood01d75842012-04-25 12:12:49 +01002928out:
Pierre-Louis Bossart1d5cd522020-06-12 15:40:50 -05002929 dev_dbg(rtd->card->dev, "%s <-> %s mapping ok\n",
Kuninori Morimoto6fb89442021-03-09 10:07:48 +09002930 soc_codec_dai_name(rtd), soc_cpu_dai_name(rtd));
Liam Girdwoodddee6272011-06-09 14:45:53 +01002931 return ret;
2932}
Liam Girdwood01d75842012-04-25 12:12:49 +01002933
2934/* is the current PCM operation for this FE ? */
2935int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream)
2936{
2937 if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE)
2938 return 1;
2939 return 0;
2940}
2941EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update);
2942
2943/* is the current PCM operation for this BE ? */
2944int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
2945 struct snd_soc_pcm_runtime *be, int stream)
2946{
2947 if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) ||
2948 ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) &&
2949 be->dpcm[stream].runtime_update))
2950 return 1;
2951 return 0;
2952}
2953EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update);
2954
2955/* get the substream for this BE */
2956struct snd_pcm_substream *
2957 snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream)
2958{
2959 return be->pcm->streams[stream].substream;
2960}
2961EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream);
2962
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002963static int snd_soc_dpcm_check_state(struct snd_soc_pcm_runtime *fe,
2964 struct snd_soc_pcm_runtime *be,
2965 int stream,
2966 const enum snd_soc_dpcm_state *states,
2967 int num_states)
Liam Girdwood01d75842012-04-25 12:12:49 +01002968{
2969 struct snd_soc_dpcm *dpcm;
2970 int state;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002971 int ret = 1;
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002972 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01002973
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00002974 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002975
2976 if (dpcm->fe == fe)
2977 continue;
2978
2979 state = dpcm->fe->dpcm[stream].state;
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002980 for (i = 0; i < num_states; i++) {
2981 if (state == states[i]) {
2982 ret = 0;
2983 break;
2984 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002985 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002986 }
2987
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002988 /* it's safe to do this BE DAI */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002989 return ret;
Liam Girdwood01d75842012-04-25 12:12:49 +01002990}
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09002991
2992/*
2993 * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE
2994 * are not running, paused or suspended for the specified stream direction.
2995 */
2996int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
2997 struct snd_soc_pcm_runtime *be, int stream)
2998{
2999 const enum snd_soc_dpcm_state state[] = {
3000 SND_SOC_DPCM_STATE_START,
3001 SND_SOC_DPCM_STATE_PAUSED,
3002 SND_SOC_DPCM_STATE_SUSPEND,
3003 };
3004
3005 return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
3006}
Liam Girdwood01d75842012-04-25 12:12:49 +01003007EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop);
3008
3009/*
3010 * We can only change hw params a BE DAI if any of it's FE are not prepared,
3011 * running, paused or suspended for the specified stream direction.
3012 */
3013int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
3014 struct snd_soc_pcm_runtime *be, int stream)
3015{
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09003016 const enum snd_soc_dpcm_state state[] = {
3017 SND_SOC_DPCM_STATE_START,
3018 SND_SOC_DPCM_STATE_PAUSED,
3019 SND_SOC_DPCM_STATE_SUSPEND,
3020 SND_SOC_DPCM_STATE_PREPARE,
3021 };
Liam Girdwood01d75842012-04-25 12:12:49 +01003022
Kuninori Morimoto085d22b2020-02-17 17:28:07 +09003023 return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
Liam Girdwood01d75842012-04-25 12:12:49 +01003024}
3025EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);