blob: 2dcc44c73f6c9d1da0c8c597f9cf2a7d4d7e8e09 [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
Charles Keepax244e2932018-06-19 16:22:09 +0100449static int soc_pcm_components_close(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
456 for_each_rtdcom(rtd, rtdcom) {
457 component = rtdcom->component;
458
459 if (component == last)
460 break;
461
462 if (!component->driver->ops ||
463 !component->driver->ops->close)
464 continue;
465
466 component->driver->ops->close(substream);
Ranjani Sridharan52034ad2019-04-05 09:57:09 -0700467
468 if (component->driver->module_get_upon_open)
469 module_put(component->dev->driver->owner);
Charles Keepax244e2932018-06-19 16:22:09 +0100470 }
471
472 return 0;
473}
474
Mark Brown58ba9b22012-01-16 18:38:51 +0000475/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100476 * Called by ALSA when a PCM substream is opened, the runtime->hw record is
477 * then initialized and any private data can be allocated. This also calls
Charles Keepaxef050be2018-04-24 16:39:02 +0100478 * startup for the cpu DAI, component, machine and codec DAI.
Liam Girdwoodddee6272011-06-09 14:45:53 +0100479 */
480static int soc_pcm_open(struct snd_pcm_substream *substream)
481{
482 struct snd_soc_pcm_runtime *rtd = substream->private_data;
483 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000484 struct snd_soc_component *component;
485 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100486 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200487 struct snd_soc_dai *codec_dai;
488 const char *codec_dai_name = "multicodec";
Charles Keepax244e2932018-06-19 16:22:09 +0100489 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100490
Nicolin Chen988e8cc2013-11-04 14:57:31 +0800491 pinctrl_pm_select_default_state(cpu_dai->dev);
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000492 for_each_rtd_codec_dai(rtd, i, codec_dai)
493 pinctrl_pm_select_default_state(codec_dai->dev);
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000494
495 for_each_rtdcom(rtd, rtdcom) {
496 component = rtdcom->component;
497
498 pm_runtime_get_sync(component->dev);
499 }
Mark Brownd6652ef2011-12-03 20:14:31 +0000500
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100501 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100502
503 /* startup the audio subsystem */
Kuninori Morimoto9900a422017-09-25 01:38:54 +0000504 if (cpu_dai->driver->ops->startup) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100505 ret = cpu_dai->driver->ops->startup(substream, cpu_dai);
506 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000507 dev_err(cpu_dai->dev, "ASoC: can't open interface"
508 " %s: %d\n", cpu_dai->name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100509 goto out;
510 }
511 }
512
Kuninori Morimotob8135862017-10-11 01:37:23 +0000513 for_each_rtdcom(rtd, rtdcom) {
514 component = rtdcom->component;
515
Kuninori Morimotob8135862017-10-11 01:37:23 +0000516 if (!component->driver->ops ||
517 !component->driver->ops->open)
518 continue;
519
Ranjani Sridharan52034ad2019-04-05 09:57:09 -0700520 if (component->driver->module_get_upon_open &&
Ranjani Sridharan708024872019-04-08 12:30:25 -0700521 !try_module_get(component->dev->driver->owner)) {
522 ret = -ENODEV;
523 goto module_err;
524 }
Ranjani Sridharan52034ad2019-04-05 09:57:09 -0700525
Charles Keepax244e2932018-06-19 16:22:09 +0100526 ret = component->driver->ops->open(substream);
527 if (ret < 0) {
Kuninori Morimotob8135862017-10-11 01:37:23 +0000528 dev_err(component->dev,
529 "ASoC: can't open component %s: %d\n",
Charles Keepax244e2932018-06-19 16:22:09 +0100530 component->name, ret);
531 goto component_err;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000532 }
533 }
Charles Keepax244e2932018-06-19 16:22:09 +0100534 component = NULL;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000535
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000536 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto9900a422017-09-25 01:38:54 +0000537 if (codec_dai->driver->ops->startup) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200538 ret = codec_dai->driver->ops->startup(substream,
539 codec_dai);
540 if (ret < 0) {
541 dev_err(codec_dai->dev,
542 "ASoC: can't open codec %s: %d\n",
543 codec_dai->name, ret);
544 goto codec_dai_err;
545 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100546 }
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200547
548 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
549 codec_dai->tx_mask = 0;
550 else
551 codec_dai->rx_mask = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100552 }
553
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000554 if (rtd->dai_link->ops->startup) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100555 ret = rtd->dai_link->ops->startup(substream);
556 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000557 pr_err("ASoC: %s startup failed: %d\n",
Mark Brown25bfe662012-02-01 21:30:32 +0000558 rtd->dai_link->name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100559 goto machine_err;
560 }
561 }
562
Liam Girdwood01d75842012-04-25 12:12:49 +0100563 /* Dynamic PCM DAI links compat checks use dynamic capabilities */
564 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm)
565 goto dynamic;
566
Liam Girdwoodddee6272011-06-09 14:45:53 +0100567 /* Check that the codec and cpu DAIs are compatible */
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200568 soc_pcm_init_runtime_hw(substream);
569
570 if (rtd->num_codecs == 1)
571 codec_dai_name = rtd->codec_dai->name;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100572
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100573 if (soc_pcm_has_symmetry(substream))
574 runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
575
Liam Girdwoodddee6272011-06-09 14:45:53 +0100576 ret = -EINVAL;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100577 if (!runtime->hw.rates) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000578 printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200579 codec_dai_name, cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100580 goto config_err;
581 }
582 if (!runtime->hw.formats) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000583 printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200584 codec_dai_name, cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100585 goto config_err;
586 }
587 if (!runtime->hw.channels_min || !runtime->hw.channels_max ||
588 runtime->hw.channels_min > runtime->hw.channels_max) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000589 printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200590 codec_dai_name, cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100591 goto config_err;
592 }
593
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200594 soc_pcm_apply_msb(substream);
Mark Brown58ba9b22012-01-16 18:38:51 +0000595
Liam Girdwoodddee6272011-06-09 14:45:53 +0100596 /* Symmetry only applies if we've already got an active stream. */
Dong Aisheng17841022011-08-29 17:15:14 +0800597 if (cpu_dai->active) {
598 ret = soc_pcm_apply_symmetry(substream, cpu_dai);
599 if (ret != 0)
600 goto config_err;
601 }
602
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000603 for_each_rtd_codec_dai(rtd, i, codec_dai) {
604 if (codec_dai->active) {
605 ret = soc_pcm_apply_symmetry(substream, codec_dai);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200606 if (ret != 0)
607 goto config_err;
608 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100609 }
610
Liam Girdwood103d84a2012-11-19 14:39:15 +0000611 pr_debug("ASoC: %s <-> %s info:\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200612 codec_dai_name, cpu_dai->name);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000613 pr_debug("ASoC: rate mask 0x%x\n", runtime->hw.rates);
614 pr_debug("ASoC: min ch %d max ch %d\n", runtime->hw.channels_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100615 runtime->hw.channels_max);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000616 pr_debug("ASoC: min rate %d max rate %d\n", runtime->hw.rate_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100617 runtime->hw.rate_max);
618
Liam Girdwood01d75842012-04-25 12:12:49 +0100619dynamic:
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100620
621 snd_soc_runtime_activate(rtd, substream->stream);
622
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100623 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100624 return 0;
625
626config_err:
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000627 if (rtd->dai_link->ops->shutdown)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100628 rtd->dai_link->ops->shutdown(substream);
629
630machine_err:
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200631 i = rtd->num_codecs;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100632
633codec_dai_err:
Kuninori Morimoto6d11b122018-09-18 01:28:30 +0000634 for_each_rtd_codec_dai_rollback(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200635 if (codec_dai->driver->ops->shutdown)
636 codec_dai->driver->ops->shutdown(substream, codec_dai);
637 }
638
Kuninori Morimotob8135862017-10-11 01:37:23 +0000639component_err:
Charles Keepax244e2932018-06-19 16:22:09 +0100640 soc_pcm_components_close(substream, component);
Ranjani Sridharan708024872019-04-08 12:30:25 -0700641module_err:
Liam Girdwoodddee6272011-06-09 14:45:53 +0100642 if (cpu_dai->driver->ops->shutdown)
643 cpu_dai->driver->ops->shutdown(substream, cpu_dai);
644out:
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100645 mutex_unlock(&rtd->pcm_mutex);
Mark Brownd6652ef2011-12-03 20:14:31 +0000646
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000647 for_each_rtdcom(rtd, rtdcom) {
648 component = rtdcom->component;
649
650 pm_runtime_mark_last_busy(component->dev);
651 pm_runtime_put_autosuspend(component->dev);
Sanyog Kale3f809782016-01-05 17:14:49 +0530652 }
653
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000654 for_each_rtd_codec_dai(rtd, i, codec_dai) {
655 if (!codec_dai->active)
656 pinctrl_pm_select_sleep_state(codec_dai->dev);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200657 }
Nicolin Chen988e8cc2013-11-04 14:57:31 +0800658 if (!cpu_dai->active)
659 pinctrl_pm_select_sleep_state(cpu_dai->dev);
Mark Brownd6652ef2011-12-03 20:14:31 +0000660
Liam Girdwoodddee6272011-06-09 14:45:53 +0100661 return ret;
662}
663
664/*
665 * Power down the audio subsystem pmdown_time msecs after close is called.
666 * This is to ensure there are no pops or clicks in between any music tracks
667 * due to DAPM power cycling.
668 */
669static void close_delayed_work(struct work_struct *work)
670{
671 struct snd_soc_pcm_runtime *rtd =
672 container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200673 struct snd_soc_dai *codec_dai = rtd->codec_dais[0];
Liam Girdwoodddee6272011-06-09 14:45:53 +0100674
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100675 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100676
Liam Girdwood103d84a2012-11-19 14:39:15 +0000677 dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n",
Liam Girdwoodddee6272011-06-09 14:45:53 +0100678 codec_dai->driver->playback.stream_name,
679 codec_dai->playback_active ? "active" : "inactive",
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600680 rtd->pop_wait ? "yes" : "no");
Liam Girdwoodddee6272011-06-09 14:45:53 +0100681
682 /* are we waiting on this codec DAI stream */
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600683 if (rtd->pop_wait == 1) {
684 rtd->pop_wait = 0;
Mark Brown7bd3a6f2012-02-16 15:03:27 -0800685 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000686 SND_SOC_DAPM_STREAM_STOP);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100687 }
688
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100689 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100690}
691
692/*
693 * Called by ALSA when a PCM substream is closed. Private data can be
Charles Keepaxef050be2018-04-24 16:39:02 +0100694 * freed here. The cpu DAI, codec DAI, machine and components are also
Liam Girdwoodddee6272011-06-09 14:45:53 +0100695 * shutdown.
696 */
Liam Girdwood91d5e6b2011-06-09 17:04:59 +0100697static int soc_pcm_close(struct snd_pcm_substream *substream)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100698{
699 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000700 struct snd_soc_component *component;
701 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100702 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200703 struct snd_soc_dai *codec_dai;
704 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100705
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100706 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100707
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100708 snd_soc_runtime_deactivate(rtd, substream->stream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100709
Dong Aisheng17841022011-08-29 17:15:14 +0800710 /* clear the corresponding DAIs rate when inactive */
711 if (!cpu_dai->active)
712 cpu_dai->rate = 0;
713
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000714 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200715 if (!codec_dai->active)
716 codec_dai->rate = 0;
717 }
Sascha Hauer25b76792011-08-17 09:20:01 +0200718
Ramesh Babuae116012014-10-15 12:34:59 +0530719 snd_soc_dai_digital_mute(cpu_dai, 1, substream->stream);
720
Liam Girdwoodddee6272011-06-09 14:45:53 +0100721 if (cpu_dai->driver->ops->shutdown)
722 cpu_dai->driver->ops->shutdown(substream, cpu_dai);
723
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000724 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200725 if (codec_dai->driver->ops->shutdown)
726 codec_dai->driver->ops->shutdown(substream, codec_dai);
727 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100728
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000729 if (rtd->dai_link->ops->shutdown)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100730 rtd->dai_link->ops->shutdown(substream);
731
Charles Keepax244e2932018-06-19 16:22:09 +0100732 soc_pcm_components_close(substream, NULL);
Kuninori Morimotob8135862017-10-11 01:37:23 +0000733
Liam Girdwoodddee6272011-06-09 14:45:53 +0100734 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100735 if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
Peter Ujfalusi1d69c5c2011-10-14 14:43:33 +0300736 /* powered down playback stream now */
737 snd_soc_dapm_stream_event(rtd,
Mark Brown7bd3a6f2012-02-16 15:03:27 -0800738 SNDRV_PCM_STREAM_PLAYBACK,
Mark Brown7bd3a6f2012-02-16 15:03:27 -0800739 SND_SOC_DAPM_STREAM_STOP);
Peter Ujfalusi1d69c5c2011-10-14 14:43:33 +0300740 } else {
741 /* start delayed pop wq here for playback streams */
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600742 rtd->pop_wait = 1;
Mark Brownd4e1a732013-07-18 11:52:17 +0100743 queue_delayed_work(system_power_efficient_wq,
744 &rtd->delayed_work,
745 msecs_to_jiffies(rtd->pmdown_time));
Peter Ujfalusi1d69c5c2011-10-14 14:43:33 +0300746 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100747 } else {
748 /* capture streams can be powered down now */
Mark Brown7bd3a6f2012-02-16 15:03:27 -0800749 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000750 SND_SOC_DAPM_STREAM_STOP);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100751 }
752
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100753 mutex_unlock(&rtd->pcm_mutex);
Mark Brownd6652ef2011-12-03 20:14:31 +0000754
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000755 for_each_rtdcom(rtd, rtdcom) {
756 component = rtdcom->component;
Sanyog Kale3f809782016-01-05 17:14:49 +0530757
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000758 pm_runtime_mark_last_busy(component->dev);
759 pm_runtime_put_autosuspend(component->dev);
Sanyog Kale3f809782016-01-05 17:14:49 +0530760 }
761
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000762 for_each_rtd_codec_dai(rtd, i, codec_dai) {
763 if (!codec_dai->active)
764 pinctrl_pm_select_sleep_state(codec_dai->dev);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200765 }
Nicolin Chen988e8cc2013-11-04 14:57:31 +0800766 if (!cpu_dai->active)
767 pinctrl_pm_select_sleep_state(cpu_dai->dev);
Mark Brownd6652ef2011-12-03 20:14:31 +0000768
Liam Girdwoodddee6272011-06-09 14:45:53 +0100769 return 0;
770}
771
772/*
773 * Called by ALSA when the PCM substream is prepared, can set format, sample
774 * rate, etc. This function is non atomic and can be called multiple times,
775 * it can refer to the runtime info.
776 */
777static int soc_pcm_prepare(struct snd_pcm_substream *substream)
778{
779 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000780 struct snd_soc_component *component;
781 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100782 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200783 struct snd_soc_dai *codec_dai;
784 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100785
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100786 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100787
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000788 if (rtd->dai_link->ops->prepare) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100789 ret = rtd->dai_link->ops->prepare(substream);
790 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000791 dev_err(rtd->card->dev, "ASoC: machine prepare error:"
792 " %d\n", ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100793 goto out;
794 }
795 }
796
Kuninori Morimotob8135862017-10-11 01:37:23 +0000797 for_each_rtdcom(rtd, rtdcom) {
798 component = rtdcom->component;
799
Kuninori Morimotob8135862017-10-11 01:37:23 +0000800 if (!component->driver->ops ||
801 !component->driver->ops->prepare)
802 continue;
803
804 ret = component->driver->ops->prepare(substream);
805 if (ret < 0) {
806 dev_err(component->dev,
807 "ASoC: platform prepare error: %d\n", ret);
808 goto out;
809 }
810 }
811
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000812 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto9900a422017-09-25 01:38:54 +0000813 if (codec_dai->driver->ops->prepare) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200814 ret = codec_dai->driver->ops->prepare(substream,
815 codec_dai);
816 if (ret < 0) {
817 dev_err(codec_dai->dev,
Jarkko Nikula90cc7f12014-12-23 11:04:41 +0200818 "ASoC: codec DAI prepare error: %d\n",
819 ret);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200820 goto out;
821 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100822 }
823 }
824
Kuninori Morimoto9900a422017-09-25 01:38:54 +0000825 if (cpu_dai->driver->ops->prepare) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100826 ret = cpu_dai->driver->ops->prepare(substream, cpu_dai);
827 if (ret < 0) {
Jarkko Nikula90cc7f12014-12-23 11:04:41 +0200828 dev_err(cpu_dai->dev,
829 "ASoC: cpu DAI prepare error: %d\n", ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100830 goto out;
831 }
832 }
833
834 /* cancel any delayed stream shutdown that is pending */
835 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600836 rtd->pop_wait) {
837 rtd->pop_wait = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100838 cancel_delayed_work(&rtd->delayed_work);
839 }
840
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000841 snd_soc_dapm_stream_event(rtd, substream->stream,
842 SND_SOC_DAPM_STREAM_START);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100843
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000844 for_each_rtd_codec_dai(rtd, i, codec_dai)
845 snd_soc_dai_digital_mute(codec_dai, 0,
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200846 substream->stream);
Ramesh Babuae116012014-10-15 12:34:59 +0530847 snd_soc_dai_digital_mute(cpu_dai, 0, substream->stream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100848
849out:
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100850 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100851 return ret;
852}
853
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200854static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params,
855 unsigned int mask)
856{
857 struct snd_interval *interval;
858 int channels = hweight_long(mask);
859
860 interval = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
861 interval->min = channels;
862 interval->max = channels;
863}
864
Benoit Cousson93e69582014-07-08 23:19:38 +0200865int soc_dai_hw_params(struct snd_pcm_substream *substream,
866 struct snd_pcm_hw_params *params,
867 struct snd_soc_dai *dai)
868{
Liam Girdwooda655de82018-07-02 16:59:54 +0100869 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Benoit Cousson93e69582014-07-08 23:19:38 +0200870 int ret;
871
Liam Girdwooda655de82018-07-02 16:59:54 +0100872 /* perform any topology hw_params fixups before DAI */
873 if (rtd->dai_link->be_hw_params_fixup) {
874 ret = rtd->dai_link->be_hw_params_fixup(rtd, params);
875 if (ret < 0) {
876 dev_err(rtd->dev,
877 "ASoC: hw_params topology fixup failed %d\n",
878 ret);
879 return ret;
880 }
881 }
882
Kuninori Morimoto9900a422017-09-25 01:38:54 +0000883 if (dai->driver->ops->hw_params) {
Benoit Cousson93e69582014-07-08 23:19:38 +0200884 ret = dai->driver->ops->hw_params(substream, params, dai);
885 if (ret < 0) {
886 dev_err(dai->dev, "ASoC: can't set %s hw params: %d\n",
887 dai->name, ret);
888 return ret;
889 }
890 }
891
892 return 0;
893}
894
Charles Keepax244e2932018-06-19 16:22:09 +0100895static int soc_pcm_components_hw_free(struct snd_pcm_substream *substream,
896 struct snd_soc_component *last)
897{
898 struct snd_soc_pcm_runtime *rtd = substream->private_data;
899 struct snd_soc_rtdcom_list *rtdcom;
900 struct snd_soc_component *component;
901
902 for_each_rtdcom(rtd, rtdcom) {
903 component = rtdcom->component;
904
905 if (component == last)
906 break;
907
908 if (!component->driver->ops ||
909 !component->driver->ops->hw_free)
910 continue;
911
912 component->driver->ops->hw_free(substream);
913 }
914
915 return 0;
916}
917
Liam Girdwoodddee6272011-06-09 14:45:53 +0100918/*
919 * Called by ALSA when the hardware params are set by application. This
920 * function can also be called multiple times and can allocate buffers
921 * (using snd_pcm_lib_* ). It's non-atomic.
922 */
923static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
924 struct snd_pcm_hw_params *params)
925{
926 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000927 struct snd_soc_component *component;
928 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100929 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000930 struct snd_soc_dai *codec_dai;
Charles Keepax244e2932018-06-19 16:22:09 +0100931 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100932
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100933 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000934 if (rtd->dai_link->ops->hw_params) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100935 ret = rtd->dai_link->ops->hw_params(substream, params);
936 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000937 dev_err(rtd->card->dev, "ASoC: machine hw_params"
938 " failed: %d\n", ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100939 goto out;
940 }
941 }
942
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +0000943 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200944 struct snd_pcm_hw_params codec_params;
945
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200946 /*
947 * Skip CODECs which don't support the current stream type,
948 * the idea being that if a CODEC is not used for the currently
949 * set up transfer direction, it should not need to be
950 * configured, especially since the configuration used might
951 * not even be supported by that CODEC. There may be cases
952 * however where a CODEC needs to be set up although it is
953 * actually not being used for the transfer, e.g. if a
954 * capture-only CODEC is acting as an LRCLK and/or BCLK master
955 * for the DAI link including a playback-only CODEC.
956 * If this becomes necessary, we will have to augment the
957 * machine driver setup with information on how to act, so
958 * we can do the right thing here.
959 */
960 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
961 continue;
962
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200963 /* copy params for each codec */
964 codec_params = *params;
965
966 /* fixup params based on TDM slot masks */
Rander Wang570f18b2019-03-08 16:38:57 +0800967 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
968 codec_dai->tx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200969 soc_pcm_codec_params_fixup(&codec_params,
970 codec_dai->tx_mask);
Rander Wang570f18b2019-03-08 16:38:57 +0800971
972 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
973 codec_dai->rx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200974 soc_pcm_codec_params_fixup(&codec_params,
975 codec_dai->rx_mask);
976
Benoit Cousson93e69582014-07-08 23:19:38 +0200977 ret = soc_dai_hw_params(substream, &codec_params, codec_dai);
978 if(ret < 0)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100979 goto codec_err;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200980
981 codec_dai->rate = params_rate(&codec_params);
982 codec_dai->channels = params_channels(&codec_params);
983 codec_dai->sample_bits = snd_pcm_format_physical_width(
984 params_format(&codec_params));
Charles Keepax078a85f2019-01-31 13:30:18 +0000985
986 snd_soc_dapm_update_dai(substream, &codec_params, codec_dai);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100987 }
988
Benoit Cousson93e69582014-07-08 23:19:38 +0200989 ret = soc_dai_hw_params(substream, params, cpu_dai);
990 if (ret < 0)
991 goto interface_err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100992
Kuninori Morimotoca58221d2019-05-13 16:07:43 +0900993 /* store the parameters for each DAIs */
994 cpu_dai->rate = params_rate(params);
995 cpu_dai->channels = params_channels(params);
996 cpu_dai->sample_bits =
997 snd_pcm_format_physical_width(params_format(params));
998
999 snd_soc_dapm_update_dai(substream, params, cpu_dai);
1000
Kuninori Morimotob8135862017-10-11 01:37:23 +00001001 for_each_rtdcom(rtd, rtdcom) {
1002 component = rtdcom->component;
1003
Kuninori Morimotob8135862017-10-11 01:37:23 +00001004 if (!component->driver->ops ||
1005 !component->driver->ops->hw_params)
1006 continue;
1007
Charles Keepax244e2932018-06-19 16:22:09 +01001008 ret = component->driver->ops->hw_params(substream, params);
1009 if (ret < 0) {
Kuninori Morimotob8135862017-10-11 01:37:23 +00001010 dev_err(component->dev,
1011 "ASoC: %s hw params failed: %d\n",
Charles Keepax244e2932018-06-19 16:22:09 +01001012 component->name, ret);
1013 goto component_err;
Kuninori Morimotob8135862017-10-11 01:37:23 +00001014 }
1015 }
Charles Keepax244e2932018-06-19 16:22:09 +01001016 component = NULL;
Kuninori Morimotob8135862017-10-11 01:37:23 +00001017
jiada wang957ce0c2017-09-20 15:25:30 +09001018 ret = soc_pcm_params_symmetry(substream, params);
1019 if (ret)
Kuninori Morimotob8135862017-10-11 01:37:23 +00001020 goto component_err;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001021out:
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +01001022 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001023 return ret;
1024
Kuninori Morimotob8135862017-10-11 01:37:23 +00001025component_err:
Charles Keepax244e2932018-06-19 16:22:09 +01001026 soc_pcm_components_hw_free(substream, component);
Kuninori Morimotob8135862017-10-11 01:37:23 +00001027
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001028 if (cpu_dai->driver->ops->hw_free)
Liam Girdwoodddee6272011-06-09 14:45:53 +01001029 cpu_dai->driver->ops->hw_free(substream, cpu_dai);
Kuninori Morimoto2371abd2019-05-13 16:07:52 +09001030 cpu_dai->rate = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001031
1032interface_err:
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001033 i = rtd->num_codecs;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001034
1035codec_err:
Kuninori Morimoto6d11b122018-09-18 01:28:30 +00001036 for_each_rtd_codec_dai_rollback(rtd, i, codec_dai) {
Jerome Brunetf47b9ad2019-04-29 11:47:50 +02001037 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
1038 continue;
1039
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001040 if (codec_dai->driver->ops->hw_free)
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001041 codec_dai->driver->ops->hw_free(substream, codec_dai);
1042 codec_dai->rate = 0;
1043 }
1044
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +00001045 if (rtd->dai_link->ops->hw_free)
Liam Girdwoodddee6272011-06-09 14:45:53 +01001046 rtd->dai_link->ops->hw_free(substream);
1047
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +01001048 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001049 return ret;
1050}
1051
1052/*
1053 * Frees resources allocated by hw_params, can be called multiple times
1054 */
1055static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
1056{
1057 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001058 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001059 struct snd_soc_dai *codec_dai;
Nicolin Chen7f62b6e2013-12-04 11:18:36 +08001060 bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001061 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001062
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +01001063 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001064
Nicolin Chend3383422013-11-20 18:37:09 +08001065 /* clear the corresponding DAIs parameters when going to be inactive */
1066 if (cpu_dai->active == 1) {
1067 cpu_dai->rate = 0;
1068 cpu_dai->channels = 0;
1069 cpu_dai->sample_bits = 0;
1070 }
1071
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001072 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001073 if (codec_dai->active == 1) {
1074 codec_dai->rate = 0;
1075 codec_dai->channels = 0;
1076 codec_dai->sample_bits = 0;
1077 }
Nicolin Chend3383422013-11-20 18:37:09 +08001078 }
1079
Liam Girdwoodddee6272011-06-09 14:45:53 +01001080 /* apply codec digital mute */
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001081 for_each_rtd_codec_dai(rtd, i, codec_dai) {
1082 if ((playback && codec_dai->playback_active == 1) ||
1083 (!playback && codec_dai->capture_active == 1))
1084 snd_soc_dai_digital_mute(codec_dai, 1,
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001085 substream->stream);
1086 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01001087
1088 /* free any machine hw params */
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +00001089 if (rtd->dai_link->ops->hw_free)
Liam Girdwoodddee6272011-06-09 14:45:53 +01001090 rtd->dai_link->ops->hw_free(substream);
1091
Kuninori Morimotob8135862017-10-11 01:37:23 +00001092 /* free any component resources */
Charles Keepax244e2932018-06-19 16:22:09 +01001093 soc_pcm_components_hw_free(substream, NULL);
Kuninori Morimotob8135862017-10-11 01:37:23 +00001094
Liam Girdwoodddee6272011-06-09 14:45:53 +01001095 /* now free hw params for the DAIs */
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001096 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Jerome Brunetf47b9ad2019-04-29 11:47:50 +02001097 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
1098 continue;
1099
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001100 if (codec_dai->driver->ops->hw_free)
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001101 codec_dai->driver->ops->hw_free(substream, codec_dai);
1102 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01001103
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001104 if (cpu_dai->driver->ops->hw_free)
Liam Girdwoodddee6272011-06-09 14:45:53 +01001105 cpu_dai->driver->ops->hw_free(substream, cpu_dai);
1106
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +01001107 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001108 return 0;
1109}
1110
1111static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1112{
1113 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +00001114 struct snd_soc_component *component;
1115 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001116 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001117 struct snd_soc_dai *codec_dai;
1118 int i, ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001119
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001120 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001121 if (codec_dai->driver->ops->trigger) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001122 ret = codec_dai->driver->ops->trigger(substream,
1123 cmd, codec_dai);
1124 if (ret < 0)
1125 return ret;
1126 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01001127 }
1128
Kuninori Morimotob8135862017-10-11 01:37:23 +00001129 for_each_rtdcom(rtd, rtdcom) {
1130 component = rtdcom->component;
1131
Kuninori Morimotob8135862017-10-11 01:37:23 +00001132 if (!component->driver->ops ||
1133 !component->driver->ops->trigger)
1134 continue;
1135
1136 ret = component->driver->ops->trigger(substream, cmd);
1137 if (ret < 0)
1138 return ret;
1139 }
1140
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001141 if (cpu_dai->driver->ops->trigger) {
Liam Girdwoodddee6272011-06-09 14:45:53 +01001142 ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai);
1143 if (ret < 0)
1144 return ret;
1145 }
Jarkko Nikula4792b0d2014-04-28 14:17:52 +02001146
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +00001147 if (rtd->dai_link->ops->trigger) {
Jarkko Nikula4792b0d2014-04-28 14:17:52 +02001148 ret = rtd->dai_link->ops->trigger(substream, cmd);
1149 if (ret < 0)
1150 return ret;
1151 }
1152
Liam Girdwoodddee6272011-06-09 14:45:53 +01001153 return 0;
1154}
1155
Mark Brown45c0a182012-05-09 21:46:27 +01001156static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
1157 int cmd)
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001158{
1159 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001160 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001161 struct snd_soc_dai *codec_dai;
1162 int i, ret;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001163
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001164 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001165 if (codec_dai->driver->ops->bespoke_trigger) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001166 ret = codec_dai->driver->ops->bespoke_trigger(substream,
1167 cmd, codec_dai);
1168 if (ret < 0)
1169 return ret;
1170 }
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001171 }
1172
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001173 if (cpu_dai->driver->ops->bespoke_trigger) {
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001174 ret = cpu_dai->driver->ops->bespoke_trigger(substream, cmd, cpu_dai);
1175 if (ret < 0)
1176 return ret;
1177 }
1178 return 0;
1179}
Liam Girdwoodddee6272011-06-09 14:45:53 +01001180/*
1181 * soc level wrapper for pointer callback
Charles Keepaxef050be2018-04-24 16:39:02 +01001182 * If cpu_dai, codec_dai, component driver has the delay callback, then
Liam Girdwoodddee6272011-06-09 14:45:53 +01001183 * the runtime->delay will be updated accordingly.
1184 */
1185static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
1186{
1187 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +00001188 struct snd_soc_component *component;
1189 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001190 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001191 struct snd_soc_dai *codec_dai;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001192 struct snd_pcm_runtime *runtime = substream->runtime;
1193 snd_pcm_uframes_t offset = 0;
1194 snd_pcm_sframes_t delay = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001195 snd_pcm_sframes_t codec_delay = 0;
1196 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001197
Akshu Agrawal9fb4c2bf2018-08-01 15:37:33 +05301198 /* clearing the previous total delay */
1199 runtime->delay = 0;
1200
Kuninori Morimotob8135862017-10-11 01:37:23 +00001201 for_each_rtdcom(rtd, rtdcom) {
1202 component = rtdcom->component;
1203
Kuninori Morimotob8135862017-10-11 01:37:23 +00001204 if (!component->driver->ops ||
1205 !component->driver->ops->pointer)
1206 continue;
1207
1208 /* FIXME: use 1st pointer */
1209 offset = component->driver->ops->pointer(substream);
1210 break;
1211 }
Akshu Agrawal9fb4c2bf2018-08-01 15:37:33 +05301212 /* base delay if assigned in pointer callback */
1213 delay = runtime->delay;
Kuninori Morimotob8135862017-10-11 01:37:23 +00001214
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001215 if (cpu_dai->driver->ops->delay)
Liam Girdwoodddee6272011-06-09 14:45:53 +01001216 delay += cpu_dai->driver->ops->delay(substream, cpu_dai);
1217
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001218 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001219 if (codec_dai->driver->ops->delay)
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001220 codec_delay = max(codec_delay,
1221 codec_dai->driver->ops->delay(substream,
1222 codec_dai));
1223 }
1224 delay += codec_delay;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001225
Liam Girdwoodddee6272011-06-09 14:45:53 +01001226 runtime->delay = delay;
1227
1228 return offset;
1229}
1230
Liam Girdwood01d75842012-04-25 12:12:49 +01001231/* connect a FE and BE */
1232static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
1233 struct snd_soc_pcm_runtime *be, int stream)
1234{
1235 struct snd_soc_dpcm *dpcm;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001236 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001237
1238 /* only add new dpcms */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001239 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001240 if (dpcm->be == be && dpcm->fe == fe)
1241 return 0;
1242 }
1243
1244 dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_KERNEL);
1245 if (!dpcm)
1246 return -ENOMEM;
1247
1248 dpcm->be = be;
1249 dpcm->fe = fe;
1250 be->dpcm[stream].runtime = fe->dpcm[stream].runtime;
1251 dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001252 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001253 list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients);
1254 list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001255 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001256
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001257 dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001258 stream ? "capture" : "playback", fe->dai_link->name,
1259 stream ? "<-" : "->", be->dai_link->name);
1260
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001261#ifdef CONFIG_DEBUG_FS
Lars-Peter Clausen6553bf062015-04-09 10:52:38 +02001262 if (fe->debugfs_dpcm_root)
1263 dpcm->debugfs_state = debugfs_create_u32(be->dai_link->name, 0644,
1264 fe->debugfs_dpcm_root, &dpcm->state);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001265#endif
Liam Girdwood01d75842012-04-25 12:12:49 +01001266 return 1;
1267}
1268
1269/* reparent a BE onto another FE */
1270static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
1271 struct snd_soc_pcm_runtime *be, int stream)
1272{
1273 struct snd_soc_dpcm *dpcm;
1274 struct snd_pcm_substream *fe_substream, *be_substream;
1275
1276 /* reparent if BE is connected to other FEs */
1277 if (!be->dpcm[stream].users)
1278 return;
1279
1280 be_substream = snd_soc_dpcm_get_substream(be, stream);
1281
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00001282 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001283 if (dpcm->fe == fe)
1284 continue;
1285
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001286 dev_dbg(fe->dev, "reparent %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001287 stream ? "capture" : "playback",
1288 dpcm->fe->dai_link->name,
1289 stream ? "<-" : "->", dpcm->be->dai_link->name);
1290
1291 fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, stream);
1292 be_substream->runtime = fe_substream->runtime;
1293 break;
1294 }
1295}
1296
1297/* disconnect a BE and FE */
Liam Girdwood23607022014-01-17 17:03:55 +00001298void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001299{
1300 struct snd_soc_dpcm *dpcm, *d;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001301 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001302
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001303 for_each_dpcm_be_safe(fe, stream, dpcm, d) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001304 dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001305 stream ? "capture" : "playback",
1306 dpcm->be->dai_link->name);
1307
1308 if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE)
1309 continue;
1310
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001311 dev_dbg(fe->dev, "freed DSP %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001312 stream ? "capture" : "playback", fe->dai_link->name,
1313 stream ? "<-" : "->", dpcm->be->dai_link->name);
1314
1315 /* BEs still alive need new FE */
1316 dpcm_be_reparent(fe, dpcm->be, stream);
1317
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001318#ifdef CONFIG_DEBUG_FS
1319 debugfs_remove(dpcm->debugfs_state);
1320#endif
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001321 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001322 list_del(&dpcm->list_be);
1323 list_del(&dpcm->list_fe);
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001324 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001325 kfree(dpcm);
1326 }
1327}
1328
1329/* get BE for DAI widget and stream */
1330static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
1331 struct snd_soc_dapm_widget *widget, int stream)
1332{
1333 struct snd_soc_pcm_runtime *be;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001334 struct snd_soc_dai *dai;
Mengdong Lin1a497982015-11-18 02:34:11 -05001335 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01001336
Liam Girdwood3c146462018-03-14 20:43:51 +00001337 dev_dbg(card->dev, "ASoC: find BE for widget %s\n", widget->name);
1338
Liam Girdwood01d75842012-04-25 12:12:49 +01001339 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00001340 for_each_card_rtds(card, be) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001341
Liam Girdwood35ea0652012-06-05 19:26:59 +01001342 if (!be->dai_link->no_pcm)
1343 continue;
1344
Liam Girdwood3c146462018-03-14 20:43:51 +00001345 dev_dbg(card->dev, "ASoC: try BE : %s\n",
1346 be->cpu_dai->playback_widget ?
1347 be->cpu_dai->playback_widget->name : "(not set)");
1348
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001349 if (be->cpu_dai->playback_widget == widget)
Liam Girdwood01d75842012-04-25 12:12:49 +01001350 return be;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001351
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001352 for_each_rtd_codec_dai(be, i, dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001353 if (dai->playback_widget == widget)
1354 return be;
1355 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001356 }
1357 } else {
1358
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00001359 for_each_card_rtds(card, be) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001360
Liam Girdwood35ea0652012-06-05 19:26:59 +01001361 if (!be->dai_link->no_pcm)
1362 continue;
1363
Liam Girdwood3c146462018-03-14 20:43:51 +00001364 dev_dbg(card->dev, "ASoC: try BE %s\n",
1365 be->cpu_dai->capture_widget ?
1366 be->cpu_dai->capture_widget->name : "(not set)");
1367
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001368 if (be->cpu_dai->capture_widget == widget)
Liam Girdwood01d75842012-04-25 12:12:49 +01001369 return be;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001370
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001371 for_each_rtd_codec_dai(be, i, dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001372 if (dai->capture_widget == widget)
1373 return be;
1374 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001375 }
1376 }
1377
Liam Girdwood3c146462018-03-14 20:43:51 +00001378 /* dai link name and stream name set correctly ? */
Liam Girdwood103d84a2012-11-19 14:39:15 +00001379 dev_err(card->dev, "ASoC: can't get %s BE for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001380 stream ? "capture" : "playback", widget->name);
1381 return NULL;
1382}
1383
1384static inline struct snd_soc_dapm_widget *
Benoit Cousson37018612014-04-24 14:01:45 +02001385 dai_get_widget(struct snd_soc_dai *dai, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001386{
1387 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
Benoit Cousson37018612014-04-24 14:01:45 +02001388 return dai->playback_widget;
Liam Girdwood01d75842012-04-25 12:12:49 +01001389 else
Benoit Cousson37018612014-04-24 14:01:45 +02001390 return dai->capture_widget;
Liam Girdwood01d75842012-04-25 12:12:49 +01001391}
1392
1393static int widget_in_list(struct snd_soc_dapm_widget_list *list,
1394 struct snd_soc_dapm_widget *widget)
1395{
1396 int i;
1397
1398 for (i = 0; i < list->num_widgets; i++) {
1399 if (widget == list->widgets[i])
1400 return 1;
1401 }
1402
1403 return 0;
1404}
1405
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001406static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget,
1407 enum snd_soc_dapm_direction dir)
1408{
1409 struct snd_soc_card *card = widget->dapm->card;
1410 struct snd_soc_pcm_runtime *rtd;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001411 struct snd_soc_dai *dai;
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001412 int i;
1413
1414 if (dir == SND_SOC_DAPM_DIR_OUT) {
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00001415 for_each_card_rtds(card, rtd) {
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001416 if (!rtd->dai_link->no_pcm)
1417 continue;
1418
1419 if (rtd->cpu_dai->playback_widget == widget)
1420 return true;
1421
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001422 for_each_rtd_codec_dai(rtd, i, dai) {
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001423 if (dai->playback_widget == widget)
1424 return true;
1425 }
1426 }
1427 } else { /* SND_SOC_DAPM_DIR_IN */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00001428 for_each_card_rtds(card, rtd) {
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001429 if (!rtd->dai_link->no_pcm)
1430 continue;
1431
1432 if (rtd->cpu_dai->capture_widget == widget)
1433 return true;
1434
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001435 for_each_rtd_codec_dai(rtd, i, dai) {
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001436 if (dai->capture_widget == widget)
1437 return true;
1438 }
1439 }
1440 }
1441
1442 return false;
1443}
1444
Liam Girdwood23607022014-01-17 17:03:55 +00001445int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001446 int stream, struct snd_soc_dapm_widget_list **list)
Liam Girdwood01d75842012-04-25 12:12:49 +01001447{
1448 struct snd_soc_dai *cpu_dai = fe->cpu_dai;
Liam Girdwood01d75842012-04-25 12:12:49 +01001449 int paths;
1450
Liam Girdwood01d75842012-04-25 12:12:49 +01001451 /* get number of valid DAI paths and their widgets */
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001452 paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list,
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001453 dpcm_end_walk_at_be);
Liam Girdwood01d75842012-04-25 12:12:49 +01001454
Liam Girdwood103d84a2012-11-19 14:39:15 +00001455 dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths,
Liam Girdwood01d75842012-04-25 12:12:49 +01001456 stream ? "capture" : "playback");
1457
Liam Girdwood01d75842012-04-25 12:12:49 +01001458 return paths;
1459}
1460
Liam Girdwood01d75842012-04-25 12:12:49 +01001461static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
1462 struct snd_soc_dapm_widget_list **list_)
1463{
1464 struct snd_soc_dpcm *dpcm;
1465 struct snd_soc_dapm_widget_list *list = *list_;
1466 struct snd_soc_dapm_widget *widget;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001467 struct snd_soc_dai *dai;
Liam Girdwood01d75842012-04-25 12:12:49 +01001468 int prune = 0;
1469
1470 /* Destroy any old FE <--> BE connections */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001471 for_each_dpcm_be(fe, stream, dpcm) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001472 unsigned int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01001473
1474 /* is there a valid CPU DAI widget for this BE */
Benoit Cousson37018612014-04-24 14:01:45 +02001475 widget = dai_get_widget(dpcm->be->cpu_dai, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001476
1477 /* prune the BE if it's no longer in our active list */
1478 if (widget && widget_in_list(list, widget))
1479 continue;
1480
1481 /* is there a valid CODEC DAI widget for this BE */
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001482 for_each_rtd_codec_dai(dpcm->be, i, dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001483 widget = dai_get_widget(dai, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001484
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001485 /* prune the BE if it's no longer in our active list */
1486 if (widget && widget_in_list(list, widget))
1487 continue;
1488 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001489
Liam Girdwood103d84a2012-11-19 14:39:15 +00001490 dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001491 stream ? "capture" : "playback",
1492 dpcm->be->dai_link->name, fe->dai_link->name);
1493 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
1494 dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1495 prune++;
1496 }
1497
Liam Girdwood103d84a2012-11-19 14:39:15 +00001498 dev_dbg(fe->dev, "ASoC: found %d old BE paths for pruning\n", prune);
Liam Girdwood01d75842012-04-25 12:12:49 +01001499 return prune;
1500}
1501
1502static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
1503 struct snd_soc_dapm_widget_list **list_)
1504{
1505 struct snd_soc_card *card = fe->card;
1506 struct snd_soc_dapm_widget_list *list = *list_;
1507 struct snd_soc_pcm_runtime *be;
1508 int i, new = 0, err;
1509
1510 /* Create any new FE <--> BE connections */
1511 for (i = 0; i < list->num_widgets; i++) {
1512
Mark Brown46162742013-06-05 19:36:11 +01001513 switch (list->widgets[i]->id) {
1514 case snd_soc_dapm_dai_in:
Koro Chenc5b85402015-07-06 10:02:10 +08001515 if (stream != SNDRV_PCM_STREAM_PLAYBACK)
1516 continue;
1517 break;
Mark Brown46162742013-06-05 19:36:11 +01001518 case snd_soc_dapm_dai_out:
Koro Chenc5b85402015-07-06 10:02:10 +08001519 if (stream != SNDRV_PCM_STREAM_CAPTURE)
1520 continue;
Mark Brown46162742013-06-05 19:36:11 +01001521 break;
1522 default:
Liam Girdwood01d75842012-04-25 12:12:49 +01001523 continue;
Mark Brown46162742013-06-05 19:36:11 +01001524 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001525
1526 /* is there a valid BE rtd for this widget */
1527 be = dpcm_get_be(card, list->widgets[i], stream);
1528 if (!be) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001529 dev_err(fe->dev, "ASoC: no BE found for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001530 list->widgets[i]->name);
1531 continue;
1532 }
1533
1534 /* make sure BE is a real BE */
1535 if (!be->dai_link->no_pcm)
1536 continue;
1537
1538 /* don't connect if FE is not running */
Liam Girdwood23607022014-01-17 17:03:55 +00001539 if (!fe->dpcm[stream].runtime && !fe->fe_compr)
Liam Girdwood01d75842012-04-25 12:12:49 +01001540 continue;
1541
1542 /* newly connected FE and BE */
1543 err = dpcm_be_connect(fe, be, stream);
1544 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001545 dev_err(fe->dev, "ASoC: can't connect %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001546 list->widgets[i]->name);
1547 break;
1548 } else if (err == 0) /* already connected */
1549 continue;
1550
1551 /* new */
1552 be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1553 new++;
1554 }
1555
Liam Girdwood103d84a2012-11-19 14:39:15 +00001556 dev_dbg(fe->dev, "ASoC: found %d new BE paths\n", new);
Liam Girdwood01d75842012-04-25 12:12:49 +01001557 return new;
1558}
1559
1560/*
1561 * Find the corresponding BE DAIs that source or sink audio to this
1562 * FE substream.
1563 */
Liam Girdwood23607022014-01-17 17:03:55 +00001564int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
Liam Girdwood01d75842012-04-25 12:12:49 +01001565 int stream, struct snd_soc_dapm_widget_list **list, int new)
1566{
1567 if (new)
1568 return dpcm_add_paths(fe, stream, list);
1569 else
1570 return dpcm_prune_paths(fe, stream, list);
1571}
1572
Liam Girdwood23607022014-01-17 17:03:55 +00001573void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001574{
1575 struct snd_soc_dpcm *dpcm;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001576 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01001577
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001578 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001579 for_each_dpcm_be(fe, stream, dpcm)
Liam Girdwood01d75842012-04-25 12:12:49 +01001580 dpcm->be->dpcm[stream].runtime_update =
1581 SND_SOC_DPCM_UPDATE_NO;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08001582 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01001583}
1584
1585static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe,
1586 int stream)
1587{
1588 struct snd_soc_dpcm *dpcm;
1589
1590 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001591 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001592
1593 struct snd_soc_pcm_runtime *be = dpcm->be;
1594 struct snd_pcm_substream *be_substream =
1595 snd_soc_dpcm_get_substream(be, stream);
1596
1597 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001598 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001599 stream ? "capture" : "playback",
1600 be->dpcm[stream].state);
1601
1602 if (--be->dpcm[stream].users != 0)
1603 continue;
1604
1605 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1606 continue;
1607
1608 soc_pcm_close(be_substream);
1609 be_substream->runtime = NULL;
1610 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1611 }
1612}
1613
Liam Girdwood23607022014-01-17 17:03:55 +00001614int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001615{
1616 struct snd_soc_dpcm *dpcm;
1617 int err, count = 0;
1618
1619 /* only startup BE DAIs that are either sinks or sources to this FE DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001620 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001621
1622 struct snd_soc_pcm_runtime *be = dpcm->be;
1623 struct snd_pcm_substream *be_substream =
1624 snd_soc_dpcm_get_substream(be, stream);
1625
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001626 if (!be_substream) {
1627 dev_err(be->dev, "ASoC: no backend %s stream\n",
1628 stream ? "capture" : "playback");
1629 continue;
1630 }
1631
Liam Girdwood01d75842012-04-25 12:12:49 +01001632 /* is this op for this BE ? */
1633 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1634 continue;
1635
1636 /* first time the dpcm is open ? */
1637 if (be->dpcm[stream].users == DPCM_MAX_BE_USERS)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001638 dev_err(be->dev, "ASoC: too many users %s at open %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001639 stream ? "capture" : "playback",
1640 be->dpcm[stream].state);
1641
1642 if (be->dpcm[stream].users++ != 0)
1643 continue;
1644
1645 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
1646 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
1647 continue;
1648
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001649 dev_dbg(be->dev, "ASoC: open %s BE %s\n",
1650 stream ? "capture" : "playback", be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001651
1652 be_substream->runtime = be->dpcm[stream].runtime;
1653 err = soc_pcm_open(be_substream);
1654 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001655 dev_err(be->dev, "ASoC: BE open failed %d\n", err);
Liam Girdwood01d75842012-04-25 12:12:49 +01001656 be->dpcm[stream].users--;
1657 if (be->dpcm[stream].users < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001658 dev_err(be->dev, "ASoC: no users %s at unwind %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001659 stream ? "capture" : "playback",
1660 be->dpcm[stream].state);
1661
1662 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1663 goto unwind;
1664 }
1665
1666 be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1667 count++;
1668 }
1669
1670 return count;
1671
1672unwind:
1673 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001674 for_each_dpcm_be_rollback(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001675 struct snd_soc_pcm_runtime *be = dpcm->be;
1676 struct snd_pcm_substream *be_substream =
1677 snd_soc_dpcm_get_substream(be, stream);
1678
1679 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1680 continue;
1681
1682 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001683 dev_err(be->dev, "ASoC: no users %s at close %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001684 stream ? "capture" : "playback",
1685 be->dpcm[stream].state);
1686
1687 if (--be->dpcm[stream].users != 0)
1688 continue;
1689
1690 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1691 continue;
1692
1693 soc_pcm_close(be_substream);
1694 be_substream->runtime = NULL;
1695 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1696 }
1697
1698 return err;
1699}
1700
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001701static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
Jerome Brunet435ffb72018-07-05 12:13:48 +02001702 struct snd_soc_pcm_stream *stream)
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001703{
1704 runtime->hw.rate_min = stream->rate_min;
Charles Keepaxe33ffbd9c2018-08-27 14:26:47 +01001705 runtime->hw.rate_max = min_not_zero(stream->rate_max, UINT_MAX);
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001706 runtime->hw.channels_min = stream->channels_min;
1707 runtime->hw.channels_max = stream->channels_max;
Lars-Peter Clausen002220a2014-01-06 14:19:07 +01001708 if (runtime->hw.formats)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001709 runtime->hw.formats &= stream->formats;
Lars-Peter Clausen002220a2014-01-06 14:19:07 +01001710 else
Jerome Brunet435ffb72018-07-05 12:13:48 +02001711 runtime->hw.formats = stream->formats;
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001712 runtime->hw.rates = stream->rates;
1713}
1714
Jerome Brunet435ffb72018-07-05 12:13:48 +02001715static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream,
1716 u64 *formats)
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001717{
1718 struct snd_soc_pcm_runtime *fe = substream->private_data;
1719 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001720 struct snd_soc_dai *dai;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001721 int stream = substream->stream;
1722
1723 if (!fe->dai_link->dpcm_merged_format)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001724 return;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001725
1726 /*
1727 * It returns merged BE codec format
1728 * if FE want to use it (= dpcm_merged_format)
1729 */
1730
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001731 for_each_dpcm_be(fe, stream, dpcm) {
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001732 struct snd_soc_pcm_runtime *be = dpcm->be;
1733 struct snd_soc_dai_driver *codec_dai_drv;
1734 struct snd_soc_pcm_stream *codec_stream;
1735 int i;
1736
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001737 for_each_rtd_codec_dai(be, i, dai) {
Jerome Brunet4febced2018-06-27 17:36:38 +02001738 /*
1739 * Skip CODECs which don't support the current stream
1740 * type. See soc_pcm_init_runtime_hw() for more details
1741 */
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001742 if (!snd_soc_dai_stream_valid(dai, stream))
Jerome Brunet4febced2018-06-27 17:36:38 +02001743 continue;
1744
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001745 codec_dai_drv = dai->driver;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001746 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1747 codec_stream = &codec_dai_drv->playback;
1748 else
1749 codec_stream = &codec_dai_drv->capture;
1750
Jerome Brunet435ffb72018-07-05 12:13:48 +02001751 *formats &= codec_stream->formats;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001752 }
1753 }
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001754}
1755
Jerome Brunet435ffb72018-07-05 12:13:48 +02001756static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream,
1757 unsigned int *channels_min,
1758 unsigned int *channels_max)
Jiada Wangf4c277b2018-06-20 18:25:20 +09001759{
1760 struct snd_soc_pcm_runtime *fe = substream->private_data;
1761 struct snd_soc_dpcm *dpcm;
1762 int stream = substream->stream;
1763
1764 if (!fe->dai_link->dpcm_merged_chan)
1765 return;
1766
Jiada Wangf4c277b2018-06-20 18:25:20 +09001767 /*
1768 * It returns merged BE codec channel;
1769 * if FE want to use it (= dpcm_merged_chan)
1770 */
1771
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001772 for_each_dpcm_be(fe, stream, dpcm) {
Jiada Wangf4c277b2018-06-20 18:25:20 +09001773 struct snd_soc_pcm_runtime *be = dpcm->be;
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001774 struct snd_soc_dai_driver *cpu_dai_drv = be->cpu_dai->driver;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001775 struct snd_soc_dai_driver *codec_dai_drv;
1776 struct snd_soc_pcm_stream *codec_stream;
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001777 struct snd_soc_pcm_stream *cpu_stream;
Jiada Wangf4c277b2018-06-20 18:25:20 +09001778
Jerome Brunet4f2bd182018-06-27 11:48:18 +02001779 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1780 cpu_stream = &cpu_dai_drv->playback;
1781 else
1782 cpu_stream = &cpu_dai_drv->capture;
1783
1784 *channels_min = max(*channels_min, cpu_stream->channels_min);
1785 *channels_max = min(*channels_max, cpu_stream->channels_max);
1786
1787 /*
1788 * chan min/max cannot be enforced if there are multiple CODEC
1789 * DAIs connected to a single CPU DAI, use CPU DAI's directly
1790 */
1791 if (be->num_codecs == 1) {
1792 codec_dai_drv = be->codec_dais[0]->driver;
1793
Jiada Wangf4c277b2018-06-20 18:25:20 +09001794 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1795 codec_stream = &codec_dai_drv->playback;
1796 else
1797 codec_stream = &codec_dai_drv->capture;
1798
1799 *channels_min = max(*channels_min,
1800 codec_stream->channels_min);
1801 *channels_max = min(*channels_max,
1802 codec_stream->channels_max);
1803 }
1804 }
1805}
1806
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001807static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream,
1808 unsigned int *rates,
1809 unsigned int *rate_min,
1810 unsigned int *rate_max)
1811{
1812 struct snd_soc_pcm_runtime *fe = substream->private_data;
1813 struct snd_soc_dpcm *dpcm;
1814 int stream = substream->stream;
1815
1816 if (!fe->dai_link->dpcm_merged_rate)
1817 return;
1818
1819 /*
1820 * It returns merged BE codec channel;
1821 * if FE want to use it (= dpcm_merged_chan)
1822 */
1823
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001824 for_each_dpcm_be(fe, stream, dpcm) {
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001825 struct snd_soc_pcm_runtime *be = dpcm->be;
1826 struct snd_soc_dai_driver *cpu_dai_drv = be->cpu_dai->driver;
1827 struct snd_soc_dai_driver *codec_dai_drv;
1828 struct snd_soc_pcm_stream *codec_stream;
1829 struct snd_soc_pcm_stream *cpu_stream;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001830 struct snd_soc_dai *dai;
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001831 int i;
1832
1833 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1834 cpu_stream = &cpu_dai_drv->playback;
1835 else
1836 cpu_stream = &cpu_dai_drv->capture;
1837
1838 *rate_min = max(*rate_min, cpu_stream->rate_min);
1839 *rate_max = min_not_zero(*rate_max, cpu_stream->rate_max);
1840 *rates = snd_pcm_rate_mask_intersect(*rates, cpu_stream->rates);
1841
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001842 for_each_rtd_codec_dai(be, i, dai) {
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001843 /*
1844 * Skip CODECs which don't support the current stream
1845 * type. See soc_pcm_init_runtime_hw() for more details
1846 */
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001847 if (!snd_soc_dai_stream_valid(dai, stream))
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001848 continue;
1849
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00001850 codec_dai_drv = dai->driver;
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001851 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1852 codec_stream = &codec_dai_drv->playback;
1853 else
1854 codec_stream = &codec_dai_drv->capture;
1855
1856 *rate_min = max(*rate_min, codec_stream->rate_min);
1857 *rate_max = min_not_zero(*rate_max,
1858 codec_stream->rate_max);
1859 *rates = snd_pcm_rate_mask_intersect(*rates,
1860 codec_stream->rates);
1861 }
1862 }
1863}
1864
Mark Brown45c0a182012-05-09 21:46:27 +01001865static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001866{
1867 struct snd_pcm_runtime *runtime = substream->runtime;
1868 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1869 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
1870 struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
1871
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001872 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
Jerome Brunet435ffb72018-07-05 12:13:48 +02001873 dpcm_init_runtime_hw(runtime, &cpu_dai_drv->playback);
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001874 else
Jerome Brunet435ffb72018-07-05 12:13:48 +02001875 dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture);
Jiada Wangf4c277b2018-06-20 18:25:20 +09001876
Jerome Brunet435ffb72018-07-05 12:13:48 +02001877 dpcm_runtime_merge_format(substream, &runtime->hw.formats);
1878 dpcm_runtime_merge_chan(substream, &runtime->hw.channels_min,
1879 &runtime->hw.channels_max);
Jerome Brunetbaacd8d2018-07-05 12:13:49 +02001880 dpcm_runtime_merge_rate(substream, &runtime->hw.rates,
1881 &runtime->hw.rate_min, &runtime->hw.rate_max);
Liam Girdwood01d75842012-04-25 12:12:49 +01001882}
1883
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001884static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
1885
1886/* Set FE's runtime_update state; the state is protected via PCM stream lock
1887 * for avoiding the race with trigger callback.
1888 * If the state is unset and a trigger is pending while the previous operation,
1889 * process the pending trigger action here.
1890 */
1891static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
1892 int stream, enum snd_soc_dpcm_update state)
1893{
1894 struct snd_pcm_substream *substream =
1895 snd_soc_dpcm_get_substream(fe, stream);
1896
1897 snd_pcm_stream_lock_irq(substream);
1898 if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) {
1899 dpcm_fe_dai_do_trigger(substream,
1900 fe->dpcm[stream].trigger_pending - 1);
1901 fe->dpcm[stream].trigger_pending = 0;
1902 }
1903 fe->dpcm[stream].runtime_update = state;
1904 snd_pcm_stream_unlock_irq(substream);
1905}
1906
PC Liao906c7d62015-12-11 11:33:51 +08001907static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
1908 int stream)
1909{
1910 struct snd_soc_dpcm *dpcm;
1911 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
1912 struct snd_soc_dai *fe_cpu_dai = fe->cpu_dai;
1913 int err;
1914
1915 /* apply symmetry for FE */
1916 if (soc_pcm_has_symmetry(fe_substream))
1917 fe_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1918
1919 /* Symmetry only applies if we've got an active stream. */
1920 if (fe_cpu_dai->active) {
1921 err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai);
1922 if (err < 0)
1923 return err;
1924 }
1925
1926 /* apply symmetry for BE */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00001927 for_each_dpcm_be(fe, stream, dpcm) {
PC Liao906c7d62015-12-11 11:33:51 +08001928 struct snd_soc_pcm_runtime *be = dpcm->be;
1929 struct snd_pcm_substream *be_substream =
1930 snd_soc_dpcm_get_substream(be, stream);
Jerome Brunet6246f282019-04-01 15:03:54 +02001931 struct snd_soc_pcm_runtime *rtd;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001932 struct snd_soc_dai *codec_dai;
PC Liao906c7d62015-12-11 11:33:51 +08001933 int i;
1934
Jerome Brunet6246f282019-04-01 15:03:54 +02001935 /* A backend may not have the requested substream */
1936 if (!be_substream)
1937 continue;
1938
1939 rtd = be_substream->private_data;
Jeeja KPf1176612016-09-06 14:17:55 +05301940 if (rtd->dai_link->be_hw_params_fixup)
1941 continue;
1942
PC Liao906c7d62015-12-11 11:33:51 +08001943 if (soc_pcm_has_symmetry(be_substream))
1944 be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1945
1946 /* Symmetry only applies if we've got an active stream. */
1947 if (rtd->cpu_dai->active) {
Kai Chieh Chuang99bcedb2018-05-28 10:18:19 +08001948 err = soc_pcm_apply_symmetry(fe_substream,
1949 rtd->cpu_dai);
PC Liao906c7d62015-12-11 11:33:51 +08001950 if (err < 0)
1951 return err;
1952 }
1953
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001954 for_each_rtd_codec_dai(rtd, i, codec_dai) {
1955 if (codec_dai->active) {
Kai Chieh Chuang99bcedb2018-05-28 10:18:19 +08001956 err = soc_pcm_apply_symmetry(fe_substream,
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00001957 codec_dai);
PC Liao906c7d62015-12-11 11:33:51 +08001958 if (err < 0)
1959 return err;
1960 }
1961 }
1962 }
1963
1964 return 0;
1965}
1966
Liam Girdwood01d75842012-04-25 12:12:49 +01001967static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
1968{
1969 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
1970 struct snd_pcm_runtime *runtime = fe_substream->runtime;
1971 int stream = fe_substream->stream, ret = 0;
1972
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001973 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001974
1975 ret = dpcm_be_dai_startup(fe, fe_substream->stream);
1976 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001977 dev_err(fe->dev,"ASoC: failed to start some BEs %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001978 goto be_err;
1979 }
1980
Liam Girdwood103d84a2012-11-19 14:39:15 +00001981 dev_dbg(fe->dev, "ASoC: open FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001982
1983 /* start the DAI frontend */
1984 ret = soc_pcm_open(fe_substream);
1985 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001986 dev_err(fe->dev,"ASoC: failed to start FE %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001987 goto unwind;
1988 }
1989
1990 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1991
1992 dpcm_set_fe_runtime(fe_substream);
1993 snd_pcm_limit_hw_rates(runtime);
1994
PC Liao906c7d62015-12-11 11:33:51 +08001995 ret = dpcm_apply_symmetry(fe_substream, stream);
1996 if (ret < 0) {
1997 dev_err(fe->dev, "ASoC: failed to apply dpcm symmetry %d\n",
1998 ret);
1999 goto unwind;
2000 }
2001
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002002 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002003 return 0;
2004
2005unwind:
2006 dpcm_be_dai_startup_unwind(fe, fe_substream->stream);
2007be_err:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002008 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002009 return ret;
2010}
2011
Liam Girdwood23607022014-01-17 17:03:55 +00002012int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002013{
2014 struct snd_soc_dpcm *dpcm;
2015
2016 /* only shutdown BEs that are either sinks or sources to this FE DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002017 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002018
2019 struct snd_soc_pcm_runtime *be = dpcm->be;
2020 struct snd_pcm_substream *be_substream =
2021 snd_soc_dpcm_get_substream(be, stream);
2022
2023 /* is this op for this BE ? */
2024 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2025 continue;
2026
2027 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002028 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002029 stream ? "capture" : "playback",
2030 be->dpcm[stream].state);
2031
2032 if (--be->dpcm[stream].users != 0)
2033 continue;
2034
2035 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Kai Chieh Chuang9c0ac702018-05-28 10:18:18 +08002036 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) {
2037 soc_pcm_hw_free(be_substream);
2038 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
2039 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002040
Liam Girdwood103d84a2012-11-19 14:39:15 +00002041 dev_dbg(be->dev, "ASoC: close BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002042 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002043
2044 soc_pcm_close(be_substream);
2045 be_substream->runtime = NULL;
2046
2047 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
2048 }
2049 return 0;
2050}
2051
2052static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
2053{
2054 struct snd_soc_pcm_runtime *fe = substream->private_data;
2055 int stream = substream->stream;
2056
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002057 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002058
2059 /* shutdown the BEs */
2060 dpcm_be_dai_shutdown(fe, substream->stream);
2061
Liam Girdwood103d84a2012-11-19 14:39:15 +00002062 dev_dbg(fe->dev, "ASoC: close FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002063
2064 /* now shutdown the frontend */
2065 soc_pcm_close(substream);
2066
2067 /* run the stream event for each BE */
2068 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
2069
2070 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002071 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002072 return 0;
2073}
2074
Liam Girdwood23607022014-01-17 17:03:55 +00002075int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002076{
2077 struct snd_soc_dpcm *dpcm;
2078
2079 /* only hw_params backends that are either sinks or sources
2080 * to this frontend DAI */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002081 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002082
2083 struct snd_soc_pcm_runtime *be = dpcm->be;
2084 struct snd_pcm_substream *be_substream =
2085 snd_soc_dpcm_get_substream(be, stream);
2086
2087 /* is this op for this BE ? */
2088 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2089 continue;
2090
2091 /* only free hw when no longer used - check all FEs */
2092 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2093 continue;
2094
Qiao Zhou36fba622014-12-03 10:13:43 +08002095 /* do not free hw if this BE is used by other FE */
2096 if (be->dpcm[stream].users > 1)
2097 continue;
2098
Liam Girdwood01d75842012-04-25 12:12:49 +01002099 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2100 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
2101 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Patrick Lai08b27842012-12-19 19:36:02 -08002102 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
Vinod Koul5e82d2b2016-02-01 22:26:40 +05302103 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
2104 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
Liam Girdwood01d75842012-04-25 12:12:49 +01002105 continue;
2106
Liam Girdwood103d84a2012-11-19 14:39:15 +00002107 dev_dbg(be->dev, "ASoC: hw_free BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002108 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002109
2110 soc_pcm_hw_free(be_substream);
2111
2112 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
2113 }
2114
2115 return 0;
2116}
2117
Mark Brown45c0a182012-05-09 21:46:27 +01002118static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002119{
2120 struct snd_soc_pcm_runtime *fe = substream->private_data;
2121 int err, stream = substream->stream;
2122
2123 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002124 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002125
Liam Girdwood103d84a2012-11-19 14:39:15 +00002126 dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002127
2128 /* call hw_free on the frontend */
2129 err = soc_pcm_hw_free(substream);
2130 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002131 dev_err(fe->dev,"ASoC: hw_free FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002132 fe->dai_link->name);
2133
2134 /* only hw_params backends that are either sinks or sources
2135 * to this frontend DAI */
2136 err = dpcm_be_dai_hw_free(fe, stream);
2137
2138 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002139 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002140
2141 mutex_unlock(&fe->card->mutex);
2142 return 0;
2143}
2144
Liam Girdwood23607022014-01-17 17:03:55 +00002145int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002146{
2147 struct snd_soc_dpcm *dpcm;
2148 int ret;
2149
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002150 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002151
2152 struct snd_soc_pcm_runtime *be = dpcm->be;
2153 struct snd_pcm_substream *be_substream =
2154 snd_soc_dpcm_get_substream(be, stream);
2155
2156 /* is this op for this BE ? */
2157 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2158 continue;
2159
Liam Girdwood01d75842012-04-25 12:12:49 +01002160 /* copy params for each dpcm */
2161 memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params,
2162 sizeof(struct snd_pcm_hw_params));
2163
2164 /* perform any hw_params fixups */
2165 if (be->dai_link->be_hw_params_fixup) {
2166 ret = be->dai_link->be_hw_params_fixup(be,
2167 &dpcm->hw_params);
2168 if (ret < 0) {
2169 dev_err(be->dev,
Liam Girdwood103d84a2012-11-19 14:39:15 +00002170 "ASoC: hw_params BE fixup failed %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002171 ret);
2172 goto unwind;
2173 }
2174 }
2175
Libin Yangae061d22019-04-19 09:53:12 +08002176 /* copy the fixed-up hw params for BE dai */
2177 memcpy(&be->dpcm[stream].hw_params, &dpcm->hw_params,
2178 sizeof(struct snd_pcm_hw_params));
2179
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00002180 /* only allow hw_params() if no connected FEs are running */
2181 if (!snd_soc_dpcm_can_be_params(fe, be, stream))
2182 continue;
2183
2184 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
2185 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2186 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE))
2187 continue;
2188
2189 dev_dbg(be->dev, "ASoC: hw_params BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002190 be->dai_link->name);
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00002191
Liam Girdwood01d75842012-04-25 12:12:49 +01002192 ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params);
2193 if (ret < 0) {
2194 dev_err(dpcm->be->dev,
Liam Girdwood103d84a2012-11-19 14:39:15 +00002195 "ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002196 goto unwind;
2197 }
2198
2199 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2200 }
2201 return 0;
2202
2203unwind:
2204 /* disable any enabled and non active backends */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002205 for_each_dpcm_be_rollback(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002206 struct snd_soc_pcm_runtime *be = dpcm->be;
2207 struct snd_pcm_substream *be_substream =
2208 snd_soc_dpcm_get_substream(be, stream);
2209
2210 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2211 continue;
2212
2213 /* only allow hw_free() if no connected FEs are running */
2214 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2215 continue;
2216
2217 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
2218 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2219 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
2220 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
2221 continue;
2222
2223 soc_pcm_hw_free(be_substream);
2224 }
2225
2226 return ret;
2227}
2228
Mark Brown45c0a182012-05-09 21:46:27 +01002229static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
2230 struct snd_pcm_hw_params *params)
Liam Girdwood01d75842012-04-25 12:12:49 +01002231{
2232 struct snd_soc_pcm_runtime *fe = substream->private_data;
2233 int ret, stream = substream->stream;
2234
2235 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002236 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002237
2238 memcpy(&fe->dpcm[substream->stream].hw_params, params,
2239 sizeof(struct snd_pcm_hw_params));
2240 ret = dpcm_be_dai_hw_params(fe, substream->stream);
2241 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002242 dev_err(fe->dev,"ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002243 goto out;
2244 }
2245
Liam Girdwood103d84a2012-11-19 14:39:15 +00002246 dev_dbg(fe->dev, "ASoC: hw_params FE %s rate %d chan %x fmt %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002247 fe->dai_link->name, params_rate(params),
2248 params_channels(params), params_format(params));
2249
2250 /* call hw_params on the frontend */
2251 ret = soc_pcm_hw_params(substream, params);
2252 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002253 dev_err(fe->dev,"ASoC: hw_params FE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002254 dpcm_be_dai_hw_free(fe, stream);
2255 } else
2256 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2257
2258out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002259 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002260 mutex_unlock(&fe->card->mutex);
2261 return ret;
2262}
2263
2264static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm,
2265 struct snd_pcm_substream *substream, int cmd)
2266{
2267 int ret;
2268
Liam Girdwood103d84a2012-11-19 14:39:15 +00002269 dev_dbg(dpcm->be->dev, "ASoC: trigger BE %s cmd %d\n",
彭东林94d215c2016-09-26 08:29:31 +00002270 dpcm->be->dai_link->name, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002271
2272 ret = soc_pcm_trigger(substream, cmd);
2273 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002274 dev_err(dpcm->be->dev,"ASoC: trigger BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002275
2276 return ret;
2277}
2278
Liam Girdwood23607022014-01-17 17:03:55 +00002279int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
Mark Brown45c0a182012-05-09 21:46:27 +01002280 int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002281{
2282 struct snd_soc_dpcm *dpcm;
2283 int ret = 0;
2284
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002285 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002286
2287 struct snd_soc_pcm_runtime *be = dpcm->be;
2288 struct snd_pcm_substream *be_substream =
2289 snd_soc_dpcm_get_substream(be, stream);
2290
2291 /* is this op for this BE ? */
2292 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2293 continue;
2294
2295 switch (cmd) {
2296 case SNDRV_PCM_TRIGGER_START:
2297 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
2298 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
2299 continue;
2300
2301 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2302 if (ret)
2303 return ret;
2304
2305 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2306 break;
2307 case SNDRV_PCM_TRIGGER_RESUME:
2308 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
2309 continue;
2310
2311 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2312 if (ret)
2313 return ret;
2314
2315 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2316 break;
2317 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2318 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
2319 continue;
2320
2321 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2322 if (ret)
2323 return ret;
2324
2325 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2326 break;
2327 case SNDRV_PCM_TRIGGER_STOP:
2328 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2329 continue;
2330
2331 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2332 continue;
2333
2334 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2335 if (ret)
2336 return ret;
2337
2338 be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2339 break;
2340 case SNDRV_PCM_TRIGGER_SUSPEND:
Nicolin Chen868a6ca2014-05-12 20:12:05 +08002341 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
Liam Girdwood01d75842012-04-25 12:12:49 +01002342 continue;
2343
2344 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2345 continue;
2346
2347 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2348 if (ret)
2349 return ret;
2350
2351 be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND;
2352 break;
2353 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2354 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2355 continue;
2356
2357 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2358 continue;
2359
2360 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2361 if (ret)
2362 return ret;
2363
2364 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2365 break;
2366 }
2367 }
2368
2369 return ret;
2370}
2371EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
2372
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002373static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002374{
2375 struct snd_soc_pcm_runtime *fe = substream->private_data;
2376 int stream = substream->stream, ret;
2377 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
2378
2379 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
2380
2381 switch (trigger) {
2382 case SND_SOC_DPCM_TRIGGER_PRE:
2383 /* call trigger on the frontend before the backend. */
2384
Liam Girdwood103d84a2012-11-19 14:39:15 +00002385 dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002386 fe->dai_link->name, cmd);
2387
2388 ret = soc_pcm_trigger(substream, cmd);
2389 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002390 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002391 goto out;
2392 }
2393
2394 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2395 break;
2396 case SND_SOC_DPCM_TRIGGER_POST:
2397 /* call trigger on the frontend after the backend. */
2398
2399 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2400 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002401 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002402 goto out;
2403 }
2404
Liam Girdwood103d84a2012-11-19 14:39:15 +00002405 dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002406 fe->dai_link->name, cmd);
2407
2408 ret = soc_pcm_trigger(substream, cmd);
2409 break;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002410 case SND_SOC_DPCM_TRIGGER_BESPOKE:
2411 /* bespoke trigger() - handles both FE and BEs */
2412
Liam Girdwood103d84a2012-11-19 14:39:15 +00002413 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd %d\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002414 fe->dai_link->name, cmd);
2415
2416 ret = soc_pcm_bespoke_trigger(substream, cmd);
2417 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002418 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002419 goto out;
2420 }
2421 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002422 default:
Liam Girdwood103d84a2012-11-19 14:39:15 +00002423 dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd,
Liam Girdwood01d75842012-04-25 12:12:49 +01002424 fe->dai_link->name);
2425 ret = -EINVAL;
2426 goto out;
2427 }
2428
2429 switch (cmd) {
2430 case SNDRV_PCM_TRIGGER_START:
2431 case SNDRV_PCM_TRIGGER_RESUME:
2432 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2433 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2434 break;
2435 case SNDRV_PCM_TRIGGER_STOP:
2436 case SNDRV_PCM_TRIGGER_SUSPEND:
Liam Girdwood01d75842012-04-25 12:12:49 +01002437 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2438 break;
Patrick Lai9f169b92016-12-31 22:44:39 -08002439 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2440 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2441 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002442 }
2443
2444out:
2445 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
2446 return ret;
2447}
2448
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002449static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
2450{
2451 struct snd_soc_pcm_runtime *fe = substream->private_data;
2452 int stream = substream->stream;
2453
2454 /* if FE's runtime_update is already set, we're in race;
2455 * process this trigger later at exit
2456 */
2457 if (fe->dpcm[stream].runtime_update != SND_SOC_DPCM_UPDATE_NO) {
2458 fe->dpcm[stream].trigger_pending = cmd + 1;
2459 return 0; /* delayed, assuming it's successful */
2460 }
2461
2462 /* we're alone, let's trigger */
2463 return dpcm_fe_dai_do_trigger(substream, cmd);
2464}
2465
Liam Girdwood23607022014-01-17 17:03:55 +00002466int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002467{
2468 struct snd_soc_dpcm *dpcm;
2469 int ret = 0;
2470
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002471 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002472
2473 struct snd_soc_pcm_runtime *be = dpcm->be;
2474 struct snd_pcm_substream *be_substream =
2475 snd_soc_dpcm_get_substream(be, stream);
2476
2477 /* is this op for this BE ? */
2478 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2479 continue;
2480
2481 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
Koro Chen95f444d2015-10-28 10:15:34 +08002482 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
2483 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
Liam Girdwood01d75842012-04-25 12:12:49 +01002484 continue;
2485
Liam Girdwood103d84a2012-11-19 14:39:15 +00002486 dev_dbg(be->dev, "ASoC: prepare BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002487 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002488
2489 ret = soc_pcm_prepare(be_substream);
2490 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002491 dev_err(be->dev, "ASoC: backend prepare failed %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002492 ret);
2493 break;
2494 }
2495
2496 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2497 }
2498 return ret;
2499}
2500
Mark Brown45c0a182012-05-09 21:46:27 +01002501static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002502{
2503 struct snd_soc_pcm_runtime *fe = substream->private_data;
2504 int stream = substream->stream, ret = 0;
2505
2506 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2507
Liam Girdwood103d84a2012-11-19 14:39:15 +00002508 dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002509
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002510 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002511
2512 /* there is no point preparing this FE if there are no BEs */
2513 if (list_empty(&fe->dpcm[stream].be_clients)) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002514 dev_err(fe->dev, "ASoC: no backend DAIs enabled for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002515 fe->dai_link->name);
2516 ret = -EINVAL;
2517 goto out;
2518 }
2519
2520 ret = dpcm_be_dai_prepare(fe, substream->stream);
2521 if (ret < 0)
2522 goto out;
2523
2524 /* call prepare on the frontend */
2525 ret = soc_pcm_prepare(substream);
2526 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002527 dev_err(fe->dev,"ASoC: prepare FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002528 fe->dai_link->name);
2529 goto out;
2530 }
2531
2532 /* run the stream event for each BE */
2533 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
2534 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2535
2536out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002537 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002538 mutex_unlock(&fe->card->mutex);
2539
2540 return ret;
2541}
2542
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01002543static int soc_pcm_ioctl(struct snd_pcm_substream *substream,
2544 unsigned int cmd, void *arg)
2545{
2546 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +00002547 struct snd_soc_component *component;
2548 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01002549
Kuninori Morimotob8135862017-10-11 01:37:23 +00002550 for_each_rtdcom(rtd, rtdcom) {
2551 component = rtdcom->component;
2552
Kuninori Morimotob8135862017-10-11 01:37:23 +00002553 if (!component->driver->ops ||
2554 !component->driver->ops->ioctl)
2555 continue;
2556
2557 /* FIXME: use 1st ioctl */
2558 return component->driver->ops->ioctl(substream, cmd, arg);
2559 }
2560
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01002561 return snd_pcm_lib_ioctl(substream, cmd, arg);
2562}
2563
Liam Girdwood618dae12012-04-25 12:12:51 +01002564static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
2565{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002566 struct snd_pcm_substream *substream =
2567 snd_soc_dpcm_get_substream(fe, stream);
2568 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01002569 int err;
Liam Girdwood01d75842012-04-25 12:12:49 +01002570
Liam Girdwood103d84a2012-11-19 14:39:15 +00002571 dev_dbg(fe->dev, "ASoC: runtime %s close on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002572 stream ? "capture" : "playback", fe->dai_link->name);
2573
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002574 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2575 /* call bespoke trigger - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002576 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002577 fe->dai_link->name);
2578
2579 err = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
2580 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002581 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002582 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002583 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002584 fe->dai_link->name);
2585
2586 err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
2587 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002588 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002589 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002590
2591 err = dpcm_be_dai_hw_free(fe, stream);
2592 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002593 dev_err(fe->dev,"ASoC: hw_free FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002594
2595 err = dpcm_be_dai_shutdown(fe, stream);
2596 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002597 dev_err(fe->dev,"ASoC: shutdown FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002598
2599 /* run the stream event for each BE */
2600 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2601
2602 return 0;
2603}
2604
2605static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
2606{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002607 struct snd_pcm_substream *substream =
2608 snd_soc_dpcm_get_substream(fe, stream);
Liam Girdwood618dae12012-04-25 12:12:51 +01002609 struct snd_soc_dpcm *dpcm;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002610 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01002611 int ret;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002612 unsigned long flags;
Liam Girdwood618dae12012-04-25 12:12:51 +01002613
Liam Girdwood103d84a2012-11-19 14:39:15 +00002614 dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002615 stream ? "capture" : "playback", fe->dai_link->name);
2616
2617 /* Only start the BE if the FE is ready */
2618 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
2619 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE)
2620 return -EINVAL;
2621
2622 /* startup must always be called for new BEs */
2623 ret = dpcm_be_dai_startup(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002624 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002625 goto disconnect;
Liam Girdwood618dae12012-04-25 12:12:51 +01002626
2627 /* keep going if FE state is > open */
2628 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN)
2629 return 0;
2630
2631 ret = dpcm_be_dai_hw_params(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002632 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002633 goto close;
Liam Girdwood618dae12012-04-25 12:12:51 +01002634
2635 /* keep going if FE state is > hw_params */
2636 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS)
2637 return 0;
2638
2639
2640 ret = dpcm_be_dai_prepare(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002641 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002642 goto hw_free;
Liam Girdwood618dae12012-04-25 12:12:51 +01002643
2644 /* run the stream event for each BE */
2645 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2646
2647 /* keep going if FE state is > prepare */
2648 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE ||
2649 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP)
2650 return 0;
2651
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002652 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2653 /* call trigger on the frontend - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002654 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002655 fe->dai_link->name);
Liam Girdwood618dae12012-04-25 12:12:51 +01002656
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002657 ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
2658 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002659 dev_err(fe->dev,"ASoC: bespoke trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002660 goto hw_free;
2661 }
2662 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002663 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002664 fe->dai_link->name);
2665
2666 ret = dpcm_be_dai_trigger(fe, stream,
2667 SNDRV_PCM_TRIGGER_START);
2668 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002669 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002670 goto hw_free;
2671 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002672 }
2673
2674 return 0;
2675
2676hw_free:
2677 dpcm_be_dai_hw_free(fe, stream);
2678close:
2679 dpcm_be_dai_shutdown(fe, stream);
2680disconnect:
2681 /* disconnect any non started BEs */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002682 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002683 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwood618dae12012-04-25 12:12:51 +01002684 struct snd_soc_pcm_runtime *be = dpcm->be;
2685 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2686 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2687 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08002688 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood618dae12012-04-25 12:12:51 +01002689
2690 return ret;
2691}
2692
2693static int dpcm_run_new_update(struct snd_soc_pcm_runtime *fe, int stream)
2694{
2695 int ret;
2696
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002697 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood618dae12012-04-25 12:12:51 +01002698 ret = dpcm_run_update_startup(fe, stream);
2699 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002700 dev_err(fe->dev, "ASoC: failed to startup some BEs\n");
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002701 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood618dae12012-04-25 12:12:51 +01002702
2703 return ret;
2704}
2705
2706static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream)
2707{
2708 int ret;
2709
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002710 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood618dae12012-04-25 12:12:51 +01002711 ret = dpcm_run_update_shutdown(fe, stream);
2712 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002713 dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n");
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002714 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood618dae12012-04-25 12:12:51 +01002715
2716 return ret;
2717}
2718
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002719static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
2720{
2721 struct snd_soc_dapm_widget_list *list;
2722 int count, paths;
2723
2724 if (!fe->dai_link->dynamic)
2725 return 0;
2726
2727 /* only check active links */
2728 if (!fe->cpu_dai->active)
2729 return 0;
2730
2731 /* DAPM sync will call this to update DSP paths */
2732 dev_dbg(fe->dev, "ASoC: DPCM %s runtime update for FE %s\n",
2733 new ? "new" : "old", fe->dai_link->name);
2734
2735 /* skip if FE doesn't have playback capability */
2736 if (!fe->cpu_dai->driver->playback.channels_min ||
2737 !fe->codec_dai->driver->playback.channels_min)
2738 goto capture;
2739
2740 /* skip if FE isn't currently playing */
2741 if (!fe->cpu_dai->playback_active || !fe->codec_dai->playback_active)
2742 goto capture;
2743
2744 paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list);
2745 if (paths < 0) {
2746 dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
2747 fe->dai_link->name, "playback");
2748 return paths;
2749 }
2750
2751 /* update any playback paths */
2752 count = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, new);
2753 if (count) {
2754 if (new)
2755 dpcm_run_new_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
2756 else
2757 dpcm_run_old_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
2758
2759 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
2760 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
2761 }
2762
2763 dpcm_path_put(&list);
2764
2765capture:
2766 /* skip if FE doesn't have capture capability */
2767 if (!fe->cpu_dai->driver->capture.channels_min ||
2768 !fe->codec_dai->driver->capture.channels_min)
2769 return 0;
2770
2771 /* skip if FE isn't currently capturing */
2772 if (!fe->cpu_dai->capture_active || !fe->codec_dai->capture_active)
2773 return 0;
2774
2775 paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list);
2776 if (paths < 0) {
2777 dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
2778 fe->dai_link->name, "capture");
2779 return paths;
2780 }
2781
2782 /* update any old capture paths */
2783 count = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, new);
2784 if (count) {
2785 if (new)
2786 dpcm_run_new_update(fe, SNDRV_PCM_STREAM_CAPTURE);
2787 else
2788 dpcm_run_old_update(fe, SNDRV_PCM_STREAM_CAPTURE);
2789
2790 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
2791 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
2792 }
2793
2794 dpcm_path_put(&list);
2795
2796 return 0;
2797}
2798
Liam Girdwood618dae12012-04-25 12:12:51 +01002799/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
2800 * any DAI links.
2801 */
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002802int soc_dpcm_runtime_update(struct snd_soc_card *card)
Liam Girdwood618dae12012-04-25 12:12:51 +01002803{
Mengdong Lin1a497982015-11-18 02:34:11 -05002804 struct snd_soc_pcm_runtime *fe;
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002805 int ret = 0;
Liam Girdwood618dae12012-04-25 12:12:51 +01002806
Liam Girdwood618dae12012-04-25 12:12:51 +01002807 mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002808 /* shutdown all old paths first */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002809 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002810 ret = soc_dpcm_fe_runtime_update(fe, 0);
2811 if (ret)
2812 goto out;
Liam Girdwood618dae12012-04-25 12:12:51 +01002813 }
2814
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002815 /* bring new paths up */
Kuninori Morimotobcb1fd12018-09-18 01:29:35 +00002816 for_each_card_rtds(card, fe) {
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002817 ret = soc_dpcm_fe_runtime_update(fe, 1);
2818 if (ret)
2819 goto out;
2820 }
2821
2822out:
Liam Girdwood618dae12012-04-25 12:12:51 +01002823 mutex_unlock(&card->mutex);
Jerome Brunetde15d7ff2018-06-26 12:07:25 +02002824 return ret;
Liam Girdwood618dae12012-04-25 12:12:51 +01002825}
Liam Girdwood01d75842012-04-25 12:12:49 +01002826int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute)
2827{
2828 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00002829 struct snd_soc_dai *dai;
Liam Girdwood01d75842012-04-25 12:12:49 +01002830
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002831 for_each_dpcm_be(fe, SNDRV_PCM_STREAM_PLAYBACK, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01002832
2833 struct snd_soc_pcm_runtime *be = dpcm->be;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002834 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01002835
2836 if (be->dai_link->ignore_suspend)
2837 continue;
2838
Kuninori Morimoto7afecb32018-09-18 01:28:04 +00002839 for_each_rtd_codec_dai(be, i, dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002840 struct snd_soc_dai_driver *drv = dai->driver;
Liam Girdwood01d75842012-04-25 12:12:49 +01002841
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002842 dev_dbg(be->dev, "ASoC: BE digital mute %s\n",
2843 be->dai_link->name);
2844
2845 if (drv->ops && drv->ops->digital_mute &&
2846 dai->playback_active)
2847 drv->ops->digital_mute(dai, mute);
2848 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002849 }
2850
2851 return 0;
2852}
2853
Mark Brown45c0a182012-05-09 21:46:27 +01002854static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002855{
2856 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
2857 struct snd_soc_dpcm *dpcm;
2858 struct snd_soc_dapm_widget_list *list;
2859 int ret;
2860 int stream = fe_substream->stream;
2861
2862 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2863 fe->dpcm[stream].runtime = fe_substream->runtime;
2864
Qiao Zhou8f70e512014-09-10 17:54:07 +08002865 ret = dpcm_path_get(fe, stream, &list);
2866 if (ret < 0) {
2867 mutex_unlock(&fe->card->mutex);
2868 return ret;
2869 } else if (ret == 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002870 dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002871 fe->dai_link->name, stream ? "capture" : "playback");
Liam Girdwood01d75842012-04-25 12:12:49 +01002872 }
2873
2874 /* calculate valid and active FE <-> BE dpcms */
2875 dpcm_process_paths(fe, stream, &list, 1);
2876
2877 ret = dpcm_fe_dai_startup(fe_substream);
2878 if (ret < 0) {
2879 /* clean up all links */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002880 for_each_dpcm_be(fe, stream, dpcm)
Liam Girdwood01d75842012-04-25 12:12:49 +01002881 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2882
2883 dpcm_be_disconnect(fe, stream);
2884 fe->dpcm[stream].runtime = NULL;
2885 }
2886
2887 dpcm_clear_pending_state(fe, stream);
2888 dpcm_path_put(&list);
2889 mutex_unlock(&fe->card->mutex);
2890 return ret;
2891}
2892
Mark Brown45c0a182012-05-09 21:46:27 +01002893static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002894{
2895 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
2896 struct snd_soc_dpcm *dpcm;
2897 int stream = fe_substream->stream, ret;
2898
2899 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2900 ret = dpcm_fe_dai_shutdown(fe_substream);
2901
2902 /* mark FE's links ready to prune */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00002903 for_each_dpcm_be(fe, stream, dpcm)
Liam Girdwood01d75842012-04-25 12:12:49 +01002904 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2905
2906 dpcm_be_disconnect(fe, stream);
2907
2908 fe->dpcm[stream].runtime = NULL;
2909 mutex_unlock(&fe->card->mutex);
2910 return ret;
2911}
2912
Takashi Iwai5d61f0b2017-08-25 12:04:07 +02002913static void soc_pcm_private_free(struct snd_pcm *pcm)
2914{
2915 struct snd_soc_pcm_runtime *rtd = pcm->private_data;
Kuninori Morimotof523ace2017-09-26 01:00:53 +00002916 struct snd_soc_rtdcom_list *rtdcom;
2917 struct snd_soc_component *component;
Takashi Iwai5d61f0b2017-08-25 12:04:07 +02002918
Kuninori Morimotof30a4c32018-01-24 05:18:46 +00002919 /* need to sync the delayed work before releasing resources */
2920 flush_delayed_work(&rtd->delayed_work);
Kuninori Morimotof523ace2017-09-26 01:00:53 +00002921 for_each_rtdcom(rtd, rtdcom) {
Kuninori Morimotof523ace2017-09-26 01:00:53 +00002922 component = rtdcom->component;
2923
Kuninori Morimoto11fb14f2018-05-08 03:19:49 +00002924 if (component->driver->pcm_free)
2925 component->driver->pcm_free(pcm);
Kuninori Morimotof523ace2017-09-26 01:00:53 +00002926 }
Takashi Iwai5d61f0b2017-08-25 12:04:07 +02002927}
2928
Kuninori Morimotob8135862017-10-11 01:37:23 +00002929static int soc_rtdcom_ack(struct snd_pcm_substream *substream)
2930{
2931 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2932 struct snd_soc_rtdcom_list *rtdcom;
2933 struct snd_soc_component *component;
2934
2935 for_each_rtdcom(rtd, rtdcom) {
2936 component = rtdcom->component;
2937
2938 if (!component->driver->ops ||
2939 !component->driver->ops->ack)
2940 continue;
2941
2942 /* FIXME. it returns 1st ask now */
2943 return component->driver->ops->ack(substream);
2944 }
2945
2946 return -EINVAL;
2947}
2948
2949static int soc_rtdcom_copy_user(struct snd_pcm_substream *substream, int channel,
2950 unsigned long pos, void __user *buf,
2951 unsigned long bytes)
2952{
2953 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2954 struct snd_soc_rtdcom_list *rtdcom;
2955 struct snd_soc_component *component;
2956
2957 for_each_rtdcom(rtd, rtdcom) {
2958 component = rtdcom->component;
2959
2960 if (!component->driver->ops ||
2961 !component->driver->ops->copy_user)
2962 continue;
2963
2964 /* FIXME. it returns 1st copy now */
2965 return component->driver->ops->copy_user(substream, channel,
2966 pos, buf, bytes);
2967 }
2968
2969 return -EINVAL;
2970}
2971
2972static int soc_rtdcom_copy_kernel(struct snd_pcm_substream *substream, int channel,
2973 unsigned long pos, void *buf, unsigned long bytes)
2974{
2975 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2976 struct snd_soc_rtdcom_list *rtdcom;
2977 struct snd_soc_component *component;
2978
2979 for_each_rtdcom(rtd, rtdcom) {
2980 component = rtdcom->component;
2981
2982 if (!component->driver->ops ||
2983 !component->driver->ops->copy_kernel)
2984 continue;
2985
2986 /* FIXME. it returns 1st copy now */
2987 return component->driver->ops->copy_kernel(substream, channel,
2988 pos, buf, bytes);
2989 }
2990
2991 return -EINVAL;
2992}
2993
2994static int soc_rtdcom_fill_silence(struct snd_pcm_substream *substream, int channel,
2995 unsigned long pos, unsigned long bytes)
2996{
2997 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2998 struct snd_soc_rtdcom_list *rtdcom;
2999 struct snd_soc_component *component;
3000
3001 for_each_rtdcom(rtd, rtdcom) {
3002 component = rtdcom->component;
3003
3004 if (!component->driver->ops ||
3005 !component->driver->ops->fill_silence)
3006 continue;
3007
3008 /* FIXME. it returns 1st silence now */
3009 return component->driver->ops->fill_silence(substream, channel,
3010 pos, bytes);
3011 }
3012
3013 return -EINVAL;
3014}
3015
3016static struct page *soc_rtdcom_page(struct snd_pcm_substream *substream,
3017 unsigned long offset)
3018{
3019 struct snd_soc_pcm_runtime *rtd = substream->private_data;
3020 struct snd_soc_rtdcom_list *rtdcom;
3021 struct snd_soc_component *component;
3022 struct page *page;
3023
3024 for_each_rtdcom(rtd, rtdcom) {
3025 component = rtdcom->component;
3026
3027 if (!component->driver->ops ||
3028 !component->driver->ops->page)
3029 continue;
3030
3031 /* FIXME. it returns 1st page now */
3032 page = component->driver->ops->page(substream, offset);
3033 if (page)
3034 return page;
3035 }
3036
3037 return NULL;
3038}
3039
3040static int soc_rtdcom_mmap(struct snd_pcm_substream *substream,
3041 struct vm_area_struct *vma)
3042{
3043 struct snd_soc_pcm_runtime *rtd = substream->private_data;
3044 struct snd_soc_rtdcom_list *rtdcom;
3045 struct snd_soc_component *component;
3046
3047 for_each_rtdcom(rtd, rtdcom) {
3048 component = rtdcom->component;
3049
3050 if (!component->driver->ops ||
3051 !component->driver->ops->mmap)
3052 continue;
3053
3054 /* FIXME. it returns 1st mmap now */
3055 return component->driver->ops->mmap(substream, vma);
3056 }
3057
3058 return -EINVAL;
3059}
3060
Liam Girdwoodddee6272011-06-09 14:45:53 +01003061/* create a new pcm */
3062int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
3063{
Benoit Cousson2e5894d2014-07-08 23:19:35 +02003064 struct snd_soc_dai *codec_dai;
Liam Girdwoodddee6272011-06-09 14:45:53 +01003065 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimotof523ace2017-09-26 01:00:53 +00003066 struct snd_soc_component *component;
3067 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +01003068 struct snd_pcm *pcm;
3069 char new_name[64];
3070 int ret = 0, playback = 0, capture = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02003071 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01003072
Liam Girdwood01d75842012-04-25 12:12:49 +01003073 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
Liam Girdwood1e9de422014-01-07 17:51:42 +00003074 playback = rtd->dai_link->dpcm_playback;
3075 capture = rtd->dai_link->dpcm_capture;
Liam Girdwood01d75842012-04-25 12:12:49 +01003076 } else {
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00003077 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02003078 if (codec_dai->driver->playback.channels_min)
3079 playback = 1;
3080 if (codec_dai->driver->capture.channels_min)
3081 capture = 1;
3082 }
3083
3084 capture = capture && cpu_dai->driver->capture.channels_min;
3085 playback = playback && cpu_dai->driver->playback.channels_min;
Liam Girdwood01d75842012-04-25 12:12:49 +01003086 }
Sangsu Parka5002312012-01-02 17:15:10 +09003087
Fabio Estevamd6bead02013-08-29 10:32:13 -03003088 if (rtd->dai_link->playback_only) {
3089 playback = 1;
3090 capture = 0;
3091 }
3092
3093 if (rtd->dai_link->capture_only) {
3094 playback = 0;
3095 capture = 1;
3096 }
3097
Liam Girdwood01d75842012-04-25 12:12:49 +01003098 /* create the PCM */
3099 if (rtd->dai_link->no_pcm) {
3100 snprintf(new_name, sizeof(new_name), "(%s)",
3101 rtd->dai_link->stream_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003102
Liam Girdwood01d75842012-04-25 12:12:49 +01003103 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
3104 playback, capture, &pcm);
3105 } else {
3106 if (rtd->dai_link->dynamic)
3107 snprintf(new_name, sizeof(new_name), "%s (*)",
3108 rtd->dai_link->stream_name);
3109 else
3110 snprintf(new_name, sizeof(new_name), "%s %s-%d",
Benoit Cousson2e5894d2014-07-08 23:19:35 +02003111 rtd->dai_link->stream_name,
3112 (rtd->num_codecs > 1) ?
3113 "multicodec" : rtd->codec_dai->name, num);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003114
Liam Girdwood01d75842012-04-25 12:12:49 +01003115 ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
3116 capture, &pcm);
3117 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01003118 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00003119 dev_err(rtd->card->dev, "ASoC: can't create pcm for %s\n",
Liam Girdwood5cb9b742012-07-06 16:54:52 +01003120 rtd->dai_link->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003121 return ret;
3122 }
Liam Girdwood103d84a2012-11-19 14:39:15 +00003123 dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003124
3125 /* DAPM dai link stream work */
3126 INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
3127
Vinod Koul48c76992015-02-12 09:59:53 +05303128 pcm->nonatomic = rtd->dai_link->nonatomic;
Liam Girdwoodddee6272011-06-09 14:45:53 +01003129 rtd->pcm = pcm;
3130 pcm->private_data = rtd;
Liam Girdwood01d75842012-04-25 12:12:49 +01003131
3132 if (rtd->dai_link->no_pcm) {
3133 if (playback)
3134 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
3135 if (capture)
3136 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
3137 goto out;
3138 }
3139
3140 /* ASoC PCM operations */
3141 if (rtd->dai_link->dynamic) {
3142 rtd->ops.open = dpcm_fe_dai_open;
3143 rtd->ops.hw_params = dpcm_fe_dai_hw_params;
3144 rtd->ops.prepare = dpcm_fe_dai_prepare;
3145 rtd->ops.trigger = dpcm_fe_dai_trigger;
3146 rtd->ops.hw_free = dpcm_fe_dai_hw_free;
3147 rtd->ops.close = dpcm_fe_dai_close;
3148 rtd->ops.pointer = soc_pcm_pointer;
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01003149 rtd->ops.ioctl = soc_pcm_ioctl;
Liam Girdwood01d75842012-04-25 12:12:49 +01003150 } else {
3151 rtd->ops.open = soc_pcm_open;
3152 rtd->ops.hw_params = soc_pcm_hw_params;
3153 rtd->ops.prepare = soc_pcm_prepare;
3154 rtd->ops.trigger = soc_pcm_trigger;
3155 rtd->ops.hw_free = soc_pcm_hw_free;
3156 rtd->ops.close = soc_pcm_close;
3157 rtd->ops.pointer = soc_pcm_pointer;
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01003158 rtd->ops.ioctl = soc_pcm_ioctl;
Liam Girdwood01d75842012-04-25 12:12:49 +01003159 }
3160
Kuninori Morimotob8135862017-10-11 01:37:23 +00003161 for_each_rtdcom(rtd, rtdcom) {
3162 const struct snd_pcm_ops *ops = rtdcom->component->driver->ops;
3163
3164 if (!ops)
3165 continue;
3166
3167 if (ops->ack)
3168 rtd->ops.ack = soc_rtdcom_ack;
3169 if (ops->copy_user)
3170 rtd->ops.copy_user = soc_rtdcom_copy_user;
3171 if (ops->copy_kernel)
3172 rtd->ops.copy_kernel = soc_rtdcom_copy_kernel;
3173 if (ops->fill_silence)
3174 rtd->ops.fill_silence = soc_rtdcom_fill_silence;
3175 if (ops->page)
3176 rtd->ops.page = soc_rtdcom_page;
3177 if (ops->mmap)
3178 rtd->ops.mmap = soc_rtdcom_mmap;
3179 }
3180
Liam Girdwoodddee6272011-06-09 14:45:53 +01003181 if (playback)
Liam Girdwood01d75842012-04-25 12:12:49 +01003182 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003183
3184 if (capture)
Liam Girdwood01d75842012-04-25 12:12:49 +01003185 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003186
Kuninori Morimotof523ace2017-09-26 01:00:53 +00003187 for_each_rtdcom(rtd, rtdcom) {
3188 component = rtdcom->component;
3189
Kuninori Morimoto11fb14f2018-05-08 03:19:49 +00003190 if (!component->driver->pcm_new)
Kuninori Morimotof523ace2017-09-26 01:00:53 +00003191 continue;
3192
Kuninori Morimoto11fb14f2018-05-08 03:19:49 +00003193 ret = component->driver->pcm_new(rtd);
Johan Hovoldc641e5b2017-07-12 17:55:29 +02003194 if (ret < 0) {
Kuninori Morimotof523ace2017-09-26 01:00:53 +00003195 dev_err(component->dev,
Johan Hovoldc641e5b2017-07-12 17:55:29 +02003196 "ASoC: pcm constructor failed: %d\n",
3197 ret);
3198 return ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +01003199 }
3200 }
Johan Hovoldc641e5b2017-07-12 17:55:29 +02003201
Takashi Iwai5d61f0b2017-08-25 12:04:07 +02003202 pcm->private_free = soc_pcm_private_free;
Takashi Iwai3d21ef02019-01-11 15:58:39 +01003203 pcm->no_device_suspend = true;
Liam Girdwood01d75842012-04-25 12:12:49 +01003204out:
Benoit Cousson2e5894d2014-07-08 23:19:35 +02003205 dev_info(rtd->card->dev, "%s <-> %s mapping ok\n",
3206 (rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name,
3207 cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003208 return ret;
3209}
Liam Girdwood01d75842012-04-25 12:12:49 +01003210
3211/* is the current PCM operation for this FE ? */
3212int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream)
3213{
3214 if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE)
3215 return 1;
3216 return 0;
3217}
3218EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update);
3219
3220/* is the current PCM operation for this BE ? */
3221int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
3222 struct snd_soc_pcm_runtime *be, int stream)
3223{
3224 if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) ||
3225 ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) &&
3226 be->dpcm[stream].runtime_update))
3227 return 1;
3228 return 0;
3229}
3230EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update);
3231
3232/* get the substream for this BE */
3233struct snd_pcm_substream *
3234 snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream)
3235{
3236 return be->pcm->streams[stream].substream;
3237}
3238EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream);
3239
3240/* get the BE runtime state */
3241enum snd_soc_dpcm_state
3242 snd_soc_dpcm_be_get_state(struct snd_soc_pcm_runtime *be, int stream)
3243{
3244 return be->dpcm[stream].state;
3245}
3246EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_get_state);
3247
3248/* set the BE runtime state */
3249void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be,
3250 int stream, enum snd_soc_dpcm_state state)
3251{
3252 be->dpcm[stream].state = state;
3253}
3254EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_set_state);
3255
3256/*
3257 * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE
3258 * are not running, paused or suspended for the specified stream direction.
3259 */
3260int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
3261 struct snd_soc_pcm_runtime *be, int stream)
3262{
3263 struct snd_soc_dpcm *dpcm;
3264 int state;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003265 int ret = 1;
3266 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01003267
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003268 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00003269 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01003270
3271 if (dpcm->fe == fe)
3272 continue;
3273
3274 state = dpcm->fe->dpcm[stream].state;
3275 if (state == SND_SOC_DPCM_STATE_START ||
3276 state == SND_SOC_DPCM_STATE_PAUSED ||
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003277 state == SND_SOC_DPCM_STATE_SUSPEND) {
3278 ret = 0;
3279 break;
3280 }
Liam Girdwood01d75842012-04-25 12:12:49 +01003281 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003282 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01003283
3284 /* it's safe to free/stop this BE DAI */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003285 return ret;
Liam Girdwood01d75842012-04-25 12:12:49 +01003286}
3287EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop);
3288
3289/*
3290 * We can only change hw params a BE DAI if any of it's FE are not prepared,
3291 * running, paused or suspended for the specified stream direction.
3292 */
3293int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
3294 struct snd_soc_pcm_runtime *be, int stream)
3295{
3296 struct snd_soc_dpcm *dpcm;
3297 int state;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003298 int ret = 1;
3299 unsigned long flags;
Liam Girdwood01d75842012-04-25 12:12:49 +01003300
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003301 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimotod2e24d62018-09-18 01:30:54 +00003302 for_each_dpcm_fe(be, stream, dpcm) {
Liam Girdwood01d75842012-04-25 12:12:49 +01003303
3304 if (dpcm->fe == fe)
3305 continue;
3306
3307 state = dpcm->fe->dpcm[stream].state;
3308 if (state == SND_SOC_DPCM_STATE_START ||
3309 state == SND_SOC_DPCM_STATE_PAUSED ||
3310 state == SND_SOC_DPCM_STATE_SUSPEND ||
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003311 state == SND_SOC_DPCM_STATE_PREPARE) {
3312 ret = 0;
3313 break;
3314 }
Liam Girdwood01d75842012-04-25 12:12:49 +01003315 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003316 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwood01d75842012-04-25 12:12:49 +01003317
3318 /* it's safe to change hw_params */
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003319 return ret;
Liam Girdwood01d75842012-04-25 12:12:49 +01003320}
3321EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003322
3323#ifdef CONFIG_DEBUG_FS
Lars-Peter Clausen852801412016-11-22 11:29:14 +01003324static const char *dpcm_state_string(enum snd_soc_dpcm_state state)
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003325{
3326 switch (state) {
3327 case SND_SOC_DPCM_STATE_NEW:
3328 return "new";
3329 case SND_SOC_DPCM_STATE_OPEN:
3330 return "open";
3331 case SND_SOC_DPCM_STATE_HW_PARAMS:
3332 return "hw_params";
3333 case SND_SOC_DPCM_STATE_PREPARE:
3334 return "prepare";
3335 case SND_SOC_DPCM_STATE_START:
3336 return "start";
3337 case SND_SOC_DPCM_STATE_STOP:
3338 return "stop";
3339 case SND_SOC_DPCM_STATE_SUSPEND:
3340 return "suspend";
3341 case SND_SOC_DPCM_STATE_PAUSED:
3342 return "paused";
3343 case SND_SOC_DPCM_STATE_HW_FREE:
3344 return "hw_free";
3345 case SND_SOC_DPCM_STATE_CLOSE:
3346 return "close";
3347 }
3348
3349 return "unknown";
3350}
3351
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003352static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
3353 int stream, char *buf, size_t size)
3354{
3355 struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params;
3356 struct snd_soc_dpcm *dpcm;
3357 ssize_t offset = 0;
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003358 unsigned long flags;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003359
3360 /* FE state */
3361 offset += snprintf(buf + offset, size - offset,
3362 "[%s - %s]\n", fe->dai_link->name,
3363 stream ? "Capture" : "Playback");
3364
3365 offset += snprintf(buf + offset, size - offset, "State: %s\n",
3366 dpcm_state_string(fe->dpcm[stream].state));
3367
3368 if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
3369 (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
3370 offset += snprintf(buf + offset, size - offset,
3371 "Hardware Params: "
3372 "Format = %s, Channels = %d, Rate = %d\n",
3373 snd_pcm_format_name(params_format(params)),
3374 params_channels(params),
3375 params_rate(params));
3376
3377 /* BEs state */
3378 offset += snprintf(buf + offset, size - offset, "Backends:\n");
3379
3380 if (list_empty(&fe->dpcm[stream].be_clients)) {
3381 offset += snprintf(buf + offset, size - offset,
3382 " No active DSP links\n");
3383 goto out;
3384 }
3385
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003386 spin_lock_irqsave(&fe->card->dpcm_lock, flags);
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +00003387 for_each_dpcm_be(fe, stream, dpcm) {
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003388 struct snd_soc_pcm_runtime *be = dpcm->be;
3389 params = &dpcm->hw_params;
3390
3391 offset += snprintf(buf + offset, size - offset,
3392 "- %s\n", be->dai_link->name);
3393
3394 offset += snprintf(buf + offset, size - offset,
3395 " State: %s\n",
3396 dpcm_state_string(be->dpcm[stream].state));
3397
3398 if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
3399 (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
3400 offset += snprintf(buf + offset, size - offset,
3401 " Hardware Params: "
3402 "Format = %s, Channels = %d, Rate = %d\n",
3403 snd_pcm_format_name(params_format(params)),
3404 params_channels(params),
3405 params_rate(params));
3406 }
KaiChieh Chuanga9764862019-03-08 13:05:53 +08003407 spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003408out:
3409 return offset;
3410}
3411
3412static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf,
3413 size_t count, loff_t *ppos)
3414{
3415 struct snd_soc_pcm_runtime *fe = file->private_data;
3416 ssize_t out_count = PAGE_SIZE, offset = 0, ret = 0;
3417 char *buf;
3418
3419 buf = kmalloc(out_count, GFP_KERNEL);
3420 if (!buf)
3421 return -ENOMEM;
3422
3423 if (fe->cpu_dai->driver->playback.channels_min)
3424 offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_PLAYBACK,
3425 buf + offset, out_count - offset);
3426
3427 if (fe->cpu_dai->driver->capture.channels_min)
3428 offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_CAPTURE,
3429 buf + offset, out_count - offset);
3430
Liam Girdwoodf57b8482012-04-27 11:33:46 +01003431 ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003432
Liam Girdwoodf57b8482012-04-27 11:33:46 +01003433 kfree(buf);
3434 return ret;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003435}
3436
3437static const struct file_operations dpcm_state_fops = {
Liam Girdwoodf57b8482012-04-27 11:33:46 +01003438 .open = simple_open,
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003439 .read = dpcm_state_read_file,
3440 .llseek = default_llseek,
3441};
3442
Lars-Peter Clausen2e55b902015-04-09 10:52:37 +02003443void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003444{
Mark Brownb3bba9a2012-05-08 10:33:47 +01003445 if (!rtd->dai_link)
Lars-Peter Clausen2e55b902015-04-09 10:52:37 +02003446 return;
Mark Brownb3bba9a2012-05-08 10:33:47 +01003447
Lars-Peter Clausen6553bf062015-04-09 10:52:38 +02003448 if (!rtd->card->debugfs_card_root)
3449 return;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003450
3451 rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name,
3452 rtd->card->debugfs_card_root);
3453 if (!rtd->debugfs_dpcm_root) {
3454 dev_dbg(rtd->dev,
3455 "ASoC: Failed to create dpcm debugfs directory %s\n",
3456 rtd->dai_link->name);
Lars-Peter Clausen2e55b902015-04-09 10:52:37 +02003457 return;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003458 }
3459
Fabio Estevamf1e3f402017-07-29 11:40:55 -03003460 debugfs_create_file("state", 0444, rtd->debugfs_dpcm_root,
3461 rtd, &dpcm_state_fops);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003462}
3463#endif