blob: 4a7096a22b28836c818a70f3e5a79a49d8d853db [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>
Ranjani Sridharan52034ad2019-04-05 09:57:09 -070018#include <linux/module.h>
Liam Girdwoodddee6272011-06-09 14:45:53 +010019#include <linux/slab.h>
20#include <linux/workqueue.h>
Liam Girdwood01d75842012-04-25 12:12:49 +010021#include <linux/export.h>
Liam Girdwoodf86dcef2012-04-25 12:12:50 +010022#include <linux/debugfs.h>
Liam Girdwoodddee6272011-06-09 14:45:53 +010023#include <sound/core.h>
24#include <sound/pcm.h>
25#include <sound/pcm_params.h>
26#include <sound/soc.h>
Liam Girdwood01d75842012-04-25 12:12:49 +010027#include <sound/soc-dpcm.h>
Liam Girdwoodddee6272011-06-09 14:45:53 +010028#include <sound/initval.h>
29
Liam Girdwood01d75842012-04-25 12:12:49 +010030#define DPCM_MAX_BE_USERS 8
31
Ricard Wanderlofcde79032015-08-24 14:16:51 +020032/*
33 * snd_soc_dai_stream_valid() - check if a DAI supports the given stream
34 *
35 * Returns true if the DAI supports the indicated stream type.
36 */
37static bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream)
38{
39 struct snd_soc_pcm_stream *codec_stream;
40
41 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
42 codec_stream = &dai->driver->playback;
43 else
44 codec_stream = &dai->driver->capture;
45
Jerome Brunet6a7c59c2019-04-29 11:47:49 +020046 /* If the codec specifies any channels at all, it supports the stream */
47 return codec_stream->channels_min;
Ricard Wanderlofcde79032015-08-24 14:16:51 +020048}
49
Lars-Peter Clausen90996f42013-05-14 11:05:30 +020050/**
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010051 * snd_soc_runtime_activate() - Increment active count for PCM runtime components
52 * @rtd: ASoC PCM runtime that is activated
53 * @stream: Direction of the PCM stream
54 *
55 * Increments the active count for all the DAIs and components attached to a PCM
56 * runtime. Should typically be called when a stream is opened.
57 *
58 * Must be called with the rtd->pcm_mutex being held
59 */
60void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream)
61{
62 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +000063 struct snd_soc_dai *codec_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +020064 int i;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010065
66 lockdep_assert_held(&rtd->pcm_mutex);
67
68 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
69 cpu_dai->playback_active++;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +000070 for_each_rtd_codec_dai(rtd, i, codec_dai)
71 codec_dai->playback_active++;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010072 } else {
73 cpu_dai->capture_active++;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +000074 for_each_rtd_codec_dai(rtd, i, codec_dai)
75 codec_dai->capture_active++;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010076 }
77
78 cpu_dai->active++;
Lars-Peter Clausencdde4cc2014-03-05 13:17:47 +010079 cpu_dai->component->active++;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +000080 for_each_rtd_codec_dai(rtd, i, codec_dai) {
81 codec_dai->active++;
82 codec_dai->component->active++;
Benoit Cousson2e5894d2014-07-08 23:19:35 +020083 }
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010084}
85
86/**
87 * snd_soc_runtime_deactivate() - Decrement active count for PCM runtime components
88 * @rtd: ASoC PCM runtime that is deactivated
89 * @stream: Direction of the PCM stream
90 *
91 * Decrements the active count for all the DAIs and components attached to a PCM
92 * runtime. Should typically be called when a stream is closed.
93 *
94 * Must be called with the rtd->pcm_mutex being held
95 */
96void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream)
97{
98 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +000099 struct snd_soc_dai *codec_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200100 int i;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100101
102 lockdep_assert_held(&rtd->pcm_mutex);
103
104 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
105 cpu_dai->playback_active--;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000106 for_each_rtd_codec_dai(rtd, i, codec_dai)
107 codec_dai->playback_active--;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100108 } else {
109 cpu_dai->capture_active--;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000110 for_each_rtd_codec_dai(rtd, i, codec_dai)
111 codec_dai->capture_active--;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100112 }
113
114 cpu_dai->active--;
Lars-Peter Clausencdde4cc2014-03-05 13:17:47 +0100115 cpu_dai->component->active--;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000116 for_each_rtd_codec_dai(rtd, i, codec_dai) {
117 codec_dai->component->active--;
118 codec_dai->active--;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200119 }
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100120}
121
122/**
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100123 * snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay
124 * @rtd: The ASoC PCM runtime that should be checked.
125 *
126 * This function checks whether the power down delay should be ignored for a
127 * specific PCM runtime. Returns true if the delay is 0, if it the DAI link has
128 * been configured to ignore the delay, or if none of the components benefits
129 * from having the delay.
130 */
131bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
132{
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000133 struct snd_soc_rtdcom_list *rtdcom;
134 struct snd_soc_component *component;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200135 bool ignore = true;
136
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100137 if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
138 return true;
139
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000140 for_each_rtdcom(rtd, rtdcom) {
141 component = rtdcom->component;
142
Kuninori Morimoto72c38182018-01-19 05:21:19 +0000143 ignore &= !component->driver->use_pmdown_time;
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000144 }
145
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000146 return ignore;
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100147}
148
149/**
Lars-Peter Clausen90996f42013-05-14 11:05:30 +0200150 * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
151 * @substream: the pcm substream
152 * @hw: the hardware parameters
153 *
154 * Sets the substream runtime hardware parameters.
155 */
156int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
157 const struct snd_pcm_hardware *hw)
158{
159 struct snd_pcm_runtime *runtime = substream->runtime;
160 runtime->hw.info = hw->info;
161 runtime->hw.formats = hw->formats;
162 runtime->hw.period_bytes_min = hw->period_bytes_min;
163 runtime->hw.period_bytes_max = hw->period_bytes_max;
164 runtime->hw.periods_min = hw->periods_min;
165 runtime->hw.periods_max = hw->periods_max;
166 runtime->hw.buffer_bytes_max = hw->buffer_bytes_max;
167 runtime->hw.fifo_size = hw->fifo_size;
168 return 0;
169}
170EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
171
Liam Girdwood01d75842012-04-25 12:12:49 +0100172/* DPCM stream event, send event to FE and all active BEs. */
Liam Girdwood23607022014-01-17 17:03:55 +0000173int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
Liam Girdwood01d75842012-04-25 12:12:49 +0100174 int event)
175{
176 struct snd_soc_dpcm *dpcm;
177
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +0000178 for_each_dpcm_be(fe, dir, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +0100179
180 struct snd_soc_pcm_runtime *be = dpcm->be;
181
Liam Girdwood103d84a2012-11-19 14:39:15 +0000182 dev_dbg(be->dev, "ASoC: BE %s event %d dir %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +0100183 be->dai_link->name, event, dir);
184
Banajit Goswamib1cd2e32017-07-14 23:15:05 -0700185 if ((event == SND_SOC_DAPM_STREAM_STOP) &&
186 (be->dpcm[dir].users >= 1))
187 continue;
188
Liam Girdwood01d75842012-04-25 12:12:49 +0100189 snd_soc_dapm_stream_event(be, dir, event);
190 }
191
192 snd_soc_dapm_stream_event(fe, dir, event);
193
194 return 0;
195}
196
Dong Aisheng17841022011-08-29 17:15:14 +0800197static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
198 struct snd_soc_dai *soc_dai)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100199{
200 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100201 int ret;
202
Nicolin Chen3635bf02013-11-13 18:56:24 +0800203 if (soc_dai->rate && (soc_dai->driver->symmetric_rates ||
204 rtd->dai_link->symmetric_rates)) {
205 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n",
206 soc_dai->rate);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100207
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200208 ret = snd_pcm_hw_constraint_single(substream->runtime,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800209 SNDRV_PCM_HW_PARAM_RATE,
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200210 soc_dai->rate);
Nicolin Chen3635bf02013-11-13 18:56:24 +0800211 if (ret < 0) {
212 dev_err(soc_dai->dev,
213 "ASoC: Unable to apply rate constraint: %d\n",
214 ret);
215 return ret;
216 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100217 }
218
Nicolin Chen3635bf02013-11-13 18:56:24 +0800219 if (soc_dai->channels && (soc_dai->driver->symmetric_channels ||
220 rtd->dai_link->symmetric_channels)) {
221 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d channel(s)\n",
222 soc_dai->channels);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100223
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200224 ret = snd_pcm_hw_constraint_single(substream->runtime,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800225 SNDRV_PCM_HW_PARAM_CHANNELS,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800226 soc_dai->channels);
227 if (ret < 0) {
228 dev_err(soc_dai->dev,
229 "ASoC: Unable to apply channel symmetry constraint: %d\n",
230 ret);
231 return ret;
232 }
233 }
234
235 if (soc_dai->sample_bits && (soc_dai->driver->symmetric_samplebits ||
236 rtd->dai_link->symmetric_samplebits)) {
237 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d sample bits\n",
238 soc_dai->sample_bits);
239
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200240 ret = snd_pcm_hw_constraint_single(substream->runtime,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800241 SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800242 soc_dai->sample_bits);
243 if (ret < 0) {
244 dev_err(soc_dai->dev,
245 "ASoC: Unable to apply sample bits symmetry constraint: %d\n",
246 ret);
247 return ret;
248 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100249 }
250
251 return 0;
252}
253
Nicolin Chen3635bf02013-11-13 18:56:24 +0800254static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
255 struct snd_pcm_hw_params *params)
256{
257 struct snd_soc_pcm_runtime *rtd = substream->private_data;
258 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000259 struct snd_soc_dai *codec_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200260 unsigned int rate, channels, sample_bits, symmetry, i;
Nicolin Chen3635bf02013-11-13 18:56:24 +0800261
262 rate = params_rate(params);
263 channels = params_channels(params);
264 sample_bits = snd_pcm_format_physical_width(params_format(params));
265
266 /* reject unmatched parameters when applying symmetry */
267 symmetry = cpu_dai->driver->symmetric_rates ||
Nicolin Chen3635bf02013-11-13 18:56:24 +0800268 rtd->dai_link->symmetric_rates;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200269
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000270 for_each_rtd_codec_dai(rtd, i, codec_dai)
271 symmetry |= codec_dai->driver->symmetric_rates;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200272
Nicolin Chen3635bf02013-11-13 18:56:24 +0800273 if (symmetry && cpu_dai->rate && cpu_dai->rate != rate) {
274 dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n",
275 cpu_dai->rate, rate);
276 return -EINVAL;
277 }
278
279 symmetry = cpu_dai->driver->symmetric_channels ||
Nicolin Chen3635bf02013-11-13 18:56:24 +0800280 rtd->dai_link->symmetric_channels;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200281
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000282 for_each_rtd_codec_dai(rtd, i, codec_dai)
283 symmetry |= codec_dai->driver->symmetric_channels;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200284
Nicolin Chen3635bf02013-11-13 18:56:24 +0800285 if (symmetry && cpu_dai->channels && cpu_dai->channels != channels) {
286 dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n",
287 cpu_dai->channels, channels);
288 return -EINVAL;
289 }
290
291 symmetry = cpu_dai->driver->symmetric_samplebits ||
Nicolin Chen3635bf02013-11-13 18:56:24 +0800292 rtd->dai_link->symmetric_samplebits;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200293
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000294 for_each_rtd_codec_dai(rtd, i, codec_dai)
295 symmetry |= codec_dai->driver->symmetric_samplebits;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200296
Nicolin Chen3635bf02013-11-13 18:56:24 +0800297 if (symmetry && cpu_dai->sample_bits && cpu_dai->sample_bits != sample_bits) {
298 dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n",
299 cpu_dai->sample_bits, sample_bits);
300 return -EINVAL;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100301 }
302
303 return 0;
304}
305
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100306static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream)
307{
308 struct snd_soc_pcm_runtime *rtd = substream->private_data;
309 struct snd_soc_dai_driver *cpu_driver = rtd->cpu_dai->driver;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100310 struct snd_soc_dai_link *link = rtd->dai_link;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000311 struct snd_soc_dai *codec_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200312 unsigned int symmetry, i;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100313
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200314 symmetry = cpu_driver->symmetric_rates || link->symmetric_rates ||
315 cpu_driver->symmetric_channels || link->symmetric_channels ||
316 cpu_driver->symmetric_samplebits || link->symmetric_samplebits;
317
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000318 for_each_rtd_codec_dai(rtd, i, codec_dai)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200319 symmetry = symmetry ||
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000320 codec_dai->driver->symmetric_rates ||
321 codec_dai->driver->symmetric_channels ||
322 codec_dai->driver->symmetric_samplebits;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200323
324 return symmetry;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100325}
326
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200327static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits)
Mark Brown58ba9b22012-01-16 18:38:51 +0000328{
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200329 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Takashi Iwaic6068d32014-12-31 17:10:34 +0100330 int ret;
Mark Brown58ba9b22012-01-16 18:38:51 +0000331
332 if (!bits)
333 return;
334
Lars-Peter Clausen0e2a3752014-12-29 18:43:38 +0100335 ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 0, bits);
336 if (ret != 0)
337 dev_warn(rtd->dev, "ASoC: Failed to set MSB %d: %d\n",
338 bits, ret);
Mark Brown58ba9b22012-01-16 18:38:51 +0000339}
340
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200341static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200342{
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200343 struct snd_soc_pcm_runtime *rtd = substream->private_data;
344 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200345 struct snd_soc_dai *codec_dai;
346 int i;
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200347 unsigned int bits = 0, cpu_bits;
348
349 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000350 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200351 if (codec_dai->driver->playback.sig_bits == 0) {
352 bits = 0;
353 break;
354 }
355 bits = max(codec_dai->driver->playback.sig_bits, bits);
356 }
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200357 cpu_bits = cpu_dai->driver->playback.sig_bits;
358 } else {
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000359 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Daniel Mack5e63dfc2014-10-07 14:33:46 +0200360 if (codec_dai->driver->capture.sig_bits == 0) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200361 bits = 0;
362 break;
363 }
364 bits = max(codec_dai->driver->capture.sig_bits, bits);
365 }
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200366 cpu_bits = cpu_dai->driver->capture.sig_bits;
367 }
368
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200369 soc_pcm_set_msb(substream, bits);
370 soc_pcm_set_msb(substream, cpu_bits);
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200371}
372
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200373static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200374{
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200375 struct snd_pcm_runtime *runtime = substream->runtime;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100376 struct snd_pcm_hardware *hw = &runtime->hw;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200377 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000378 struct snd_soc_dai *codec_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200379 struct snd_soc_dai_driver *cpu_dai_drv = rtd->cpu_dai->driver;
380 struct snd_soc_dai_driver *codec_dai_drv;
381 struct snd_soc_pcm_stream *codec_stream;
382 struct snd_soc_pcm_stream *cpu_stream;
383 unsigned int chan_min = 0, chan_max = UINT_MAX;
384 unsigned int rate_min = 0, rate_max = UINT_MAX;
385 unsigned int rates = UINT_MAX;
386 u64 formats = ULLONG_MAX;
387 int i;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100388
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200389 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
390 cpu_stream = &cpu_dai_drv->playback;
Lars-Peter Clausen16d7ea92014-01-06 14:19:16 +0100391 else
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200392 cpu_stream = &cpu_dai_drv->capture;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100393
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200394 /* first calculate min/max only for CODECs in the DAI link */
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000395 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200396
397 /*
398 * Skip CODECs which don't support the current stream type.
399 * Otherwise, since the rate, channel, and format values will
400 * zero in that case, we would have no usable settings left,
401 * causing the resulting setup to fail.
402 * At least one CODEC should match, otherwise we should have
403 * bailed out on a higher level, since there would be no
404 * CODEC to support the transfer direction in that case.
405 */
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000406 if (!snd_soc_dai_stream_valid(codec_dai,
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200407 substream->stream))
408 continue;
409
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000410 codec_dai_drv = codec_dai->driver;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200411 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
412 codec_stream = &codec_dai_drv->playback;
413 else
414 codec_stream = &codec_dai_drv->capture;
415 chan_min = max(chan_min, codec_stream->channels_min);
416 chan_max = min(chan_max, codec_stream->channels_max);
417 rate_min = max(rate_min, codec_stream->rate_min);
418 rate_max = min_not_zero(rate_max, codec_stream->rate_max);
419 formats &= codec_stream->formats;
420 rates = snd_pcm_rate_mask_intersect(codec_stream->rates, rates);
421 }
422
423 /*
424 * chan min/max cannot be enforced if there are multiple CODEC DAIs
425 * connected to a single CPU DAI, use CPU DAI's directly and let
426 * channel allocation be fixed up later
427 */
428 if (rtd->num_codecs > 1) {
429 chan_min = cpu_stream->channels_min;
430 chan_max = cpu_stream->channels_max;
431 }
432
433 hw->channels_min = max(chan_min, cpu_stream->channels_min);
434 hw->channels_max = min(chan_max, cpu_stream->channels_max);
435 if (hw->formats)
436 hw->formats &= formats & cpu_stream->formats;
437 else
438 hw->formats = formats & cpu_stream->formats;
439 hw->rates = snd_pcm_rate_mask_intersect(rates, cpu_stream->rates);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100440
441 snd_pcm_limit_hw_rates(runtime);
442
443 hw->rate_min = max(hw->rate_min, cpu_stream->rate_min);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200444 hw->rate_min = max(hw->rate_min, rate_min);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100445 hw->rate_max = min_not_zero(hw->rate_max, cpu_stream->rate_max);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200446 hw->rate_max = min_not_zero(hw->rate_max, rate_max);
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200447}
448
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900449static int soc_pcm_components_open(struct snd_pcm_substream *substream,
450 struct snd_soc_component **last)
451{
452 struct snd_soc_pcm_runtime *rtd = substream->private_data;
453 struct snd_soc_rtdcom_list *rtdcom;
454 struct snd_soc_component *component;
455 int ret = 0;
456
457 for_each_rtdcom(rtd, rtdcom) {
458 component = rtdcom->component;
459 *last = component;
460
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900461 if (component->driver->module_get_upon_open &&
462 !try_module_get(component->dev->driver->owner)) {
463 dev_err(component->dev,
464 "ASoC: can't get module %s\n",
465 component->name);
466 return -ENODEV;
467 }
468
Kuninori Morimoto428306c2019-05-20 10:42:39 +0900469 if (!component->driver->ops ||
470 !component->driver->ops->open)
471 continue;
472
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900473 ret = component->driver->ops->open(substream);
474 if (ret < 0) {
475 dev_err(component->dev,
476 "ASoC: can't open component %s: %d\n",
477 component->name, ret);
478 return ret;
479 }
480 }
481 *last = NULL;
482 return 0;
483}
484
Charles Keepax244e2932018-06-19 16:22:09 +0100485static int soc_pcm_components_close(struct snd_pcm_substream *substream,
486 struct snd_soc_component *last)
487{
488 struct snd_soc_pcm_runtime *rtd = substream->private_data;
489 struct snd_soc_rtdcom_list *rtdcom;
490 struct snd_soc_component *component;
491
492 for_each_rtdcom(rtd, rtdcom) {
493 component = rtdcom->component;
494
495 if (component == last)
496 break;
497
Kuninori Morimoto428306c2019-05-20 10:42:39 +0900498 if (component->driver->ops &&
499 component->driver->ops->close)
500 component->driver->ops->close(substream);
Ranjani Sridharan52034ad2019-04-05 09:57:09 -0700501
502 if (component->driver->module_get_upon_open)
503 module_put(component->dev->driver->owner);
Charles Keepax244e2932018-06-19 16:22:09 +0100504 }
505
506 return 0;
507}
508
Mark Brown58ba9b22012-01-16 18:38:51 +0000509/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100510 * Called by ALSA when a PCM substream is opened, the runtime->hw record is
511 * then initialized and any private data can be allocated. This also calls
Charles Keepaxef050be2018-04-24 16:39:02 +0100512 * startup for the cpu DAI, component, machine and codec DAI.
Liam Girdwoodddee6272011-06-09 14:45:53 +0100513 */
514static int soc_pcm_open(struct snd_pcm_substream *substream)
515{
516 struct snd_soc_pcm_runtime *rtd = substream->private_data;
517 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000518 struct snd_soc_component *component;
519 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100520 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200521 struct snd_soc_dai *codec_dai;
522 const char *codec_dai_name = "multicodec";
Charles Keepax244e2932018-06-19 16:22:09 +0100523 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100524
Nicolin Chen988e8cc2013-11-04 14:57:31 +0800525 pinctrl_pm_select_default_state(cpu_dai->dev);
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000526 for_each_rtd_codec_dai(rtd, i, codec_dai)
527 pinctrl_pm_select_default_state(codec_dai->dev);
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000528
529 for_each_rtdcom(rtd, rtdcom) {
530 component = rtdcom->component;
531
532 pm_runtime_get_sync(component->dev);
533 }
Mark Brownd6652ef2011-12-03 20:14:31 +0000534
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100535 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100536
537 /* startup the audio subsystem */
Kuninori Morimoto9900a422017-09-25 01:38:54 +0000538 if (cpu_dai->driver->ops->startup) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100539 ret = cpu_dai->driver->ops->startup(substream, cpu_dai);
540 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000541 dev_err(cpu_dai->dev, "ASoC: can't open interface"
542 " %s: %d\n", cpu_dai->name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100543 goto out;
544 }
545 }
546
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900547 ret = soc_pcm_components_open(substream, &component);
548 if (ret < 0)
549 goto component_err;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000550
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000551 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto9900a422017-09-25 01:38:54 +0000552 if (codec_dai->driver->ops->startup) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200553 ret = codec_dai->driver->ops->startup(substream,
554 codec_dai);
555 if (ret < 0) {
556 dev_err(codec_dai->dev,
557 "ASoC: can't open codec %s: %d\n",
558 codec_dai->name, ret);
559 goto codec_dai_err;
560 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100561 }
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200562
563 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
564 codec_dai->tx_mask = 0;
565 else
566 codec_dai->rx_mask = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100567 }
568
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000569 if (rtd->dai_link->ops->startup) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100570 ret = rtd->dai_link->ops->startup(substream);
571 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000572 pr_err("ASoC: %s startup failed: %d\n",
Mark Brown25bfe662012-02-01 21:30:32 +0000573 rtd->dai_link->name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100574 goto machine_err;
575 }
576 }
577
Liam Girdwood01d75842012-04-25 12:12:49 +0100578 /* Dynamic PCM DAI links compat checks use dynamic capabilities */
579 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm)
580 goto dynamic;
581
Liam Girdwoodddee6272011-06-09 14:45:53 +0100582 /* Check that the codec and cpu DAIs are compatible */
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200583 soc_pcm_init_runtime_hw(substream);
584
585 if (rtd->num_codecs == 1)
586 codec_dai_name = rtd->codec_dai->name;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100587
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100588 if (soc_pcm_has_symmetry(substream))
589 runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
590
Liam Girdwoodddee6272011-06-09 14:45:53 +0100591 ret = -EINVAL;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100592 if (!runtime->hw.rates) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000593 printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200594 codec_dai_name, cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100595 goto config_err;
596 }
597 if (!runtime->hw.formats) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000598 printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200599 codec_dai_name, cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100600 goto config_err;
601 }
602 if (!runtime->hw.channels_min || !runtime->hw.channels_max ||
603 runtime->hw.channels_min > runtime->hw.channels_max) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000604 printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200605 codec_dai_name, cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100606 goto config_err;
607 }
608
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200609 soc_pcm_apply_msb(substream);
Mark Brown58ba9b22012-01-16 18:38:51 +0000610
Liam Girdwoodddee6272011-06-09 14:45:53 +0100611 /* Symmetry only applies if we've already got an active stream. */
Dong Aisheng17841022011-08-29 17:15:14 +0800612 if (cpu_dai->active) {
613 ret = soc_pcm_apply_symmetry(substream, cpu_dai);
614 if (ret != 0)
615 goto config_err;
616 }
617
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000618 for_each_rtd_codec_dai(rtd, i, codec_dai) {
619 if (codec_dai->active) {
620 ret = soc_pcm_apply_symmetry(substream, codec_dai);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200621 if (ret != 0)
622 goto config_err;
623 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100624 }
625
Liam Girdwood103d84a2012-11-19 14:39:15 +0000626 pr_debug("ASoC: %s <-> %s info:\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200627 codec_dai_name, cpu_dai->name);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000628 pr_debug("ASoC: rate mask 0x%x\n", runtime->hw.rates);
629 pr_debug("ASoC: min ch %d max ch %d\n", runtime->hw.channels_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100630 runtime->hw.channels_max);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000631 pr_debug("ASoC: min rate %d max rate %d\n", runtime->hw.rate_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100632 runtime->hw.rate_max);
633
Liam Girdwood01d75842012-04-25 12:12:49 +0100634dynamic:
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100635
636 snd_soc_runtime_activate(rtd, substream->stream);
637
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100638 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100639 return 0;
640
641config_err:
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000642 if (rtd->dai_link->ops->shutdown)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100643 rtd->dai_link->ops->shutdown(substream);
644
645machine_err:
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200646 i = rtd->num_codecs;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100647
648codec_dai_err:
Kuninori Morimoto6d11b122018-09-18 01:28:30 +0000649 for_each_rtd_codec_dai_rollback(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200650 if (codec_dai->driver->ops->shutdown)
651 codec_dai->driver->ops->shutdown(substream, codec_dai);
652 }
653
Kuninori Morimotob8135862017-10-11 01:37:23 +0000654component_err:
Charles Keepax244e2932018-06-19 16:22:09 +0100655 soc_pcm_components_close(substream, component);
Kuninori Morimotoe7ecfdb2019-05-13 16:08:33 +0900656
Liam Girdwoodddee6272011-06-09 14:45:53 +0100657 if (cpu_dai->driver->ops->shutdown)
658 cpu_dai->driver->ops->shutdown(substream, cpu_dai);
659out:
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100660 mutex_unlock(&rtd->pcm_mutex);
Mark Brownd6652ef2011-12-03 20:14:31 +0000661
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000662 for_each_rtdcom(rtd, rtdcom) {
663 component = rtdcom->component;
664
665 pm_runtime_mark_last_busy(component->dev);
666 pm_runtime_put_autosuspend(component->dev);
Sanyog Kale3f809782016-01-05 17:14:49 +0530667 }
668
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000669 for_each_rtd_codec_dai(rtd, i, codec_dai) {
670 if (!codec_dai->active)
671 pinctrl_pm_select_sleep_state(codec_dai->dev);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200672 }
Nicolin Chen988e8cc2013-11-04 14:57:31 +0800673 if (!cpu_dai->active)
674 pinctrl_pm_select_sleep_state(cpu_dai->dev);
Mark Brownd6652ef2011-12-03 20:14:31 +0000675
Liam Girdwoodddee6272011-06-09 14:45:53 +0100676 return ret;
677}
678
679/*
680 * Power down the audio subsystem pmdown_time msecs after close is called.
681 * This is to ensure there are no pops or clicks in between any music tracks
682 * due to DAPM power cycling.
683 */
684static void close_delayed_work(struct work_struct *work)
685{
686 struct snd_soc_pcm_runtime *rtd =
687 container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200688 struct snd_soc_dai *codec_dai = rtd->codec_dais[0];
Liam Girdwoodddee6272011-06-09 14:45:53 +0100689
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100690 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100691
Liam Girdwood103d84a2012-11-19 14:39:15 +0000692 dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n",
Liam Girdwoodddee6272011-06-09 14:45:53 +0100693 codec_dai->driver->playback.stream_name,
694 codec_dai->playback_active ? "active" : "inactive",
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600695 rtd->pop_wait ? "yes" : "no");
Liam Girdwoodddee6272011-06-09 14:45:53 +0100696
697 /* are we waiting on this codec DAI stream */
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600698 if (rtd->pop_wait == 1) {
699 rtd->pop_wait = 0;
Mark Brown7bd3a6f2012-02-16 15:03:27 -0800700 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000701 SND_SOC_DAPM_STREAM_STOP);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100702 }
703
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100704 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100705}
706
707/*
708 * Called by ALSA when a PCM substream is closed. Private data can be
Charles Keepaxef050be2018-04-24 16:39:02 +0100709 * freed here. The cpu DAI, codec DAI, machine and components are also
Liam Girdwoodddee6272011-06-09 14:45:53 +0100710 * shutdown.
711 */
Liam Girdwood91d5e6b2011-06-09 17:04:59 +0100712static int soc_pcm_close(struct snd_pcm_substream *substream)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100713{
714 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000715 struct snd_soc_component *component;
716 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100717 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200718 struct snd_soc_dai *codec_dai;
719 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100720
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100721 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100722
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100723 snd_soc_runtime_deactivate(rtd, substream->stream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100724
Dong Aisheng17841022011-08-29 17:15:14 +0800725 /* clear the corresponding DAIs rate when inactive */
726 if (!cpu_dai->active)
727 cpu_dai->rate = 0;
728
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000729 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200730 if (!codec_dai->active)
731 codec_dai->rate = 0;
732 }
Sascha Hauer25b76792011-08-17 09:20:01 +0200733
Ramesh Babuae116012014-10-15 12:34:59 +0530734 snd_soc_dai_digital_mute(cpu_dai, 1, substream->stream);
735
Liam Girdwoodddee6272011-06-09 14:45:53 +0100736 if (cpu_dai->driver->ops->shutdown)
737 cpu_dai->driver->ops->shutdown(substream, cpu_dai);
738
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000739 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200740 if (codec_dai->driver->ops->shutdown)
741 codec_dai->driver->ops->shutdown(substream, codec_dai);
742 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100743
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000744 if (rtd->dai_link->ops->shutdown)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100745 rtd->dai_link->ops->shutdown(substream);
746
Charles Keepax244e2932018-06-19 16:22:09 +0100747 soc_pcm_components_close(substream, NULL);
Kuninori Morimotob8135862017-10-11 01:37:23 +0000748
Liam Girdwoodddee6272011-06-09 14:45:53 +0100749 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100750 if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
Peter Ujfalusi1d69c5c2011-10-14 14:43:33 +0300751 /* powered down playback stream now */
752 snd_soc_dapm_stream_event(rtd,
Mark Brown7bd3a6f2012-02-16 15:03:27 -0800753 SNDRV_PCM_STREAM_PLAYBACK,
Mark Brown7bd3a6f2012-02-16 15:03:27 -0800754 SND_SOC_DAPM_STREAM_STOP);
Peter Ujfalusi1d69c5c2011-10-14 14:43:33 +0300755 } else {
756 /* start delayed pop wq here for playback streams */
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600757 rtd->pop_wait = 1;
Mark Brownd4e1a732013-07-18 11:52:17 +0100758 queue_delayed_work(system_power_efficient_wq,
759 &rtd->delayed_work,
760 msecs_to_jiffies(rtd->pmdown_time));
Peter Ujfalusi1d69c5c2011-10-14 14:43:33 +0300761 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100762 } else {
763 /* capture streams can be powered down now */
Mark Brown7bd3a6f2012-02-16 15:03:27 -0800764 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000765 SND_SOC_DAPM_STREAM_STOP);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100766 }
767
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100768 mutex_unlock(&rtd->pcm_mutex);
Mark Brownd6652ef2011-12-03 20:14:31 +0000769
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000770 for_each_rtdcom(rtd, rtdcom) {
771 component = rtdcom->component;
Sanyog Kale3f809782016-01-05 17:14:49 +0530772
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000773 pm_runtime_mark_last_busy(component->dev);
774 pm_runtime_put_autosuspend(component->dev);
Sanyog Kale3f809782016-01-05 17:14:49 +0530775 }
776
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000777 for_each_rtd_codec_dai(rtd, i, codec_dai) {
778 if (!codec_dai->active)
779 pinctrl_pm_select_sleep_state(codec_dai->dev);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200780 }
Nicolin Chen988e8cc2013-11-04 14:57:31 +0800781 if (!cpu_dai->active)
782 pinctrl_pm_select_sleep_state(cpu_dai->dev);
Mark Brownd6652ef2011-12-03 20:14:31 +0000783
Liam Girdwoodddee6272011-06-09 14:45:53 +0100784 return 0;
785}
786
787/*
788 * Called by ALSA when the PCM substream is prepared, can set format, sample
789 * rate, etc. This function is non atomic and can be called multiple times,
790 * it can refer to the runtime info.
791 */
792static int soc_pcm_prepare(struct snd_pcm_substream *substream)
793{
794 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000795 struct snd_soc_component *component;
796 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100797 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200798 struct snd_soc_dai *codec_dai;
799 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100800
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100801 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100802
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000803 if (rtd->dai_link->ops->prepare) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100804 ret = rtd->dai_link->ops->prepare(substream);
805 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000806 dev_err(rtd->card->dev, "ASoC: machine prepare error:"
807 " %d\n", ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100808 goto out;
809 }
810 }
811
Kuninori Morimotob8135862017-10-11 01:37:23 +0000812 for_each_rtdcom(rtd, rtdcom) {
813 component = rtdcom->component;
814
Kuninori Morimotob8135862017-10-11 01:37:23 +0000815 if (!component->driver->ops ||
816 !component->driver->ops->prepare)
817 continue;
818
819 ret = component->driver->ops->prepare(substream);
820 if (ret < 0) {
821 dev_err(component->dev,
822 "ASoC: platform prepare error: %d\n", ret);
823 goto out;
824 }
825 }
826
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000827 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto9900a422017-09-25 01:38:54 +0000828 if (codec_dai->driver->ops->prepare) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200829 ret = codec_dai->driver->ops->prepare(substream,
830 codec_dai);
831 if (ret < 0) {
832 dev_err(codec_dai->dev,
Jarkko Nikula90cc7f12014-12-23 11:04:41 +0200833 "ASoC: codec DAI prepare error: %d\n",
834 ret);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200835 goto out;
836 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100837 }
838 }
839
Kuninori Morimoto9900a422017-09-25 01:38:54 +0000840 if (cpu_dai->driver->ops->prepare) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100841 ret = cpu_dai->driver->ops->prepare(substream, cpu_dai);
842 if (ret < 0) {
Jarkko Nikula90cc7f12014-12-23 11:04:41 +0200843 dev_err(cpu_dai->dev,
844 "ASoC: cpu DAI prepare error: %d\n", ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100845 goto out;
846 }
847 }
848
849 /* cancel any delayed stream shutdown that is pending */
850 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600851 rtd->pop_wait) {
852 rtd->pop_wait = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100853 cancel_delayed_work(&rtd->delayed_work);
854 }
855
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000856 snd_soc_dapm_stream_event(rtd, substream->stream,
857 SND_SOC_DAPM_STREAM_START);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100858
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000859 for_each_rtd_codec_dai(rtd, i, codec_dai)
860 snd_soc_dai_digital_mute(codec_dai, 0,
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200861 substream->stream);
Ramesh Babuae116012014-10-15 12:34:59 +0530862 snd_soc_dai_digital_mute(cpu_dai, 0, substream->stream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100863
864out:
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100865 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100866 return ret;
867}
868
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200869static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params,
870 unsigned int mask)
871{
872 struct snd_interval *interval;
873 int channels = hweight_long(mask);
874
875 interval = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
876 interval->min = channels;
877 interval->max = channels;
878}
879
Benoit Cousson93e69582014-07-08 23:19:38 +0200880int soc_dai_hw_params(struct snd_pcm_substream *substream,
881 struct snd_pcm_hw_params *params,
882 struct snd_soc_dai *dai)
883{
Liam Girdwooda655de82018-07-02 16:59:54 +0100884 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Benoit Cousson93e69582014-07-08 23:19:38 +0200885 int ret;
886
Liam Girdwooda655de82018-07-02 16:59:54 +0100887 /* perform any topology hw_params fixups before DAI */
888 if (rtd->dai_link->be_hw_params_fixup) {
889 ret = rtd->dai_link->be_hw_params_fixup(rtd, params);
890 if (ret < 0) {
891 dev_err(rtd->dev,
892 "ASoC: hw_params topology fixup failed %d\n",
893 ret);
894 return ret;
895 }
896 }
897
Kuninori Morimoto9900a422017-09-25 01:38:54 +0000898 if (dai->driver->ops->hw_params) {
Benoit Cousson93e69582014-07-08 23:19:38 +0200899 ret = dai->driver->ops->hw_params(substream, params, dai);
900 if (ret < 0) {
901 dev_err(dai->dev, "ASoC: can't set %s hw params: %d\n",
902 dai->name, ret);
903 return ret;
904 }
905 }
906
907 return 0;
908}
909
Charles Keepax244e2932018-06-19 16:22:09 +0100910static int soc_pcm_components_hw_free(struct snd_pcm_substream *substream,
911 struct snd_soc_component *last)
912{
913 struct snd_soc_pcm_runtime *rtd = substream->private_data;
914 struct snd_soc_rtdcom_list *rtdcom;
915 struct snd_soc_component *component;
916
917 for_each_rtdcom(rtd, rtdcom) {
918 component = rtdcom->component;
919
920 if (component == last)
921 break;
922
923 if (!component->driver->ops ||
924 !component->driver->ops->hw_free)
925 continue;
926
927 component->driver->ops->hw_free(substream);
928 }
929
930 return 0;
931}
932
Liam Girdwoodddee6272011-06-09 14:45:53 +0100933/*
934 * Called by ALSA when the hardware params are set by application. This
935 * function can also be called multiple times and can allocate buffers
936 * (using snd_pcm_lib_* ). It's non-atomic.
937 */
938static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
939 struct snd_pcm_hw_params *params)
940{
941 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000942 struct snd_soc_component *component;
943 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100944 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000945 struct snd_soc_dai *codec_dai;
Charles Keepax244e2932018-06-19 16:22:09 +0100946 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100947
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100948 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000949 if (rtd->dai_link->ops->hw_params) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100950 ret = rtd->dai_link->ops->hw_params(substream, params);
951 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000952 dev_err(rtd->card->dev, "ASoC: machine hw_params"
953 " failed: %d\n", ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100954 goto out;
955 }
956 }
957
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000958 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200959 struct snd_pcm_hw_params codec_params;
960
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200961 /*
962 * Skip CODECs which don't support the current stream type,
963 * the idea being that if a CODEC is not used for the currently
964 * set up transfer direction, it should not need to be
965 * configured, especially since the configuration used might
966 * not even be supported by that CODEC. There may be cases
967 * however where a CODEC needs to be set up although it is
968 * actually not being used for the transfer, e.g. if a
969 * capture-only CODEC is acting as an LRCLK and/or BCLK master
970 * for the DAI link including a playback-only CODEC.
971 * If this becomes necessary, we will have to augment the
972 * machine driver setup with information on how to act, so
973 * we can do the right thing here.
974 */
975 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
976 continue;
977
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200978 /* copy params for each codec */
979 codec_params = *params;
980
981 /* fixup params based on TDM slot masks */
Rander Wang570f18b2019-03-08 16:38:57 +0800982 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
983 codec_dai->tx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200984 soc_pcm_codec_params_fixup(&codec_params,
985 codec_dai->tx_mask);
Rander Wang570f18b2019-03-08 16:38:57 +0800986
987 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
988 codec_dai->rx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200989 soc_pcm_codec_params_fixup(&codec_params,
990 codec_dai->rx_mask);
991
Benoit Cousson93e69582014-07-08 23:19:38 +0200992 ret = soc_dai_hw_params(substream, &codec_params, codec_dai);
993 if(ret < 0)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100994 goto codec_err;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200995
996 codec_dai->rate = params_rate(&codec_params);
997 codec_dai->channels = params_channels(&codec_params);
998 codec_dai->sample_bits = snd_pcm_format_physical_width(
999 params_format(&codec_params));
Charles Keepax078a85f2019-01-31 13:30:18 +00001000
1001 snd_soc_dapm_update_dai(substream, &codec_params, codec_dai);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001002 }
1003
Benoit Cousson93e69582014-07-08 23:19:38 +02001004 ret = soc_dai_hw_params(substream, params, cpu_dai);
1005 if (ret < 0)
1006 goto interface_err;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001007
Kuninori Morimotoca58221d2019-05-13 16:07:43 +09001008 /* store the parameters for each DAIs */
1009 cpu_dai->rate = params_rate(params);
1010 cpu_dai->channels = params_channels(params);
1011 cpu_dai->sample_bits =
1012 snd_pcm_format_physical_width(params_format(params));
1013
1014 snd_soc_dapm_update_dai(substream, params, cpu_dai);
1015
Kuninori Morimotob8135862017-10-11 01:37:23 +00001016 for_each_rtdcom(rtd, rtdcom) {
1017 component = rtdcom->component;
1018
Kuninori Morimotob8135862017-10-11 01:37:23 +00001019 if (!component->driver->ops ||
1020 !component->driver->ops->hw_params)
1021 continue;
1022
Charles Keepax244e2932018-06-19 16:22:09 +01001023 ret = component->driver->ops->hw_params(substream, params);
1024 if (ret < 0) {
Kuninori Morimotob8135862017-10-11 01:37:23 +00001025 dev_err(component->dev,
1026 "ASoC: %s hw params failed: %d\n",
Charles Keepax244e2932018-06-19 16:22:09 +01001027 component->name, ret);
1028 goto component_err;
Kuninori Morimotob8135862017-10-11 01:37:23 +00001029 }
1030 }
Charles Keepax244e2932018-06-19 16:22:09 +01001031 component = NULL;
Kuninori Morimotob8135862017-10-11 01:37:23 +00001032
jiada wang957ce0c2017-09-20 15:25:30 +09001033 ret = soc_pcm_params_symmetry(substream, params);
1034 if (ret)
Kuninori Morimotob8135862017-10-11 01:37:23 +00001035 goto component_err;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001036out:
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +01001037 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001038 return ret;
1039
Kuninori Morimotob8135862017-10-11 01:37:23 +00001040component_err:
Charles Keepax244e2932018-06-19 16:22:09 +01001041 soc_pcm_components_hw_free(substream, component);
Kuninori Morimotob8135862017-10-11 01:37:23 +00001042
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001043 if (cpu_dai->driver->ops->hw_free)
Liam Girdwoodddee6272011-06-09 14:45:53 +01001044 cpu_dai->driver->ops->hw_free(substream, cpu_dai);
Kuninori Morimoto2371abd2019-05-13 16:07:52 +09001045 cpu_dai->rate = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001046
1047interface_err:
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001048 i = rtd->num_codecs;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001049
1050codec_err:
Kuninori Morimoto6d11b122018-09-18 01:28:30 +00001051 for_each_rtd_codec_dai_rollback(rtd, i, codec_dai) {
Jerome Brunetf47b9ad2019-04-29 11:47:50 +02001052 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
1053 continue;
1054
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001055 if (codec_dai->driver->ops->hw_free)
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001056 codec_dai->driver->ops->hw_free(substream, codec_dai);
1057 codec_dai->rate = 0;
1058 }
1059
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +00001060 if (rtd->dai_link->ops->hw_free)
Liam Girdwoodddee6272011-06-09 14:45:53 +01001061 rtd->dai_link->ops->hw_free(substream);
1062
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +01001063 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001064 return ret;
1065}
1066
1067/*
1068 * Frees resources allocated by hw_params, can be called multiple times
1069 */
1070static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
1071{
1072 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001073 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001074 struct snd_soc_dai *codec_dai;
Nicolin Chen7f62b6e2013-12-04 11:18:36 +08001075 bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001076 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001077
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +01001078 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001079
Nicolin Chend3383422013-11-20 18:37:09 +08001080 /* clear the corresponding DAIs parameters when going to be inactive */
1081 if (cpu_dai->active == 1) {
1082 cpu_dai->rate = 0;
1083 cpu_dai->channels = 0;
1084 cpu_dai->sample_bits = 0;
1085 }
1086
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001087 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001088 if (codec_dai->active == 1) {
1089 codec_dai->rate = 0;
1090 codec_dai->channels = 0;
1091 codec_dai->sample_bits = 0;
1092 }
Nicolin Chend3383422013-11-20 18:37:09 +08001093 }
1094
Liam Girdwoodddee6272011-06-09 14:45:53 +01001095 /* apply codec digital mute */
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001096 for_each_rtd_codec_dai(rtd, i, codec_dai) {
1097 if ((playback && codec_dai->playback_active == 1) ||
1098 (!playback && codec_dai->capture_active == 1))
1099 snd_soc_dai_digital_mute(codec_dai, 1,
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001100 substream->stream);
1101 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01001102
1103 /* free any machine hw params */
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +00001104 if (rtd->dai_link->ops->hw_free)
Liam Girdwoodddee6272011-06-09 14:45:53 +01001105 rtd->dai_link->ops->hw_free(substream);
1106
Kuninori Morimotob8135862017-10-11 01:37:23 +00001107 /* free any component resources */
Charles Keepax244e2932018-06-19 16:22:09 +01001108 soc_pcm_components_hw_free(substream, NULL);
Kuninori Morimotob8135862017-10-11 01:37:23 +00001109
Liam Girdwoodddee6272011-06-09 14:45:53 +01001110 /* now free hw params for the DAIs */
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001111 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Jerome Brunetf47b9ad2019-04-29 11:47:50 +02001112 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
1113 continue;
1114
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001115 if (codec_dai->driver->ops->hw_free)
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001116 codec_dai->driver->ops->hw_free(substream, codec_dai);
1117 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01001118
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001119 if (cpu_dai->driver->ops->hw_free)
Liam Girdwoodddee6272011-06-09 14:45:53 +01001120 cpu_dai->driver->ops->hw_free(substream, cpu_dai);
1121
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +01001122 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001123 return 0;
1124}
1125
1126static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1127{
1128 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +00001129 struct snd_soc_component *component;
1130 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001131 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001132 struct snd_soc_dai *codec_dai;
1133 int i, ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001134
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001135 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001136 if (codec_dai->driver->ops->trigger) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001137 ret = codec_dai->driver->ops->trigger(substream,
1138 cmd, codec_dai);
1139 if (ret < 0)
1140 return ret;
1141 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01001142 }
1143
Kuninori Morimotob8135862017-10-11 01:37:23 +00001144 for_each_rtdcom(rtd, rtdcom) {
1145 component = rtdcom->component;
1146
Kuninori Morimotob8135862017-10-11 01:37:23 +00001147 if (!component->driver->ops ||
1148 !component->driver->ops->trigger)
1149 continue;
1150
1151 ret = component->driver->ops->trigger(substream, cmd);
1152 if (ret < 0)
1153 return ret;
1154 }
1155
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001156 if (cpu_dai->driver->ops->trigger) {
Liam Girdwoodddee6272011-06-09 14:45:53 +01001157 ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai);
1158 if (ret < 0)
1159 return ret;
1160 }
Jarkko Nikula4792b0d2014-04-28 14:17:52 +02001161
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +00001162 if (rtd->dai_link->ops->trigger) {
Jarkko Nikula4792b0d2014-04-28 14:17:52 +02001163 ret = rtd->dai_link->ops->trigger(substream, cmd);
1164 if (ret < 0)
1165 return ret;
1166 }
1167
Liam Girdwoodddee6272011-06-09 14:45:53 +01001168 return 0;
1169}
1170
Mark Brown45c0a182012-05-09 21:46:27 +01001171static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
1172 int cmd)
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001173{
1174 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001175 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001176 struct snd_soc_dai *codec_dai;
1177 int i, ret;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001178
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001179 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001180 if (codec_dai->driver->ops->bespoke_trigger) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001181 ret = codec_dai->driver->ops->bespoke_trigger(substream,
1182 cmd, codec_dai);
1183 if (ret < 0)
1184 return ret;
1185 }
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001186 }
1187
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001188 if (cpu_dai->driver->ops->bespoke_trigger) {
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001189 ret = cpu_dai->driver->ops->bespoke_trigger(substream, cmd, cpu_dai);
1190 if (ret < 0)
1191 return ret;
1192 }
1193 return 0;
1194}
Liam Girdwoodddee6272011-06-09 14:45:53 +01001195/*
1196 * soc level wrapper for pointer callback
Charles Keepaxef050be2018-04-24 16:39:02 +01001197 * If cpu_dai, codec_dai, component driver has the delay callback, then
Liam Girdwoodddee6272011-06-09 14:45:53 +01001198 * the runtime->delay will be updated accordingly.
1199 */
1200static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
1201{
1202 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +00001203 struct snd_soc_component *component;
1204 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001205 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001206 struct snd_soc_dai *codec_dai;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001207 struct snd_pcm_runtime *runtime = substream->runtime;
1208 snd_pcm_uframes_t offset = 0;
1209 snd_pcm_sframes_t delay = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001210 snd_pcm_sframes_t codec_delay = 0;
1211 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001212
Akshu Agrawal9fb4c2bf2018-08-01 15:37:33 +05301213 /* clearing the previous total delay */
1214 runtime->delay = 0;
1215
Kuninori Morimotob8135862017-10-11 01:37:23 +00001216 for_each_rtdcom(rtd, rtdcom) {
1217 component = rtdcom->component;
1218
Kuninori Morimotob8135862017-10-11 01:37:23 +00001219 if (!component->driver->ops ||
1220 !component->driver->ops->pointer)
1221 continue;
1222
1223 /* FIXME: use 1st pointer */
1224 offset = component->driver->ops->pointer(substream);
1225 break;
1226 }
Akshu Agrawal9fb4c2bf2018-08-01 15:37:33 +05301227 /* base delay if assigned in pointer callback */
1228 delay = runtime->delay;
Kuninori Morimotob8135862017-10-11 01:37:23 +00001229
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001230 if (cpu_dai->driver->ops->delay)
Liam Girdwoodddee6272011-06-09 14:45:53 +01001231 delay += cpu_dai->driver->ops->delay(substream, cpu_dai);
1232
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001233 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001234 if (codec_dai->driver->ops->delay)
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001235 codec_delay = max(codec_delay,
1236 codec_dai->driver->ops->delay(substream,
1237 codec_dai));
1238 }
1239 delay += codec_delay;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001240
Liam Girdwoodddee6272011-06-09 14:45:53 +01001241 runtime->delay = delay;
1242
1243 return offset;
1244}
1245
Liam Girdwood01d75842012-04-25 12:12:49 +01001246/* connect a FE and BE */
1247static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
1248 struct snd_soc_pcm_runtime *be, int stream)
1249{
1250 struct snd_soc_dpcm *dpcm;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001251 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001252
1253 /* only add new dpcms */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001254 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001255 if (dpcm->be == be && dpcm->fe == fe)
1256 return 0;
1257 }
1258
1259 dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_KERNEL);
1260 if (!dpcm)
1261 return -ENOMEM;
1262
1263 dpcm->be = be;
1264 dpcm->fe = fe;
1265 be->dpcm[stream].runtime = fe->dpcm[stream].runtime;
1266 dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001267 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001268 list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients);
1269 list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001270 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001271
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001272 dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001273 stream ? "capture" : "playback", fe->dai_link->name,
1274 stream ? "<-" : "->", be->dai_link->name);
1275
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001276#ifdef CONFIG_DEBUG_FS
Lars-Peter Clausen6553bf062015-04-09 10:52:38 +02001277 if (fe->debugfs_dpcm_root)
1278 dpcm->debugfs_state = debugfs_create_u32(be->dai_link->name, 0644,
1279 fe->debugfs_dpcm_root, &dpcm->state);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001280#endif
Liam Girdwood01d75842012-04-25 12:12:49 +01001281 return 1;
1282}
1283
1284/* reparent a BE onto another FE */
1285static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
1286 struct snd_soc_pcm_runtime *be, int stream)
1287{
1288 struct snd_soc_dpcm *dpcm;
1289 struct snd_pcm_substream *fe_substream, *be_substream;
1290
1291 /* reparent if BE is connected to other FEs */
1292 if (!be->dpcm[stream].users)
1293 return;
1294
1295 be_substream = snd_soc_dpcm_get_substream(be, stream);
1296
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00001297 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001298 if (dpcm->fe == fe)
1299 continue;
1300
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001301 dev_dbg(fe->dev, "reparent %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001302 stream ? "capture" : "playback",
1303 dpcm->fe->dai_link->name,
1304 stream ? "<-" : "->", dpcm->be->dai_link->name);
1305
1306 fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, stream);
1307 be_substream->runtime = fe_substream->runtime;
1308 break;
1309 }
1310}
1311
1312/* disconnect a BE and FE */
Liam Girdwood23607022014-01-17 17:03:55 +00001313void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001314{
1315 struct snd_soc_dpcm *dpcm, *d;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001316 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001317
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001318 for_each_dpcm_be_safe(fe, stream, dpcm, d) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001319 dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001320 stream ? "capture" : "playback",
1321 dpcm->be->dai_link->name);
1322
1323 if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE)
1324 continue;
1325
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001326 dev_dbg(fe->dev, "freed DSP %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001327 stream ? "capture" : "playback", fe->dai_link->name,
1328 stream ? "<-" : "->", dpcm->be->dai_link->name);
1329
1330 /* BEs still alive need new FE */
1331 dpcm_be_reparent(fe, dpcm->be, stream);
1332
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001333#ifdef CONFIG_DEBUG_FS
1334 debugfs_remove(dpcm->debugfs_state);
1335#endif
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001336 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001337 list_del(&dpcm->list_be);
1338 list_del(&dpcm->list_fe);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001339 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001340 kfree(dpcm);
1341 }
1342}
1343
1344/* get BE for DAI widget and stream */
1345static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
1346 struct snd_soc_dapm_widget *widget, int stream)
1347{
1348 struct snd_soc_pcm_runtime *be;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001349 struct snd_soc_dai *dai;
Mengdong Lin1a497982015-11-18 02:34:11 -05001350 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01001351
Liam Girdwood3c146462018-03-14 20:43:51 +00001352 dev_dbg(card->dev, "ASoC: find BE for widget %s\n", widget->name);
1353
Liam Girdwood01d75842012-04-25 12:12:49 +01001354 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00001355 for_each_card_rtds(card, be) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001356
Liam Girdwood35ea0652012-06-05 19:26:59 +01001357 if (!be->dai_link->no_pcm)
1358 continue;
1359
Liam Girdwood3c146462018-03-14 20:43:51 +00001360 dev_dbg(card->dev, "ASoC: try BE : %s\n",
1361 be->cpu_dai->playback_widget ?
1362 be->cpu_dai->playback_widget->name : "(not set)");
1363
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001364 if (be->cpu_dai->playback_widget == widget)
Liam Girdwood01d75842012-04-25 12:12:49 +01001365 return be;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001366
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001367 for_each_rtd_codec_dai(be, i, dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001368 if (dai->playback_widget == widget)
1369 return be;
1370 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001371 }
1372 } else {
1373
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00001374 for_each_card_rtds(card, be) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001375
Liam Girdwood35ea0652012-06-05 19:26:59 +01001376 if (!be->dai_link->no_pcm)
1377 continue;
1378
Liam Girdwood3c146462018-03-14 20:43:51 +00001379 dev_dbg(card->dev, "ASoC: try BE %s\n",
1380 be->cpu_dai->capture_widget ?
1381 be->cpu_dai->capture_widget->name : "(not set)");
1382
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001383 if (be->cpu_dai->capture_widget == widget)
Liam Girdwood01d75842012-04-25 12:12:49 +01001384 return be;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001385
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001386 for_each_rtd_codec_dai(be, i, dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001387 if (dai->capture_widget == widget)
1388 return be;
1389 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001390 }
1391 }
1392
Liam Girdwood3c146462018-03-14 20:43:51 +00001393 /* dai link name and stream name set correctly ? */
Liam Girdwood103d84a2012-11-19 14:39:15 +00001394 dev_err(card->dev, "ASoC: can't get %s BE for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001395 stream ? "capture" : "playback", widget->name);
1396 return NULL;
1397}
1398
1399static inline struct snd_soc_dapm_widget *
Benoit Cousson37018612014-04-24 14:01:45 +02001400 dai_get_widget(struct snd_soc_dai *dai, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001401{
1402 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
Benoit Cousson37018612014-04-24 14:01:45 +02001403 return dai->playback_widget;
Liam Girdwood01d75842012-04-25 12:12:49 +01001404 else
Benoit Cousson37018612014-04-24 14:01:45 +02001405 return dai->capture_widget;
Liam Girdwood01d75842012-04-25 12:12:49 +01001406}
1407
1408static int widget_in_list(struct snd_soc_dapm_widget_list *list,
1409 struct snd_soc_dapm_widget *widget)
1410{
1411 int i;
1412
1413 for (i = 0; i < list->num_widgets; i++) {
1414 if (widget == list->widgets[i])
1415 return 1;
1416 }
1417
1418 return 0;
1419}
1420
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001421static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget,
1422 enum snd_soc_dapm_direction dir)
1423{
1424 struct snd_soc_card *card = widget->dapm->card;
1425 struct snd_soc_pcm_runtime *rtd;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001426 struct snd_soc_dai *dai;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001427 int i;
1428
1429 if (dir == SND_SOC_DAPM_DIR_OUT) {
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00001430 for_each_card_rtds(card, rtd) {
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001431 if (!rtd->dai_link->no_pcm)
1432 continue;
1433
1434 if (rtd->cpu_dai->playback_widget == widget)
1435 return true;
1436
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001437 for_each_rtd_codec_dai(rtd, i, dai) {
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001438 if (dai->playback_widget == widget)
1439 return true;
1440 }
1441 }
1442 } else { /* SND_SOC_DAPM_DIR_IN */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00001443 for_each_card_rtds(card, rtd) {
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001444 if (!rtd->dai_link->no_pcm)
1445 continue;
1446
1447 if (rtd->cpu_dai->capture_widget == widget)
1448 return true;
1449
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001450 for_each_rtd_codec_dai(rtd, i, dai) {
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001451 if (dai->capture_widget == widget)
1452 return true;
1453 }
1454 }
1455 }
1456
1457 return false;
1458}
1459
Liam Girdwood23607022014-01-17 17:03:55 +00001460int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001461 int stream, struct snd_soc_dapm_widget_list **list)
Liam Girdwood01d75842012-04-25 12:12:49 +01001462{
1463 struct snd_soc_dai *cpu_dai = fe->cpu_dai;
Liam Girdwood01d75842012-04-25 12:12:49 +01001464 int paths;
1465
Liam Girdwood01d75842012-04-25 12:12:49 +01001466 /* get number of valid DAI paths and their widgets */
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001467 paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list,
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001468 dpcm_end_walk_at_be);
Liam Girdwood01d75842012-04-25 12:12:49 +01001469
Liam Girdwood103d84a2012-11-19 14:39:15 +00001470 dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths,
Liam Girdwood01d75842012-04-25 12:12:49 +01001471 stream ? "capture" : "playback");
1472
Liam Girdwood01d75842012-04-25 12:12:49 +01001473 return paths;
1474}
1475
Liam Girdwood01d75842012-04-25 12:12:49 +01001476static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
1477 struct snd_soc_dapm_widget_list **list_)
1478{
1479 struct snd_soc_dpcm *dpcm;
1480 struct snd_soc_dapm_widget_list *list = *list_;
1481 struct snd_soc_dapm_widget *widget;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001482 struct snd_soc_dai *dai;
Liam Girdwood01d75842012-04-25 12:12:49 +01001483 int prune = 0;
1484
1485 /* Destroy any old FE <--> BE connections */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001486 for_each_dpcm_be(fe, stream, dpcm) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001487 unsigned int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01001488
1489 /* is there a valid CPU DAI widget for this BE */
Benoit Cousson37018612014-04-24 14:01:45 +02001490 widget = dai_get_widget(dpcm->be->cpu_dai, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001491
1492 /* prune the BE if it's no longer in our active list */
1493 if (widget && widget_in_list(list, widget))
1494 continue;
1495
1496 /* is there a valid CODEC DAI widget for this BE */
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001497 for_each_rtd_codec_dai(dpcm->be, i, dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001498 widget = dai_get_widget(dai, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001499
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001500 /* prune the BE if it's no longer in our active list */
1501 if (widget && widget_in_list(list, widget))
1502 continue;
1503 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001504
Liam Girdwood103d84a2012-11-19 14:39:15 +00001505 dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001506 stream ? "capture" : "playback",
1507 dpcm->be->dai_link->name, fe->dai_link->name);
1508 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
1509 dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1510 prune++;
1511 }
1512
Liam Girdwood103d84a2012-11-19 14:39:15 +00001513 dev_dbg(fe->dev, "ASoC: found %d old BE paths for pruning\n", prune);
Liam Girdwood01d75842012-04-25 12:12:49 +01001514 return prune;
1515}
1516
1517static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
1518 struct snd_soc_dapm_widget_list **list_)
1519{
1520 struct snd_soc_card *card = fe->card;
1521 struct snd_soc_dapm_widget_list *list = *list_;
1522 struct snd_soc_pcm_runtime *be;
1523 int i, new = 0, err;
1524
1525 /* Create any new FE <--> BE connections */
1526 for (i = 0; i < list->num_widgets; i++) {
1527
Mark Brown46162742013-06-05 19:36:11 +01001528 switch (list->widgets[i]->id) {
1529 case snd_soc_dapm_dai_in:
Koro Chenc5b85402015-07-06 10:02:10 +08001530 if (stream != SNDRV_PCM_STREAM_PLAYBACK)
1531 continue;
1532 break;
Mark Brown46162742013-06-05 19:36:11 +01001533 case snd_soc_dapm_dai_out:
Koro Chenc5b85402015-07-06 10:02:10 +08001534 if (stream != SNDRV_PCM_STREAM_CAPTURE)
1535 continue;
Mark Brown46162742013-06-05 19:36:11 +01001536 break;
1537 default:
Liam Girdwood01d75842012-04-25 12:12:49 +01001538 continue;
Mark Brown46162742013-06-05 19:36:11 +01001539 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001540
1541 /* is there a valid BE rtd for this widget */
1542 be = dpcm_get_be(card, list->widgets[i], stream);
1543 if (!be) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001544 dev_err(fe->dev, "ASoC: no BE found for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001545 list->widgets[i]->name);
1546 continue;
1547 }
1548
1549 /* make sure BE is a real BE */
1550 if (!be->dai_link->no_pcm)
1551 continue;
1552
1553 /* don't connect if FE is not running */
Liam Girdwood23607022014-01-17 17:03:55 +00001554 if (!fe->dpcm[stream].runtime && !fe->fe_compr)
Liam Girdwood01d75842012-04-25 12:12:49 +01001555 continue;
1556
1557 /* newly connected FE and BE */
1558 err = dpcm_be_connect(fe, be, stream);
1559 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001560 dev_err(fe->dev, "ASoC: can't connect %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001561 list->widgets[i]->name);
1562 break;
1563 } else if (err == 0) /* already connected */
1564 continue;
1565
1566 /* new */
1567 be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1568 new++;
1569 }
1570
Liam Girdwood103d84a2012-11-19 14:39:15 +00001571 dev_dbg(fe->dev, "ASoC: found %d new BE paths\n", new);
Liam Girdwood01d75842012-04-25 12:12:49 +01001572 return new;
1573}
1574
1575/*
1576 * Find the corresponding BE DAIs that source or sink audio to this
1577 * FE substream.
1578 */
Liam Girdwood23607022014-01-17 17:03:55 +00001579int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
Liam Girdwood01d75842012-04-25 12:12:49 +01001580 int stream, struct snd_soc_dapm_widget_list **list, int new)
1581{
1582 if (new)
1583 return dpcm_add_paths(fe, stream, list);
1584 else
1585 return dpcm_prune_paths(fe, stream, list);
1586}
1587
Liam Girdwood23607022014-01-17 17:03:55 +00001588void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001589{
1590 struct snd_soc_dpcm *dpcm;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001591 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001592
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001593 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001594 for_each_dpcm_be(fe, stream, dpcm)
Liam Girdwood01d75842012-04-25 12:12:49 +01001595 dpcm->be->dpcm[stream].runtime_update =
1596 SND_SOC_DPCM_UPDATE_NO;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001597 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001598}
1599
1600static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe,
1601 int stream)
1602{
1603 struct snd_soc_dpcm *dpcm;
1604
1605 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001606 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001607
1608 struct snd_soc_pcm_runtime *be = dpcm->be;
1609 struct snd_pcm_substream *be_substream =
1610 snd_soc_dpcm_get_substream(be, stream);
1611
1612 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001613 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001614 stream ? "capture" : "playback",
1615 be->dpcm[stream].state);
1616
1617 if (--be->dpcm[stream].users != 0)
1618 continue;
1619
1620 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1621 continue;
1622
1623 soc_pcm_close(be_substream);
1624 be_substream->runtime = NULL;
1625 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1626 }
1627}
1628
Liam Girdwood23607022014-01-17 17:03:55 +00001629int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001630{
1631 struct snd_soc_dpcm *dpcm;
1632 int err, count = 0;
1633
1634 /* only startup BE DAIs that are either sinks or sources to this FE DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001635 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001636
1637 struct snd_soc_pcm_runtime *be = dpcm->be;
1638 struct snd_pcm_substream *be_substream =
1639 snd_soc_dpcm_get_substream(be, stream);
1640
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001641 if (!be_substream) {
1642 dev_err(be->dev, "ASoC: no backend %s stream\n",
1643 stream ? "capture" : "playback");
1644 continue;
1645 }
1646
Liam Girdwood01d75842012-04-25 12:12:49 +01001647 /* is this op for this BE ? */
1648 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1649 continue;
1650
1651 /* first time the dpcm is open ? */
1652 if (be->dpcm[stream].users == DPCM_MAX_BE_USERS)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001653 dev_err(be->dev, "ASoC: too many users %s at open %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001654 stream ? "capture" : "playback",
1655 be->dpcm[stream].state);
1656
1657 if (be->dpcm[stream].users++ != 0)
1658 continue;
1659
1660 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
1661 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
1662 continue;
1663
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001664 dev_dbg(be->dev, "ASoC: open %s BE %s\n",
1665 stream ? "capture" : "playback", be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001666
1667 be_substream->runtime = be->dpcm[stream].runtime;
1668 err = soc_pcm_open(be_substream);
1669 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001670 dev_err(be->dev, "ASoC: BE open failed %d\n", err);
Liam Girdwood01d75842012-04-25 12:12:49 +01001671 be->dpcm[stream].users--;
1672 if (be->dpcm[stream].users < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001673 dev_err(be->dev, "ASoC: no users %s at unwind %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001674 stream ? "capture" : "playback",
1675 be->dpcm[stream].state);
1676
1677 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1678 goto unwind;
1679 }
1680
1681 be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1682 count++;
1683 }
1684
1685 return count;
1686
1687unwind:
1688 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001689 for_each_dpcm_be_rollback(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001690 struct snd_soc_pcm_runtime *be = dpcm->be;
1691 struct snd_pcm_substream *be_substream =
1692 snd_soc_dpcm_get_substream(be, stream);
1693
1694 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1695 continue;
1696
1697 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001698 dev_err(be->dev, "ASoC: no users %s at close %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001699 stream ? "capture" : "playback",
1700 be->dpcm[stream].state);
1701
1702 if (--be->dpcm[stream].users != 0)
1703 continue;
1704
1705 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1706 continue;
1707
1708 soc_pcm_close(be_substream);
1709 be_substream->runtime = NULL;
1710 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1711 }
1712
1713 return err;
1714}
1715
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001716static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
Jerome Brunet435ffb72018-07-05 12:13:48 +02001717 struct snd_soc_pcm_stream *stream)
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001718{
1719 runtime->hw.rate_min = stream->rate_min;
Charles Keepaxe33ffbd9c2018-08-27 14:26:47 +01001720 runtime->hw.rate_max = min_not_zero(stream->rate_max, UINT_MAX);
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001721 runtime->hw.channels_min = stream->channels_min;
1722 runtime->hw.channels_max = stream->channels_max;
Lars-Peter Clausen002220a2014-01-06 14:19:07 +01001723 if (runtime->hw.formats)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001724 runtime->hw.formats &= stream->formats;
Lars-Peter Clausen002220a2014-01-06 14:19:07 +01001725 else
Jerome Brunet435ffb72018-07-05 12:13:48 +02001726 runtime->hw.formats = stream->formats;
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001727 runtime->hw.rates = stream->rates;
1728}
1729
Jerome Brunet435ffb72018-07-05 12:13:48 +02001730static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream,
1731 u64 *formats)
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001732{
1733 struct snd_soc_pcm_runtime *fe = substream->private_data;
1734 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001735 struct snd_soc_dai *dai;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001736 int stream = substream->stream;
1737
1738 if (!fe->dai_link->dpcm_merged_format)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001739 return;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001740
1741 /*
1742 * It returns merged BE codec format
1743 * if FE want to use it (= dpcm_merged_format)
1744 */
1745
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001746 for_each_dpcm_be(fe, stream, dpcm) {
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001747 struct snd_soc_pcm_runtime *be = dpcm->be;
1748 struct snd_soc_dai_driver *codec_dai_drv;
1749 struct snd_soc_pcm_stream *codec_stream;
1750 int i;
1751
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001752 for_each_rtd_codec_dai(be, i, dai) {
Jerome Brunet4febced2018-06-27 17:36:38 +02001753 /*
1754 * Skip CODECs which don't support the current stream
1755 * type. See soc_pcm_init_runtime_hw() for more details
1756 */
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001757 if (!snd_soc_dai_stream_valid(dai, stream))
Jerome Brunet4febced2018-06-27 17:36:38 +02001758 continue;
1759
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001760 codec_dai_drv = dai->driver;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001761 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1762 codec_stream = &codec_dai_drv->playback;
1763 else
1764 codec_stream = &codec_dai_drv->capture;
1765
Jerome Brunet435ffb72018-07-05 12:13:48 +02001766 *formats &= codec_stream->formats;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001767 }
1768 }
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001769}
1770
Jerome Brunet435ffb72018-07-05 12:13:48 +02001771static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream,
1772 unsigned int *channels_min,
1773 unsigned int *channels_max)
Jiada Wangf4c277b2018-06-20 18:25:20 +09001774{
1775 struct snd_soc_pcm_runtime *fe = substream->private_data;
1776 struct snd_soc_dpcm *dpcm;
1777 int stream = substream->stream;
1778
1779 if (!fe->dai_link->dpcm_merged_chan)
1780 return;
1781
Jiada Wangf4c277b2018-06-20 18:25:20 +09001782 /*
1783 * It returns merged BE codec channel;
1784 * if FE want to use it (= dpcm_merged_chan)
1785 */
1786
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001787 for_each_dpcm_be(fe, stream, dpcm) {
Jiada Wangf4c277b2018-06-20 18:25:20 +09001788 struct snd_soc_pcm_runtime *be = dpcm->be;
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001789 struct snd_soc_dai_driver *cpu_dai_drv = be->cpu_dai->driver;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001790 struct snd_soc_dai_driver *codec_dai_drv;
1791 struct snd_soc_pcm_stream *codec_stream;
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001792 struct snd_soc_pcm_stream *cpu_stream;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001793
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001794 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1795 cpu_stream = &cpu_dai_drv->playback;
1796 else
1797 cpu_stream = &cpu_dai_drv->capture;
1798
1799 *channels_min = max(*channels_min, cpu_stream->channels_min);
1800 *channels_max = min(*channels_max, cpu_stream->channels_max);
1801
1802 /*
1803 * chan min/max cannot be enforced if there are multiple CODEC
1804 * DAIs connected to a single CPU DAI, use CPU DAI's directly
1805 */
1806 if (be->num_codecs == 1) {
1807 codec_dai_drv = be->codec_dais[0]->driver;
1808
Jiada Wangf4c277b2018-06-20 18:25:20 +09001809 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1810 codec_stream = &codec_dai_drv->playback;
1811 else
1812 codec_stream = &codec_dai_drv->capture;
1813
1814 *channels_min = max(*channels_min,
1815 codec_stream->channels_min);
1816 *channels_max = min(*channels_max,
1817 codec_stream->channels_max);
1818 }
1819 }
1820}
1821
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001822static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream,
1823 unsigned int *rates,
1824 unsigned int *rate_min,
1825 unsigned int *rate_max)
1826{
1827 struct snd_soc_pcm_runtime *fe = substream->private_data;
1828 struct snd_soc_dpcm *dpcm;
1829 int stream = substream->stream;
1830
1831 if (!fe->dai_link->dpcm_merged_rate)
1832 return;
1833
1834 /*
1835 * It returns merged BE codec channel;
1836 * if FE want to use it (= dpcm_merged_chan)
1837 */
1838
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001839 for_each_dpcm_be(fe, stream, dpcm) {
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001840 struct snd_soc_pcm_runtime *be = dpcm->be;
1841 struct snd_soc_dai_driver *cpu_dai_drv = be->cpu_dai->driver;
1842 struct snd_soc_dai_driver *codec_dai_drv;
1843 struct snd_soc_pcm_stream *codec_stream;
1844 struct snd_soc_pcm_stream *cpu_stream;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001845 struct snd_soc_dai *dai;
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001846 int i;
1847
1848 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1849 cpu_stream = &cpu_dai_drv->playback;
1850 else
1851 cpu_stream = &cpu_dai_drv->capture;
1852
1853 *rate_min = max(*rate_min, cpu_stream->rate_min);
1854 *rate_max = min_not_zero(*rate_max, cpu_stream->rate_max);
1855 *rates = snd_pcm_rate_mask_intersect(*rates, cpu_stream->rates);
1856
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001857 for_each_rtd_codec_dai(be, i, dai) {
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001858 /*
1859 * Skip CODECs which don't support the current stream
1860 * type. See soc_pcm_init_runtime_hw() for more details
1861 */
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001862 if (!snd_soc_dai_stream_valid(dai, stream))
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001863 continue;
1864
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001865 codec_dai_drv = dai->driver;
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001866 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1867 codec_stream = &codec_dai_drv->playback;
1868 else
1869 codec_stream = &codec_dai_drv->capture;
1870
1871 *rate_min = max(*rate_min, codec_stream->rate_min);
1872 *rate_max = min_not_zero(*rate_max,
1873 codec_stream->rate_max);
1874 *rates = snd_pcm_rate_mask_intersect(*rates,
1875 codec_stream->rates);
1876 }
1877 }
1878}
1879
Mark Brown45c0a182012-05-09 21:46:27 +01001880static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001881{
1882 struct snd_pcm_runtime *runtime = substream->runtime;
1883 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1884 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
1885 struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
1886
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001887 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001888 dpcm_init_runtime_hw(runtime, &cpu_dai_drv->playback);
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001889 else
Jerome Brunet435ffb72018-07-05 12:13:48 +02001890 dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture);
Jiada Wangf4c277b2018-06-20 18:25:20 +09001891
Jerome Brunet435ffb72018-07-05 12:13:48 +02001892 dpcm_runtime_merge_format(substream, &runtime->hw.formats);
1893 dpcm_runtime_merge_chan(substream, &runtime->hw.channels_min,
1894 &runtime->hw.channels_max);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001895 dpcm_runtime_merge_rate(substream, &runtime->hw.rates,
1896 &runtime->hw.rate_min, &runtime->hw.rate_max);
Liam Girdwood01d75842012-04-25 12:12:49 +01001897}
1898
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001899static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
1900
1901/* Set FE's runtime_update state; the state is protected via PCM stream lock
1902 * for avoiding the race with trigger callback.
1903 * If the state is unset and a trigger is pending while the previous operation,
1904 * process the pending trigger action here.
1905 */
1906static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
1907 int stream, enum snd_soc_dpcm_update state)
1908{
1909 struct snd_pcm_substream *substream =
1910 snd_soc_dpcm_get_substream(fe, stream);
1911
1912 snd_pcm_stream_lock_irq(substream);
1913 if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) {
1914 dpcm_fe_dai_do_trigger(substream,
1915 fe->dpcm[stream].trigger_pending - 1);
1916 fe->dpcm[stream].trigger_pending = 0;
1917 }
1918 fe->dpcm[stream].runtime_update = state;
1919 snd_pcm_stream_unlock_irq(substream);
1920}
1921
PC Liao906c7d62015-12-11 11:33:51 +08001922static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
1923 int stream)
1924{
1925 struct snd_soc_dpcm *dpcm;
1926 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
1927 struct snd_soc_dai *fe_cpu_dai = fe->cpu_dai;
1928 int err;
1929
1930 /* apply symmetry for FE */
1931 if (soc_pcm_has_symmetry(fe_substream))
1932 fe_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1933
1934 /* Symmetry only applies if we've got an active stream. */
1935 if (fe_cpu_dai->active) {
1936 err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai);
1937 if (err < 0)
1938 return err;
1939 }
1940
1941 /* apply symmetry for BE */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001942 for_each_dpcm_be(fe, stream, dpcm) {
PC Liao906c7d62015-12-11 11:33:51 +08001943 struct snd_soc_pcm_runtime *be = dpcm->be;
1944 struct snd_pcm_substream *be_substream =
1945 snd_soc_dpcm_get_substream(be, stream);
Jerome Brunet6246f282019-04-01 15:03:54 +02001946 struct snd_soc_pcm_runtime *rtd;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001947 struct snd_soc_dai *codec_dai;
PC Liao906c7d62015-12-11 11:33:51 +08001948 int i;
1949
Jerome Brunet6246f282019-04-01 15:03:54 +02001950 /* A backend may not have the requested substream */
1951 if (!be_substream)
1952 continue;
1953
1954 rtd = be_substream->private_data;
Jeeja KPf1176612016-09-06 14:17:55 +05301955 if (rtd->dai_link->be_hw_params_fixup)
1956 continue;
1957
PC Liao906c7d62015-12-11 11:33:51 +08001958 if (soc_pcm_has_symmetry(be_substream))
1959 be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1960
1961 /* Symmetry only applies if we've got an active stream. */
1962 if (rtd->cpu_dai->active) {
Kai Chieh Chuang99bcedb2018-05-28 10:18:19 +08001963 err = soc_pcm_apply_symmetry(fe_substream,
1964 rtd->cpu_dai);
PC Liao906c7d62015-12-11 11:33:51 +08001965 if (err < 0)
1966 return err;
1967 }
1968
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001969 for_each_rtd_codec_dai(rtd, i, codec_dai) {
1970 if (codec_dai->active) {
Kai Chieh Chuang99bcedb2018-05-28 10:18:19 +08001971 err = soc_pcm_apply_symmetry(fe_substream,
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001972 codec_dai);
PC Liao906c7d62015-12-11 11:33:51 +08001973 if (err < 0)
1974 return err;
1975 }
1976 }
1977 }
1978
1979 return 0;
1980}
1981
Liam Girdwood01d75842012-04-25 12:12:49 +01001982static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
1983{
1984 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
1985 struct snd_pcm_runtime *runtime = fe_substream->runtime;
1986 int stream = fe_substream->stream, ret = 0;
1987
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001988 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001989
1990 ret = dpcm_be_dai_startup(fe, fe_substream->stream);
1991 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001992 dev_err(fe->dev,"ASoC: failed to start some BEs %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001993 goto be_err;
1994 }
1995
Liam Girdwood103d84a2012-11-19 14:39:15 +00001996 dev_dbg(fe->dev, "ASoC: open FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001997
1998 /* start the DAI frontend */
1999 ret = soc_pcm_open(fe_substream);
2000 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002001 dev_err(fe->dev,"ASoC: failed to start FE %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002002 goto unwind;
2003 }
2004
2005 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
2006
2007 dpcm_set_fe_runtime(fe_substream);
2008 snd_pcm_limit_hw_rates(runtime);
2009
PC Liao906c7d62015-12-11 11:33:51 +08002010 ret = dpcm_apply_symmetry(fe_substream, stream);
2011 if (ret < 0) {
2012 dev_err(fe->dev, "ASoC: failed to apply dpcm symmetry %d\n",
2013 ret);
2014 goto unwind;
2015 }
2016
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002017 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002018 return 0;
2019
2020unwind:
2021 dpcm_be_dai_startup_unwind(fe, fe_substream->stream);
2022be_err:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002023 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002024 return ret;
2025}
2026
Liam Girdwood23607022014-01-17 17:03:55 +00002027int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002028{
2029 struct snd_soc_dpcm *dpcm;
2030
2031 /* only shutdown BEs that are either sinks or sources to this FE DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002032 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002033
2034 struct snd_soc_pcm_runtime *be = dpcm->be;
2035 struct snd_pcm_substream *be_substream =
2036 snd_soc_dpcm_get_substream(be, stream);
2037
2038 /* is this op for this BE ? */
2039 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2040 continue;
2041
2042 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002043 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002044 stream ? "capture" : "playback",
2045 be->dpcm[stream].state);
2046
2047 if (--be->dpcm[stream].users != 0)
2048 continue;
2049
2050 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Kai Chieh Chuang9c0ac702018-05-28 10:18:18 +08002051 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) {
2052 soc_pcm_hw_free(be_substream);
2053 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
2054 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002055
Liam Girdwood103d84a2012-11-19 14:39:15 +00002056 dev_dbg(be->dev, "ASoC: close BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002057 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002058
2059 soc_pcm_close(be_substream);
2060 be_substream->runtime = NULL;
2061
2062 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
2063 }
2064 return 0;
2065}
2066
2067static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
2068{
2069 struct snd_soc_pcm_runtime *fe = substream->private_data;
2070 int stream = substream->stream;
2071
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002072 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002073
2074 /* shutdown the BEs */
2075 dpcm_be_dai_shutdown(fe, substream->stream);
2076
Liam Girdwood103d84a2012-11-19 14:39:15 +00002077 dev_dbg(fe->dev, "ASoC: close FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002078
2079 /* now shutdown the frontend */
2080 soc_pcm_close(substream);
2081
2082 /* run the stream event for each BE */
2083 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
2084
2085 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002086 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002087 return 0;
2088}
2089
Liam Girdwood23607022014-01-17 17:03:55 +00002090int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002091{
2092 struct snd_soc_dpcm *dpcm;
2093
2094 /* only hw_params backends that are either sinks or sources
2095 * to this frontend DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002096 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002097
2098 struct snd_soc_pcm_runtime *be = dpcm->be;
2099 struct snd_pcm_substream *be_substream =
2100 snd_soc_dpcm_get_substream(be, stream);
2101
2102 /* is this op for this BE ? */
2103 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2104 continue;
2105
2106 /* only free hw when no longer used - check all FEs */
2107 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2108 continue;
2109
Qiao Zhou36fba622014-12-03 10:13:43 +08002110 /* do not free hw if this BE is used by other FE */
2111 if (be->dpcm[stream].users > 1)
2112 continue;
2113
Liam Girdwood01d75842012-04-25 12:12:49 +01002114 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2115 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
2116 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Patrick Lai08b27842012-12-19 19:36:02 -08002117 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
Vinod Koul5e82d2b2016-02-01 22:26:40 +05302118 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
2119 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
Liam Girdwood01d75842012-04-25 12:12:49 +01002120 continue;
2121
Liam Girdwood103d84a2012-11-19 14:39:15 +00002122 dev_dbg(be->dev, "ASoC: hw_free BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002123 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002124
2125 soc_pcm_hw_free(be_substream);
2126
2127 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
2128 }
2129
2130 return 0;
2131}
2132
Mark Brown45c0a182012-05-09 21:46:27 +01002133static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002134{
2135 struct snd_soc_pcm_runtime *fe = substream->private_data;
2136 int err, stream = substream->stream;
2137
2138 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002139 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002140
Liam Girdwood103d84a2012-11-19 14:39:15 +00002141 dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002142
2143 /* call hw_free on the frontend */
2144 err = soc_pcm_hw_free(substream);
2145 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002146 dev_err(fe->dev,"ASoC: hw_free FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002147 fe->dai_link->name);
2148
2149 /* only hw_params backends that are either sinks or sources
2150 * to this frontend DAI */
2151 err = dpcm_be_dai_hw_free(fe, stream);
2152
2153 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002154 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002155
2156 mutex_unlock(&fe->card->mutex);
2157 return 0;
2158}
2159
Liam Girdwood23607022014-01-17 17:03:55 +00002160int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002161{
2162 struct snd_soc_dpcm *dpcm;
2163 int ret;
2164
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002165 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002166
2167 struct snd_soc_pcm_runtime *be = dpcm->be;
2168 struct snd_pcm_substream *be_substream =
2169 snd_soc_dpcm_get_substream(be, stream);
2170
2171 /* is this op for this BE ? */
2172 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2173 continue;
2174
Liam Girdwood01d75842012-04-25 12:12:49 +01002175 /* copy params for each dpcm */
2176 memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params,
2177 sizeof(struct snd_pcm_hw_params));
2178
2179 /* perform any hw_params fixups */
2180 if (be->dai_link->be_hw_params_fixup) {
2181 ret = be->dai_link->be_hw_params_fixup(be,
2182 &dpcm->hw_params);
2183 if (ret < 0) {
2184 dev_err(be->dev,
Liam Girdwood103d84a2012-11-19 14:39:15 +00002185 "ASoC: hw_params BE fixup failed %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002186 ret);
2187 goto unwind;
2188 }
2189 }
2190
Libin Yangae061d22019-04-19 09:53:12 +08002191 /* copy the fixed-up hw params for BE dai */
2192 memcpy(&be->dpcm[stream].hw_params, &dpcm->hw_params,
2193 sizeof(struct snd_pcm_hw_params));
2194
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00002195 /* only allow hw_params() if no connected FEs are running */
2196 if (!snd_soc_dpcm_can_be_params(fe, be, stream))
2197 continue;
2198
2199 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
2200 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2201 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE))
2202 continue;
2203
2204 dev_dbg(be->dev, "ASoC: hw_params BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002205 be->dai_link->name);
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00002206
Liam Girdwood01d75842012-04-25 12:12:49 +01002207 ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params);
2208 if (ret < 0) {
2209 dev_err(dpcm->be->dev,
Liam Girdwood103d84a2012-11-19 14:39:15 +00002210 "ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002211 goto unwind;
2212 }
2213
2214 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2215 }
2216 return 0;
2217
2218unwind:
2219 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002220 for_each_dpcm_be_rollback(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002221 struct snd_soc_pcm_runtime *be = dpcm->be;
2222 struct snd_pcm_substream *be_substream =
2223 snd_soc_dpcm_get_substream(be, stream);
2224
2225 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2226 continue;
2227
2228 /* only allow hw_free() if no connected FEs are running */
2229 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2230 continue;
2231
2232 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
2233 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2234 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
2235 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
2236 continue;
2237
2238 soc_pcm_hw_free(be_substream);
2239 }
2240
2241 return ret;
2242}
2243
Mark Brown45c0a182012-05-09 21:46:27 +01002244static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
2245 struct snd_pcm_hw_params *params)
Liam Girdwood01d75842012-04-25 12:12:49 +01002246{
2247 struct snd_soc_pcm_runtime *fe = substream->private_data;
2248 int ret, stream = substream->stream;
2249
2250 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002251 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002252
2253 memcpy(&fe->dpcm[substream->stream].hw_params, params,
2254 sizeof(struct snd_pcm_hw_params));
2255 ret = dpcm_be_dai_hw_params(fe, substream->stream);
2256 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002257 dev_err(fe->dev,"ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002258 goto out;
2259 }
2260
Liam Girdwood103d84a2012-11-19 14:39:15 +00002261 dev_dbg(fe->dev, "ASoC: hw_params FE %s rate %d chan %x fmt %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002262 fe->dai_link->name, params_rate(params),
2263 params_channels(params), params_format(params));
2264
2265 /* call hw_params on the frontend */
2266 ret = soc_pcm_hw_params(substream, params);
2267 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002268 dev_err(fe->dev,"ASoC: hw_params FE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002269 dpcm_be_dai_hw_free(fe, stream);
2270 } else
2271 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2272
2273out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002274 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002275 mutex_unlock(&fe->card->mutex);
2276 return ret;
2277}
2278
2279static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm,
2280 struct snd_pcm_substream *substream, int cmd)
2281{
2282 int ret;
2283
Liam Girdwood103d84a2012-11-19 14:39:15 +00002284 dev_dbg(dpcm->be->dev, "ASoC: trigger BE %s cmd %d\n",
彭东林94d215c2016-09-26 08:29:31 +00002285 dpcm->be->dai_link->name, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002286
2287 ret = soc_pcm_trigger(substream, cmd);
2288 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002289 dev_err(dpcm->be->dev,"ASoC: trigger BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002290
2291 return ret;
2292}
2293
Liam Girdwood23607022014-01-17 17:03:55 +00002294int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
Mark Brown45c0a182012-05-09 21:46:27 +01002295 int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002296{
2297 struct snd_soc_dpcm *dpcm;
2298 int ret = 0;
2299
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002300 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002301
2302 struct snd_soc_pcm_runtime *be = dpcm->be;
2303 struct snd_pcm_substream *be_substream =
2304 snd_soc_dpcm_get_substream(be, stream);
2305
2306 /* is this op for this BE ? */
2307 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2308 continue;
2309
2310 switch (cmd) {
2311 case SNDRV_PCM_TRIGGER_START:
2312 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
2313 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
2314 continue;
2315
2316 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2317 if (ret)
2318 return ret;
2319
2320 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2321 break;
2322 case SNDRV_PCM_TRIGGER_RESUME:
2323 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
2324 continue;
2325
2326 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2327 if (ret)
2328 return ret;
2329
2330 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2331 break;
2332 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2333 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
2334 continue;
2335
2336 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2337 if (ret)
2338 return ret;
2339
2340 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2341 break;
2342 case SNDRV_PCM_TRIGGER_STOP:
2343 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2344 continue;
2345
2346 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2347 continue;
2348
2349 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2350 if (ret)
2351 return ret;
2352
2353 be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2354 break;
2355 case SNDRV_PCM_TRIGGER_SUSPEND:
Nicolin Chen868a6ca2014-05-12 20:12:05 +08002356 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
Liam Girdwood01d75842012-04-25 12:12:49 +01002357 continue;
2358
2359 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2360 continue;
2361
2362 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2363 if (ret)
2364 return ret;
2365
2366 be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND;
2367 break;
2368 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2369 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2370 continue;
2371
2372 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2373 continue;
2374
2375 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2376 if (ret)
2377 return ret;
2378
2379 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2380 break;
2381 }
2382 }
2383
2384 return ret;
2385}
2386EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
2387
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002388static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002389{
2390 struct snd_soc_pcm_runtime *fe = substream->private_data;
2391 int stream = substream->stream, ret;
2392 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
2393
2394 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
2395
2396 switch (trigger) {
2397 case SND_SOC_DPCM_TRIGGER_PRE:
2398 /* call trigger on the frontend before the backend. */
2399
Liam Girdwood103d84a2012-11-19 14:39:15 +00002400 dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002401 fe->dai_link->name, cmd);
2402
2403 ret = soc_pcm_trigger(substream, cmd);
2404 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002405 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002406 goto out;
2407 }
2408
2409 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2410 break;
2411 case SND_SOC_DPCM_TRIGGER_POST:
2412 /* call trigger on the frontend after the backend. */
2413
2414 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2415 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002416 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002417 goto out;
2418 }
2419
Liam Girdwood103d84a2012-11-19 14:39:15 +00002420 dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002421 fe->dai_link->name, cmd);
2422
2423 ret = soc_pcm_trigger(substream, cmd);
2424 break;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002425 case SND_SOC_DPCM_TRIGGER_BESPOKE:
2426 /* bespoke trigger() - handles both FE and BEs */
2427
Liam Girdwood103d84a2012-11-19 14:39:15 +00002428 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd %d\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002429 fe->dai_link->name, cmd);
2430
2431 ret = soc_pcm_bespoke_trigger(substream, cmd);
2432 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002433 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002434 goto out;
2435 }
2436 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002437 default:
Liam Girdwood103d84a2012-11-19 14:39:15 +00002438 dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd,
Liam Girdwood01d75842012-04-25 12:12:49 +01002439 fe->dai_link->name);
2440 ret = -EINVAL;
2441 goto out;
2442 }
2443
2444 switch (cmd) {
2445 case SNDRV_PCM_TRIGGER_START:
2446 case SNDRV_PCM_TRIGGER_RESUME:
2447 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2448 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2449 break;
2450 case SNDRV_PCM_TRIGGER_STOP:
2451 case SNDRV_PCM_TRIGGER_SUSPEND:
Liam Girdwood01d75842012-04-25 12:12:49 +01002452 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2453 break;
Patrick Lai9f169b92016-12-31 22:44:39 -08002454 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2455 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2456 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002457 }
2458
2459out:
2460 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
2461 return ret;
2462}
2463
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002464static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
2465{
2466 struct snd_soc_pcm_runtime *fe = substream->private_data;
2467 int stream = substream->stream;
2468
2469 /* if FE's runtime_update is already set, we're in race;
2470 * process this trigger later at exit
2471 */
2472 if (fe->dpcm[stream].runtime_update != SND_SOC_DPCM_UPDATE_NO) {
2473 fe->dpcm[stream].trigger_pending = cmd + 1;
2474 return 0; /* delayed, assuming it's successful */
2475 }
2476
2477 /* we're alone, let's trigger */
2478 return dpcm_fe_dai_do_trigger(substream, cmd);
2479}
2480
Liam Girdwood23607022014-01-17 17:03:55 +00002481int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002482{
2483 struct snd_soc_dpcm *dpcm;
2484 int ret = 0;
2485
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002486 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002487
2488 struct snd_soc_pcm_runtime *be = dpcm->be;
2489 struct snd_pcm_substream *be_substream =
2490 snd_soc_dpcm_get_substream(be, stream);
2491
2492 /* is this op for this BE ? */
2493 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2494 continue;
2495
2496 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
Koro Chen95f444d2015-10-28 10:15:34 +08002497 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
2498 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
Liam Girdwood01d75842012-04-25 12:12:49 +01002499 continue;
2500
Liam Girdwood103d84a2012-11-19 14:39:15 +00002501 dev_dbg(be->dev, "ASoC: prepare BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002502 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002503
2504 ret = soc_pcm_prepare(be_substream);
2505 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002506 dev_err(be->dev, "ASoC: backend prepare failed %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002507 ret);
2508 break;
2509 }
2510
2511 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2512 }
2513 return ret;
2514}
2515
Mark Brown45c0a182012-05-09 21:46:27 +01002516static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002517{
2518 struct snd_soc_pcm_runtime *fe = substream->private_data;
2519 int stream = substream->stream, ret = 0;
2520
2521 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2522
Liam Girdwood103d84a2012-11-19 14:39:15 +00002523 dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002524
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002525 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002526
2527 /* there is no point preparing this FE if there are no BEs */
2528 if (list_empty(&fe->dpcm[stream].be_clients)) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002529 dev_err(fe->dev, "ASoC: no backend DAIs enabled for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002530 fe->dai_link->name);
2531 ret = -EINVAL;
2532 goto out;
2533 }
2534
2535 ret = dpcm_be_dai_prepare(fe, substream->stream);
2536 if (ret < 0)
2537 goto out;
2538
2539 /* call prepare on the frontend */
2540 ret = soc_pcm_prepare(substream);
2541 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002542 dev_err(fe->dev,"ASoC: prepare FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002543 fe->dai_link->name);
2544 goto out;
2545 }
2546
2547 /* run the stream event for each BE */
2548 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
2549 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2550
2551out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002552 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002553 mutex_unlock(&fe->card->mutex);
2554
2555 return ret;
2556}
2557
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01002558static int soc_pcm_ioctl(struct snd_pcm_substream *substream,
2559 unsigned int cmd, void *arg)
2560{
2561 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +00002562 struct snd_soc_component *component;
2563 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01002564
Kuninori Morimotob8135862017-10-11 01:37:23 +00002565 for_each_rtdcom(rtd, rtdcom) {
2566 component = rtdcom->component;
2567
Kuninori Morimotob8135862017-10-11 01:37:23 +00002568 if (!component->driver->ops ||
2569 !component->driver->ops->ioctl)
2570 continue;
2571
2572 /* FIXME: use 1st ioctl */
2573 return component->driver->ops->ioctl(substream, cmd, arg);
2574 }
2575
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01002576 return snd_pcm_lib_ioctl(substream, cmd, arg);
2577}
2578
Liam Girdwood618dae12012-04-25 12:12:51 +01002579static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
2580{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002581 struct snd_pcm_substream *substream =
2582 snd_soc_dpcm_get_substream(fe, stream);
2583 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01002584 int err;
Liam Girdwood01d75842012-04-25 12:12:49 +01002585
Liam Girdwood103d84a2012-11-19 14:39:15 +00002586 dev_dbg(fe->dev, "ASoC: runtime %s close on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002587 stream ? "capture" : "playback", fe->dai_link->name);
2588
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002589 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2590 /* call bespoke trigger - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002591 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002592 fe->dai_link->name);
2593
2594 err = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
2595 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002596 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002597 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002598 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002599 fe->dai_link->name);
2600
2601 err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
2602 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002603 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002604 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002605
2606 err = dpcm_be_dai_hw_free(fe, stream);
2607 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002608 dev_err(fe->dev,"ASoC: hw_free FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002609
2610 err = dpcm_be_dai_shutdown(fe, stream);
2611 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002612 dev_err(fe->dev,"ASoC: shutdown FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002613
2614 /* run the stream event for each BE */
2615 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2616
2617 return 0;
2618}
2619
2620static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
2621{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002622 struct snd_pcm_substream *substream =
2623 snd_soc_dpcm_get_substream(fe, stream);
Liam Girdwood618dae12012-04-25 12:12:51 +01002624 struct snd_soc_dpcm *dpcm;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002625 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01002626 int ret;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002627 unsigned long flags;
Liam Girdwood618dae12012-04-25 12:12:51 +01002628
Liam Girdwood103d84a2012-11-19 14:39:15 +00002629 dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002630 stream ? "capture" : "playback", fe->dai_link->name);
2631
2632 /* Only start the BE if the FE is ready */
2633 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
2634 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE)
2635 return -EINVAL;
2636
2637 /* startup must always be called for new BEs */
2638 ret = dpcm_be_dai_startup(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002639 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002640 goto disconnect;
Liam Girdwood618dae12012-04-25 12:12:51 +01002641
2642 /* keep going if FE state is > open */
2643 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN)
2644 return 0;
2645
2646 ret = dpcm_be_dai_hw_params(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002647 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002648 goto close;
Liam Girdwood618dae12012-04-25 12:12:51 +01002649
2650 /* keep going if FE state is > hw_params */
2651 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS)
2652 return 0;
2653
2654
2655 ret = dpcm_be_dai_prepare(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002656 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002657 goto hw_free;
Liam Girdwood618dae12012-04-25 12:12:51 +01002658
2659 /* run the stream event for each BE */
2660 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2661
2662 /* keep going if FE state is > prepare */
2663 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE ||
2664 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP)
2665 return 0;
2666
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002667 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2668 /* call trigger on the frontend - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002669 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002670 fe->dai_link->name);
Liam Girdwood618dae12012-04-25 12:12:51 +01002671
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002672 ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
2673 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002674 dev_err(fe->dev,"ASoC: bespoke trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002675 goto hw_free;
2676 }
2677 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002678 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002679 fe->dai_link->name);
2680
2681 ret = dpcm_be_dai_trigger(fe, stream,
2682 SNDRV_PCM_TRIGGER_START);
2683 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002684 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002685 goto hw_free;
2686 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002687 }
2688
2689 return 0;
2690
2691hw_free:
2692 dpcm_be_dai_hw_free(fe, stream);
2693close:
2694 dpcm_be_dai_shutdown(fe, stream);
2695disconnect:
2696 /* disconnect any non started BEs */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002697 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002698 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood618dae12012-04-25 12:12:51 +01002699 struct snd_soc_pcm_runtime *be = dpcm->be;
2700 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2701 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2702 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002703 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood618dae12012-04-25 12:12:51 +01002704
2705 return ret;
2706}
2707
2708static int dpcm_run_new_update(struct snd_soc_pcm_runtime *fe, int stream)
2709{
2710 int ret;
2711
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002712 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood618dae12012-04-25 12:12:51 +01002713 ret = dpcm_run_update_startup(fe, stream);
2714 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002715 dev_err(fe->dev, "ASoC: failed to startup some BEs\n");
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002716 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood618dae12012-04-25 12:12:51 +01002717
2718 return ret;
2719}
2720
2721static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream)
2722{
2723 int ret;
2724
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002725 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood618dae12012-04-25 12:12:51 +01002726 ret = dpcm_run_update_shutdown(fe, stream);
2727 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002728 dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n");
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002729 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood618dae12012-04-25 12:12:51 +01002730
2731 return ret;
2732}
2733
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002734static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
2735{
2736 struct snd_soc_dapm_widget_list *list;
2737 int count, paths;
2738
2739 if (!fe->dai_link->dynamic)
2740 return 0;
2741
2742 /* only check active links */
2743 if (!fe->cpu_dai->active)
2744 return 0;
2745
2746 /* DAPM sync will call this to update DSP paths */
2747 dev_dbg(fe->dev, "ASoC: DPCM %s runtime update for FE %s\n",
2748 new ? "new" : "old", fe->dai_link->name);
2749
2750 /* skip if FE doesn't have playback capability */
2751 if (!fe->cpu_dai->driver->playback.channels_min ||
2752 !fe->codec_dai->driver->playback.channels_min)
2753 goto capture;
2754
2755 /* skip if FE isn't currently playing */
2756 if (!fe->cpu_dai->playback_active || !fe->codec_dai->playback_active)
2757 goto capture;
2758
2759 paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list);
2760 if (paths < 0) {
2761 dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
2762 fe->dai_link->name, "playback");
2763 return paths;
2764 }
2765
2766 /* update any playback paths */
2767 count = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, new);
2768 if (count) {
2769 if (new)
2770 dpcm_run_new_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
2771 else
2772 dpcm_run_old_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
2773
2774 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
2775 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
2776 }
2777
2778 dpcm_path_put(&list);
2779
2780capture:
2781 /* skip if FE doesn't have capture capability */
2782 if (!fe->cpu_dai->driver->capture.channels_min ||
2783 !fe->codec_dai->driver->capture.channels_min)
2784 return 0;
2785
2786 /* skip if FE isn't currently capturing */
2787 if (!fe->cpu_dai->capture_active || !fe->codec_dai->capture_active)
2788 return 0;
2789
2790 paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list);
2791 if (paths < 0) {
2792 dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
2793 fe->dai_link->name, "capture");
2794 return paths;
2795 }
2796
2797 /* update any old capture paths */
2798 count = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, new);
2799 if (count) {
2800 if (new)
2801 dpcm_run_new_update(fe, SNDRV_PCM_STREAM_CAPTURE);
2802 else
2803 dpcm_run_old_update(fe, SNDRV_PCM_STREAM_CAPTURE);
2804
2805 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
2806 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
2807 }
2808
2809 dpcm_path_put(&list);
2810
2811 return 0;
2812}
2813
Liam Girdwood618dae12012-04-25 12:12:51 +01002814/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
2815 * any DAI links.
2816 */
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002817int soc_dpcm_runtime_update(struct snd_soc_card *card)
Liam Girdwood618dae12012-04-25 12:12:51 +01002818{
Mengdong Lin1a497982015-11-18 02:34:11 -05002819 struct snd_soc_pcm_runtime *fe;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002820 int ret = 0;
Liam Girdwood618dae12012-04-25 12:12:51 +01002821
Liam Girdwood618dae12012-04-25 12:12:51 +01002822 mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002823 /* shutdown all old paths first */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002824 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002825 ret = soc_dpcm_fe_runtime_update(fe, 0);
2826 if (ret)
2827 goto out;
Liam Girdwood618dae12012-04-25 12:12:51 +01002828 }
2829
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002830 /* bring new paths up */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002831 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002832 ret = soc_dpcm_fe_runtime_update(fe, 1);
2833 if (ret)
2834 goto out;
2835 }
2836
2837out:
Liam Girdwood618dae12012-04-25 12:12:51 +01002838 mutex_unlock(&card->mutex);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002839 return ret;
Liam Girdwood618dae12012-04-25 12:12:51 +01002840}
Liam Girdwood01d75842012-04-25 12:12:49 +01002841int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute)
2842{
2843 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00002844 struct snd_soc_dai *dai;
Liam Girdwood01d75842012-04-25 12:12:49 +01002845
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002846 for_each_dpcm_be(fe, SNDRV_PCM_STREAM_PLAYBACK, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002847
2848 struct snd_soc_pcm_runtime *be = dpcm->be;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002849 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01002850
2851 if (be->dai_link->ignore_suspend)
2852 continue;
2853
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00002854 for_each_rtd_codec_dai(be, i, dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002855 struct snd_soc_dai_driver *drv = dai->driver;
Liam Girdwood01d75842012-04-25 12:12:49 +01002856
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002857 dev_dbg(be->dev, "ASoC: BE digital mute %s\n",
2858 be->dai_link->name);
2859
2860 if (drv->ops && drv->ops->digital_mute &&
2861 dai->playback_active)
2862 drv->ops->digital_mute(dai, mute);
2863 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002864 }
2865
2866 return 0;
2867}
2868
Mark Brown45c0a182012-05-09 21:46:27 +01002869static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002870{
2871 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
2872 struct snd_soc_dpcm *dpcm;
2873 struct snd_soc_dapm_widget_list *list;
2874 int ret;
2875 int stream = fe_substream->stream;
2876
2877 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2878 fe->dpcm[stream].runtime = fe_substream->runtime;
2879
Qiao Zhou8f70e512014-09-10 17:54:07 +08002880 ret = dpcm_path_get(fe, stream, &list);
2881 if (ret < 0) {
2882 mutex_unlock(&fe->card->mutex);
2883 return ret;
2884 } else if (ret == 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002885 dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002886 fe->dai_link->name, stream ? "capture" : "playback");
Liam Girdwood01d75842012-04-25 12:12:49 +01002887 }
2888
2889 /* calculate valid and active FE <-> BE dpcms */
2890 dpcm_process_paths(fe, stream, &list, 1);
2891
2892 ret = dpcm_fe_dai_startup(fe_substream);
2893 if (ret < 0) {
2894 /* clean up all links */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002895 for_each_dpcm_be(fe, stream, dpcm)
Liam Girdwood01d75842012-04-25 12:12:49 +01002896 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2897
2898 dpcm_be_disconnect(fe, stream);
2899 fe->dpcm[stream].runtime = NULL;
2900 }
2901
2902 dpcm_clear_pending_state(fe, stream);
2903 dpcm_path_put(&list);
2904 mutex_unlock(&fe->card->mutex);
2905 return ret;
2906}
2907
Mark Brown45c0a182012-05-09 21:46:27 +01002908static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002909{
2910 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
2911 struct snd_soc_dpcm *dpcm;
2912 int stream = fe_substream->stream, ret;
2913
2914 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2915 ret = dpcm_fe_dai_shutdown(fe_substream);
2916
2917 /* mark FE's links ready to prune */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002918 for_each_dpcm_be(fe, stream, dpcm)
Liam Girdwood01d75842012-04-25 12:12:49 +01002919 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2920
2921 dpcm_be_disconnect(fe, stream);
2922
2923 fe->dpcm[stream].runtime = NULL;
2924 mutex_unlock(&fe->card->mutex);
2925 return ret;
2926}
2927
Takashi Iwai5d61f0b2017-08-25 12:04:07 +02002928static void soc_pcm_private_free(struct snd_pcm *pcm)
2929{
2930 struct snd_soc_pcm_runtime *rtd = pcm->private_data;
Kuninori Morimotof523ace2017-09-26 01:00:53 +00002931 struct snd_soc_rtdcom_list *rtdcom;
2932 struct snd_soc_component *component;
Takashi Iwai5d61f0b2017-08-25 12:04:07 +02002933
Kuninori Morimotof30a4c32018-01-24 05:18:46 +00002934 /* need to sync the delayed work before releasing resources */
2935 flush_delayed_work(&rtd->delayed_work);
Kuninori Morimotof523ace2017-09-26 01:00:53 +00002936 for_each_rtdcom(rtd, rtdcom) {
Kuninori Morimotof523ace2017-09-26 01:00:53 +00002937 component = rtdcom->component;
2938
Kuninori Morimoto11fb14f2018-05-08 03:19:49 +00002939 if (component->driver->pcm_free)
2940 component->driver->pcm_free(pcm);
Kuninori Morimotof523ace2017-09-26 01:00:53 +00002941 }
Takashi Iwai5d61f0b2017-08-25 12:04:07 +02002942}
2943
Kuninori Morimotob8135862017-10-11 01:37:23 +00002944static int soc_rtdcom_ack(struct snd_pcm_substream *substream)
2945{
2946 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2947 struct snd_soc_rtdcom_list *rtdcom;
2948 struct snd_soc_component *component;
2949
2950 for_each_rtdcom(rtd, rtdcom) {
2951 component = rtdcom->component;
2952
2953 if (!component->driver->ops ||
2954 !component->driver->ops->ack)
2955 continue;
2956
2957 /* FIXME. it returns 1st ask now */
2958 return component->driver->ops->ack(substream);
2959 }
2960
2961 return -EINVAL;
2962}
2963
2964static int soc_rtdcom_copy_user(struct snd_pcm_substream *substream, int channel,
2965 unsigned long pos, void __user *buf,
2966 unsigned long bytes)
2967{
2968 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2969 struct snd_soc_rtdcom_list *rtdcom;
2970 struct snd_soc_component *component;
2971
2972 for_each_rtdcom(rtd, rtdcom) {
2973 component = rtdcom->component;
2974
2975 if (!component->driver->ops ||
2976 !component->driver->ops->copy_user)
2977 continue;
2978
2979 /* FIXME. it returns 1st copy now */
2980 return component->driver->ops->copy_user(substream, channel,
2981 pos, buf, bytes);
2982 }
2983
2984 return -EINVAL;
2985}
2986
2987static int soc_rtdcom_copy_kernel(struct snd_pcm_substream *substream, int channel,
2988 unsigned long pos, void *buf, unsigned long bytes)
2989{
2990 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2991 struct snd_soc_rtdcom_list *rtdcom;
2992 struct snd_soc_component *component;
2993
2994 for_each_rtdcom(rtd, rtdcom) {
2995 component = rtdcom->component;
2996
2997 if (!component->driver->ops ||
2998 !component->driver->ops->copy_kernel)
2999 continue;
3000
3001 /* FIXME. it returns 1st copy now */
3002 return component->driver->ops->copy_kernel(substream, channel,
3003 pos, buf, bytes);
3004 }
3005
3006 return -EINVAL;
3007}
3008
3009static int soc_rtdcom_fill_silence(struct snd_pcm_substream *substream, int channel,
3010 unsigned long pos, unsigned long bytes)
3011{
3012 struct snd_soc_pcm_runtime *rtd = substream->private_data;
3013 struct snd_soc_rtdcom_list *rtdcom;
3014 struct snd_soc_component *component;
3015
3016 for_each_rtdcom(rtd, rtdcom) {
3017 component = rtdcom->component;
3018
3019 if (!component->driver->ops ||
3020 !component->driver->ops->fill_silence)
3021 continue;
3022
3023 /* FIXME. it returns 1st silence now */
3024 return component->driver->ops->fill_silence(substream, channel,
3025 pos, bytes);
3026 }
3027
3028 return -EINVAL;
3029}
3030
3031static struct page *soc_rtdcom_page(struct snd_pcm_substream *substream,
3032 unsigned long offset)
3033{
3034 struct snd_soc_pcm_runtime *rtd = substream->private_data;
3035 struct snd_soc_rtdcom_list *rtdcom;
3036 struct snd_soc_component *component;
3037 struct page *page;
3038
3039 for_each_rtdcom(rtd, rtdcom) {
3040 component = rtdcom->component;
3041
3042 if (!component->driver->ops ||
3043 !component->driver->ops->page)
3044 continue;
3045
3046 /* FIXME. it returns 1st page now */
3047 page = component->driver->ops->page(substream, offset);
3048 if (page)
3049 return page;
3050 }
3051
3052 return NULL;
3053}
3054
3055static int soc_rtdcom_mmap(struct snd_pcm_substream *substream,
3056 struct vm_area_struct *vma)
3057{
3058 struct snd_soc_pcm_runtime *rtd = substream->private_data;
3059 struct snd_soc_rtdcom_list *rtdcom;
3060 struct snd_soc_component *component;
3061
3062 for_each_rtdcom(rtd, rtdcom) {
3063 component = rtdcom->component;
3064
3065 if (!component->driver->ops ||
3066 !component->driver->ops->mmap)
3067 continue;
3068
3069 /* FIXME. it returns 1st mmap now */
3070 return component->driver->ops->mmap(substream, vma);
3071 }
3072
3073 return -EINVAL;
3074}
3075
Liam Girdwoodddee6272011-06-09 14:45:53 +01003076/* create a new pcm */
3077int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
3078{
Benoit Cousson2e5894d2014-07-08 23:19:35 +02003079 struct snd_soc_dai *codec_dai;
Liam Girdwoodddee6272011-06-09 14:45:53 +01003080 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimotof523ace2017-09-26 01:00:53 +00003081 struct snd_soc_component *component;
3082 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +01003083 struct snd_pcm *pcm;
3084 char new_name[64];
3085 int ret = 0, playback = 0, capture = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02003086 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01003087
Liam Girdwood01d75842012-04-25 12:12:49 +01003088 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
Liam Girdwood1e9de422014-01-07 17:51:42 +00003089 playback = rtd->dai_link->dpcm_playback;
3090 capture = rtd->dai_link->dpcm_capture;
Liam Girdwood01d75842012-04-25 12:12:49 +01003091 } else {
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00003092 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02003093 if (codec_dai->driver->playback.channels_min)
3094 playback = 1;
3095 if (codec_dai->driver->capture.channels_min)
3096 capture = 1;
3097 }
3098
3099 capture = capture && cpu_dai->driver->capture.channels_min;
3100 playback = playback && cpu_dai->driver->playback.channels_min;
Liam Girdwood01d75842012-04-25 12:12:49 +01003101 }
Sangsu Parka5002312012-01-02 17:15:10 +09003102
Fabio Estevamd6bead02013-08-29 10:32:13 -03003103 if (rtd->dai_link->playback_only) {
3104 playback = 1;
3105 capture = 0;
3106 }
3107
3108 if (rtd->dai_link->capture_only) {
3109 playback = 0;
3110 capture = 1;
3111 }
3112
Liam Girdwood01d75842012-04-25 12:12:49 +01003113 /* create the PCM */
3114 if (rtd->dai_link->no_pcm) {
3115 snprintf(new_name, sizeof(new_name), "(%s)",
3116 rtd->dai_link->stream_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003117
Liam Girdwood01d75842012-04-25 12:12:49 +01003118 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
3119 playback, capture, &pcm);
3120 } else {
3121 if (rtd->dai_link->dynamic)
3122 snprintf(new_name, sizeof(new_name), "%s (*)",
3123 rtd->dai_link->stream_name);
3124 else
3125 snprintf(new_name, sizeof(new_name), "%s %s-%d",
Benoit Cousson2e5894d2014-07-08 23:19:35 +02003126 rtd->dai_link->stream_name,
3127 (rtd->num_codecs > 1) ?
3128 "multicodec" : rtd->codec_dai->name, num);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003129
Liam Girdwood01d75842012-04-25 12:12:49 +01003130 ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
3131 capture, &pcm);
3132 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01003133 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00003134 dev_err(rtd->card->dev, "ASoC: can't create pcm for %s\n",
Liam Girdwood5cb9b742012-07-06 16:54:52 +01003135 rtd->dai_link->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003136 return ret;
3137 }
Liam Girdwood103d84a2012-11-19 14:39:15 +00003138 dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003139
3140 /* DAPM dai link stream work */
3141 INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
3142
Vinod Koul48c76992015-02-12 09:59:53 +05303143 pcm->nonatomic = rtd->dai_link->nonatomic;
Liam Girdwoodddee6272011-06-09 14:45:53 +01003144 rtd->pcm = pcm;
3145 pcm->private_data = rtd;
Liam Girdwood01d75842012-04-25 12:12:49 +01003146
3147 if (rtd->dai_link->no_pcm) {
3148 if (playback)
3149 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
3150 if (capture)
3151 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
3152 goto out;
3153 }
3154
3155 /* ASoC PCM operations */
3156 if (rtd->dai_link->dynamic) {
3157 rtd->ops.open = dpcm_fe_dai_open;
3158 rtd->ops.hw_params = dpcm_fe_dai_hw_params;
3159 rtd->ops.prepare = dpcm_fe_dai_prepare;
3160 rtd->ops.trigger = dpcm_fe_dai_trigger;
3161 rtd->ops.hw_free = dpcm_fe_dai_hw_free;
3162 rtd->ops.close = dpcm_fe_dai_close;
3163 rtd->ops.pointer = soc_pcm_pointer;
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01003164 rtd->ops.ioctl = soc_pcm_ioctl;
Liam Girdwood01d75842012-04-25 12:12:49 +01003165 } else {
3166 rtd->ops.open = soc_pcm_open;
3167 rtd->ops.hw_params = soc_pcm_hw_params;
3168 rtd->ops.prepare = soc_pcm_prepare;
3169 rtd->ops.trigger = soc_pcm_trigger;
3170 rtd->ops.hw_free = soc_pcm_hw_free;
3171 rtd->ops.close = soc_pcm_close;
3172 rtd->ops.pointer = soc_pcm_pointer;
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01003173 rtd->ops.ioctl = soc_pcm_ioctl;
Liam Girdwood01d75842012-04-25 12:12:49 +01003174 }
3175
Kuninori Morimotob8135862017-10-11 01:37:23 +00003176 for_each_rtdcom(rtd, rtdcom) {
3177 const struct snd_pcm_ops *ops = rtdcom->component->driver->ops;
3178
3179 if (!ops)
3180 continue;
3181
3182 if (ops->ack)
3183 rtd->ops.ack = soc_rtdcom_ack;
3184 if (ops->copy_user)
3185 rtd->ops.copy_user = soc_rtdcom_copy_user;
3186 if (ops->copy_kernel)
3187 rtd->ops.copy_kernel = soc_rtdcom_copy_kernel;
3188 if (ops->fill_silence)
3189 rtd->ops.fill_silence = soc_rtdcom_fill_silence;
3190 if (ops->page)
3191 rtd->ops.page = soc_rtdcom_page;
3192 if (ops->mmap)
3193 rtd->ops.mmap = soc_rtdcom_mmap;
3194 }
3195
Liam Girdwoodddee6272011-06-09 14:45:53 +01003196 if (playback)
Liam Girdwood01d75842012-04-25 12:12:49 +01003197 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003198
3199 if (capture)
Liam Girdwood01d75842012-04-25 12:12:49 +01003200 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003201
Kuninori Morimotof523ace2017-09-26 01:00:53 +00003202 for_each_rtdcom(rtd, rtdcom) {
3203 component = rtdcom->component;
3204
Kuninori Morimoto11fb14f2018-05-08 03:19:49 +00003205 if (!component->driver->pcm_new)
Kuninori Morimotof523ace2017-09-26 01:00:53 +00003206 continue;
3207
Kuninori Morimoto11fb14f2018-05-08 03:19:49 +00003208 ret = component->driver->pcm_new(rtd);
Johan Hovoldc641e5b2017-07-12 17:55:29 +02003209 if (ret < 0) {
Kuninori Morimotof523ace2017-09-26 01:00:53 +00003210 dev_err(component->dev,
Johan Hovoldc641e5b2017-07-12 17:55:29 +02003211 "ASoC: pcm constructor failed: %d\n",
3212 ret);
3213 return ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +01003214 }
3215 }
Johan Hovoldc641e5b2017-07-12 17:55:29 +02003216
Takashi Iwai5d61f0b2017-08-25 12:04:07 +02003217 pcm->private_free = soc_pcm_private_free;
Takashi Iwai3d21ef02019-01-11 15:58:39 +01003218 pcm->no_device_suspend = true;
Liam Girdwood01d75842012-04-25 12:12:49 +01003219out:
Benoit Cousson2e5894d2014-07-08 23:19:35 +02003220 dev_info(rtd->card->dev, "%s <-> %s mapping ok\n",
3221 (rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name,
3222 cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003223 return ret;
3224}
Liam Girdwood01d75842012-04-25 12:12:49 +01003225
3226/* is the current PCM operation for this FE ? */
3227int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream)
3228{
3229 if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE)
3230 return 1;
3231 return 0;
3232}
3233EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update);
3234
3235/* is the current PCM operation for this BE ? */
3236int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
3237 struct snd_soc_pcm_runtime *be, int stream)
3238{
3239 if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) ||
3240 ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) &&
3241 be->dpcm[stream].runtime_update))
3242 return 1;
3243 return 0;
3244}
3245EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update);
3246
3247/* get the substream for this BE */
3248struct snd_pcm_substream *
3249 snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream)
3250{
3251 return be->pcm->streams[stream].substream;
3252}
3253EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream);
3254
3255/* get the BE runtime state */
3256enum snd_soc_dpcm_state
3257 snd_soc_dpcm_be_get_state(struct snd_soc_pcm_runtime *be, int stream)
3258{
3259 return be->dpcm[stream].state;
3260}
3261EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_get_state);
3262
3263/* set the BE runtime state */
3264void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be,
3265 int stream, enum snd_soc_dpcm_state state)
3266{
3267 be->dpcm[stream].state = state;
3268}
3269EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_set_state);
3270
3271/*
3272 * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE
3273 * are not running, paused or suspended for the specified stream direction.
3274 */
3275int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
3276 struct snd_soc_pcm_runtime *be, int stream)
3277{
3278 struct snd_soc_dpcm *dpcm;
3279 int state;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003280 int ret = 1;
3281 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01003282
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003283 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00003284 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01003285
3286 if (dpcm->fe == fe)
3287 continue;
3288
3289 state = dpcm->fe->dpcm[stream].state;
3290 if (state == SND_SOC_DPCM_STATE_START ||
3291 state == SND_SOC_DPCM_STATE_PAUSED ||
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003292 state == SND_SOC_DPCM_STATE_SUSPEND) {
3293 ret = 0;
3294 break;
3295 }
Liam Girdwood01d75842012-04-25 12:12:49 +01003296 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003297 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01003298
3299 /* it's safe to free/stop this BE DAI */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003300 return ret;
Liam Girdwood01d75842012-04-25 12:12:49 +01003301}
3302EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop);
3303
3304/*
3305 * We can only change hw params a BE DAI if any of it's FE are not prepared,
3306 * running, paused or suspended for the specified stream direction.
3307 */
3308int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
3309 struct snd_soc_pcm_runtime *be, int stream)
3310{
3311 struct snd_soc_dpcm *dpcm;
3312 int state;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003313 int ret = 1;
3314 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01003315
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003316 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00003317 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01003318
3319 if (dpcm->fe == fe)
3320 continue;
3321
3322 state = dpcm->fe->dpcm[stream].state;
3323 if (state == SND_SOC_DPCM_STATE_START ||
3324 state == SND_SOC_DPCM_STATE_PAUSED ||
3325 state == SND_SOC_DPCM_STATE_SUSPEND ||
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003326 state == SND_SOC_DPCM_STATE_PREPARE) {
3327 ret = 0;
3328 break;
3329 }
Liam Girdwood01d75842012-04-25 12:12:49 +01003330 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003331 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01003332
3333 /* it's safe to change hw_params */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003334 return ret;
Liam Girdwood01d75842012-04-25 12:12:49 +01003335}
3336EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003337
3338#ifdef CONFIG_DEBUG_FS
Lars-Peter Clausen852801412016-11-22 11:29:14 +01003339static const char *dpcm_state_string(enum snd_soc_dpcm_state state)
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003340{
3341 switch (state) {
3342 case SND_SOC_DPCM_STATE_NEW:
3343 return "new";
3344 case SND_SOC_DPCM_STATE_OPEN:
3345 return "open";
3346 case SND_SOC_DPCM_STATE_HW_PARAMS:
3347 return "hw_params";
3348 case SND_SOC_DPCM_STATE_PREPARE:
3349 return "prepare";
3350 case SND_SOC_DPCM_STATE_START:
3351 return "start";
3352 case SND_SOC_DPCM_STATE_STOP:
3353 return "stop";
3354 case SND_SOC_DPCM_STATE_SUSPEND:
3355 return "suspend";
3356 case SND_SOC_DPCM_STATE_PAUSED:
3357 return "paused";
3358 case SND_SOC_DPCM_STATE_HW_FREE:
3359 return "hw_free";
3360 case SND_SOC_DPCM_STATE_CLOSE:
3361 return "close";
3362 }
3363
3364 return "unknown";
3365}
3366
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003367static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
3368 int stream, char *buf, size_t size)
3369{
3370 struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params;
3371 struct snd_soc_dpcm *dpcm;
3372 ssize_t offset = 0;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003373 unsigned long flags;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003374
3375 /* FE state */
3376 offset += snprintf(buf + offset, size - offset,
3377 "[%s - %s]\n", fe->dai_link->name,
3378 stream ? "Capture" : "Playback");
3379
3380 offset += snprintf(buf + offset, size - offset, "State: %s\n",
3381 dpcm_state_string(fe->dpcm[stream].state));
3382
3383 if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
3384 (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
3385 offset += snprintf(buf + offset, size - offset,
3386 "Hardware Params: "
3387 "Format = %s, Channels = %d, Rate = %d\n",
3388 snd_pcm_format_name(params_format(params)),
3389 params_channels(params),
3390 params_rate(params));
3391
3392 /* BEs state */
3393 offset += snprintf(buf + offset, size - offset, "Backends:\n");
3394
3395 if (list_empty(&fe->dpcm[stream].be_clients)) {
3396 offset += snprintf(buf + offset, size - offset,
3397 " No active DSP links\n");
3398 goto out;
3399 }
3400
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003401 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00003402 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003403 struct snd_soc_pcm_runtime *be = dpcm->be;
3404 params = &dpcm->hw_params;
3405
3406 offset += snprintf(buf + offset, size - offset,
3407 "- %s\n", be->dai_link->name);
3408
3409 offset += snprintf(buf + offset, size - offset,
3410 " State: %s\n",
3411 dpcm_state_string(be->dpcm[stream].state));
3412
3413 if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
3414 (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
3415 offset += snprintf(buf + offset, size - offset,
3416 " Hardware Params: "
3417 "Format = %s, Channels = %d, Rate = %d\n",
3418 snd_pcm_format_name(params_format(params)),
3419 params_channels(params),
3420 params_rate(params));
3421 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003422 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003423out:
3424 return offset;
3425}
3426
3427static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf,
3428 size_t count, loff_t *ppos)
3429{
3430 struct snd_soc_pcm_runtime *fe = file->private_data;
3431 ssize_t out_count = PAGE_SIZE, offset = 0, ret = 0;
3432 char *buf;
3433
3434 buf = kmalloc(out_count, GFP_KERNEL);
3435 if (!buf)
3436 return -ENOMEM;
3437
3438 if (fe->cpu_dai->driver->playback.channels_min)
3439 offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_PLAYBACK,
3440 buf + offset, out_count - offset);
3441
3442 if (fe->cpu_dai->driver->capture.channels_min)
3443 offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_CAPTURE,
3444 buf + offset, out_count - offset);
3445
Liam Girdwoodf57b8482012-04-27 11:33:46 +01003446 ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003447
Liam Girdwoodf57b8482012-04-27 11:33:46 +01003448 kfree(buf);
3449 return ret;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003450}
3451
3452static const struct file_operations dpcm_state_fops = {
Liam Girdwoodf57b8482012-04-27 11:33:46 +01003453 .open = simple_open,
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003454 .read = dpcm_state_read_file,
3455 .llseek = default_llseek,
3456};
3457
Lars-Peter Clausen2e55b902015-04-09 10:52:37 +02003458void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003459{
Mark Brownb3bba9a2012-05-08 10:33:47 +01003460 if (!rtd->dai_link)
Lars-Peter Clausen2e55b902015-04-09 10:52:37 +02003461 return;
Mark Brownb3bba9a2012-05-08 10:33:47 +01003462
Lars-Peter Clausen6553bf062015-04-09 10:52:38 +02003463 if (!rtd->card->debugfs_card_root)
3464 return;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003465
3466 rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name,
3467 rtd->card->debugfs_card_root);
3468 if (!rtd->debugfs_dpcm_root) {
3469 dev_dbg(rtd->dev,
3470 "ASoC: Failed to create dpcm debugfs directory %s\n",
3471 rtd->dai_link->name);
Lars-Peter Clausen2e55b902015-04-09 10:52:37 +02003472 return;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003473 }
3474
Fabio Estevamf1e3f402017-07-29 11:40:55 -03003475 debugfs_create_file("state", 0444, rtd->debugfs_dpcm_root,
3476 rtd, &dpcm_state_fops);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003477}
3478#endif