blob: 3f6375499102068a5549121a902da3f109f531e2 [file] [log] [blame]
Liam Girdwoodddee6272011-06-09 14:45:53 +01001/*
2 * soc-pcm.c -- ALSA SoC PCM
3 *
4 * Copyright 2005 Wolfson Microelectronics PLC.
5 * Copyright 2005 Openedhand Ltd.
6 * Copyright (C) 2010 Slimlogic Ltd.
7 * Copyright (C) 2010 Texas Instruments Inc.
8 *
9 * Authors: Liam Girdwood <lrg@ti.com>
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +020010 * Mark Brown <broonie@opensource.wolfsonmicro.com>
Liam Girdwoodddee6272011-06-09 14:45:53 +010011 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 *
17 */
18
19#include <linux/kernel.h>
20#include <linux/init.h>
21#include <linux/delay.h>
Nicolin Chen988e8cc2013-11-04 14:57:31 +080022#include <linux/pinctrl/consumer.h>
Mark Brownd6652ef2011-12-03 20:14:31 +000023#include <linux/pm_runtime.h>
Liam Girdwoodddee6272011-06-09 14:45:53 +010024#include <linux/slab.h>
25#include <linux/workqueue.h>
Liam Girdwood01d75842012-04-25 12:12:49 +010026#include <linux/export.h>
Liam Girdwoodf86dcef2012-04-25 12:12:50 +010027#include <linux/debugfs.h>
Liam Girdwoodddee6272011-06-09 14:45:53 +010028#include <sound/core.h>
29#include <sound/pcm.h>
30#include <sound/pcm_params.h>
31#include <sound/soc.h>
Liam Girdwood01d75842012-04-25 12:12:49 +010032#include <sound/soc-dpcm.h>
Liam Girdwoodddee6272011-06-09 14:45:53 +010033#include <sound/initval.h>
34
Liam Girdwood01d75842012-04-25 12:12:49 +010035#define DPCM_MAX_BE_USERS 8
36
Ricard Wanderlofcde79032015-08-24 14:16:51 +020037/*
38 * snd_soc_dai_stream_valid() - check if a DAI supports the given stream
39 *
40 * Returns true if the DAI supports the indicated stream type.
41 */
42static bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream)
43{
44 struct snd_soc_pcm_stream *codec_stream;
45
46 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
47 codec_stream = &dai->driver->playback;
48 else
49 codec_stream = &dai->driver->capture;
50
51 /* If the codec specifies any rate at all, it supports the stream. */
52 return codec_stream->rates;
53}
54
Lars-Peter Clausen90996f42013-05-14 11:05:30 +020055/**
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010056 * snd_soc_runtime_activate() - Increment active count for PCM runtime components
57 * @rtd: ASoC PCM runtime that is activated
58 * @stream: Direction of the PCM stream
59 *
60 * Increments the active count for all the DAIs and components attached to a PCM
61 * runtime. Should typically be called when a stream is opened.
62 *
63 * Must be called with the rtd->pcm_mutex being held
64 */
65void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream)
66{
67 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +020068 int i;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010069
70 lockdep_assert_held(&rtd->pcm_mutex);
71
72 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
73 cpu_dai->playback_active++;
Benoit Cousson2e5894d2014-07-08 23:19:35 +020074 for (i = 0; i < rtd->num_codecs; i++)
75 rtd->codec_dais[i]->playback_active++;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010076 } else {
77 cpu_dai->capture_active++;
Benoit Cousson2e5894d2014-07-08 23:19:35 +020078 for (i = 0; i < rtd->num_codecs; i++)
79 rtd->codec_dais[i]->capture_active++;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010080 }
81
82 cpu_dai->active++;
Lars-Peter Clausencdde4cc2014-03-05 13:17:47 +010083 cpu_dai->component->active++;
Benoit Cousson2e5894d2014-07-08 23:19:35 +020084 for (i = 0; i < rtd->num_codecs; i++) {
85 rtd->codec_dais[i]->active++;
86 rtd->codec_dais[i]->component->active++;
87 }
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010088}
89
90/**
91 * snd_soc_runtime_deactivate() - Decrement active count for PCM runtime components
92 * @rtd: ASoC PCM runtime that is deactivated
93 * @stream: Direction of the PCM stream
94 *
95 * Decrements the active count for all the DAIs and components attached to a PCM
96 * runtime. Should typically be called when a stream is closed.
97 *
98 * Must be called with the rtd->pcm_mutex being held
99 */
100void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream)
101{
102 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200103 int i;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100104
105 lockdep_assert_held(&rtd->pcm_mutex);
106
107 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
108 cpu_dai->playback_active--;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200109 for (i = 0; i < rtd->num_codecs; i++)
110 rtd->codec_dais[i]->playback_active--;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100111 } else {
112 cpu_dai->capture_active--;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200113 for (i = 0; i < rtd->num_codecs; i++)
114 rtd->codec_dais[i]->capture_active--;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100115 }
116
117 cpu_dai->active--;
Lars-Peter Clausencdde4cc2014-03-05 13:17:47 +0100118 cpu_dai->component->active--;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200119 for (i = 0; i < rtd->num_codecs; i++) {
120 rtd->codec_dais[i]->component->active--;
121 rtd->codec_dais[i]->active--;
122 }
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100123}
124
125/**
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100126 * snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay
127 * @rtd: The ASoC PCM runtime that should be checked.
128 *
129 * This function checks whether the power down delay should be ignored for a
130 * specific PCM runtime. Returns true if the delay is 0, if it the DAI link has
131 * been configured to ignore the delay, or if none of the components benefits
132 * from having the delay.
133 */
134bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
135{
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000136 struct snd_soc_rtdcom_list *rtdcom;
137 struct snd_soc_component *component;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200138 int i;
139 bool ignore = true;
140
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100141 if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
142 return true;
143
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000144 for_each_rtdcom(rtd, rtdcom) {
145 component = rtdcom->component;
146
Kuninori Morimoto72c38182018-01-19 05:21:19 +0000147 ignore &= !component->driver->use_pmdown_time;
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000148 }
149
150 /* this will be removed */
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200151 for (i = 0; i < rtd->num_codecs; i++)
152 ignore &= rtd->codec_dais[i]->component->ignore_pmdown_time;
153
Kuninori Morimotofbb16562017-10-11 01:38:08 +0000154 return ignore;
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100155}
156
157/**
Lars-Peter Clausen90996f42013-05-14 11:05:30 +0200158 * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
159 * @substream: the pcm substream
160 * @hw: the hardware parameters
161 *
162 * Sets the substream runtime hardware parameters.
163 */
164int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
165 const struct snd_pcm_hardware *hw)
166{
167 struct snd_pcm_runtime *runtime = substream->runtime;
168 runtime->hw.info = hw->info;
169 runtime->hw.formats = hw->formats;
170 runtime->hw.period_bytes_min = hw->period_bytes_min;
171 runtime->hw.period_bytes_max = hw->period_bytes_max;
172 runtime->hw.periods_min = hw->periods_min;
173 runtime->hw.periods_max = hw->periods_max;
174 runtime->hw.buffer_bytes_max = hw->buffer_bytes_max;
175 runtime->hw.fifo_size = hw->fifo_size;
176 return 0;
177}
178EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
179
Liam Girdwood01d75842012-04-25 12:12:49 +0100180/* DPCM stream event, send event to FE and all active BEs. */
Liam Girdwood23607022014-01-17 17:03:55 +0000181int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
Liam Girdwood01d75842012-04-25 12:12:49 +0100182 int event)
183{
184 struct snd_soc_dpcm *dpcm;
185
186 list_for_each_entry(dpcm, &fe->dpcm[dir].be_clients, list_be) {
187
188 struct snd_soc_pcm_runtime *be = dpcm->be;
189
Liam Girdwood103d84a2012-11-19 14:39:15 +0000190 dev_dbg(be->dev, "ASoC: BE %s event %d dir %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +0100191 be->dai_link->name, event, dir);
192
Banajit Goswamib1cd2e32017-07-14 23:15:05 -0700193 if ((event == SND_SOC_DAPM_STREAM_STOP) &&
194 (be->dpcm[dir].users >= 1))
195 continue;
196
Liam Girdwood01d75842012-04-25 12:12:49 +0100197 snd_soc_dapm_stream_event(be, dir, event);
198 }
199
200 snd_soc_dapm_stream_event(fe, dir, event);
201
202 return 0;
203}
204
Dong Aisheng17841022011-08-29 17:15:14 +0800205static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
206 struct snd_soc_dai *soc_dai)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100207{
208 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100209 int ret;
210
Nicolin Chen3635bf02013-11-13 18:56:24 +0800211 if (soc_dai->rate && (soc_dai->driver->symmetric_rates ||
212 rtd->dai_link->symmetric_rates)) {
213 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n",
214 soc_dai->rate);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100215
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200216 ret = snd_pcm_hw_constraint_single(substream->runtime,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800217 SNDRV_PCM_HW_PARAM_RATE,
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200218 soc_dai->rate);
Nicolin Chen3635bf02013-11-13 18:56:24 +0800219 if (ret < 0) {
220 dev_err(soc_dai->dev,
221 "ASoC: Unable to apply rate constraint: %d\n",
222 ret);
223 return ret;
224 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100225 }
226
Nicolin Chen3635bf02013-11-13 18:56:24 +0800227 if (soc_dai->channels && (soc_dai->driver->symmetric_channels ||
228 rtd->dai_link->symmetric_channels)) {
229 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d channel(s)\n",
230 soc_dai->channels);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100231
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200232 ret = snd_pcm_hw_constraint_single(substream->runtime,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800233 SNDRV_PCM_HW_PARAM_CHANNELS,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800234 soc_dai->channels);
235 if (ret < 0) {
236 dev_err(soc_dai->dev,
237 "ASoC: Unable to apply channel symmetry constraint: %d\n",
238 ret);
239 return ret;
240 }
241 }
242
243 if (soc_dai->sample_bits && (soc_dai->driver->symmetric_samplebits ||
244 rtd->dai_link->symmetric_samplebits)) {
245 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d sample bits\n",
246 soc_dai->sample_bits);
247
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200248 ret = snd_pcm_hw_constraint_single(substream->runtime,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800249 SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800250 soc_dai->sample_bits);
251 if (ret < 0) {
252 dev_err(soc_dai->dev,
253 "ASoC: Unable to apply sample bits symmetry constraint: %d\n",
254 ret);
255 return ret;
256 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100257 }
258
259 return 0;
260}
261
Nicolin Chen3635bf02013-11-13 18:56:24 +0800262static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
263 struct snd_pcm_hw_params *params)
264{
265 struct snd_soc_pcm_runtime *rtd = substream->private_data;
266 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200267 unsigned int rate, channels, sample_bits, symmetry, i;
Nicolin Chen3635bf02013-11-13 18:56:24 +0800268
269 rate = params_rate(params);
270 channels = params_channels(params);
271 sample_bits = snd_pcm_format_physical_width(params_format(params));
272
273 /* reject unmatched parameters when applying symmetry */
274 symmetry = cpu_dai->driver->symmetric_rates ||
Nicolin Chen3635bf02013-11-13 18:56:24 +0800275 rtd->dai_link->symmetric_rates;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200276
277 for (i = 0; i < rtd->num_codecs; i++)
278 symmetry |= rtd->codec_dais[i]->driver->symmetric_rates;
279
Nicolin Chen3635bf02013-11-13 18:56:24 +0800280 if (symmetry && cpu_dai->rate && cpu_dai->rate != rate) {
281 dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n",
282 cpu_dai->rate, rate);
283 return -EINVAL;
284 }
285
286 symmetry = cpu_dai->driver->symmetric_channels ||
Nicolin Chen3635bf02013-11-13 18:56:24 +0800287 rtd->dai_link->symmetric_channels;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200288
289 for (i = 0; i < rtd->num_codecs; i++)
290 symmetry |= rtd->codec_dais[i]->driver->symmetric_channels;
291
Nicolin Chen3635bf02013-11-13 18:56:24 +0800292 if (symmetry && cpu_dai->channels && cpu_dai->channels != channels) {
293 dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n",
294 cpu_dai->channels, channels);
295 return -EINVAL;
296 }
297
298 symmetry = cpu_dai->driver->symmetric_samplebits ||
Nicolin Chen3635bf02013-11-13 18:56:24 +0800299 rtd->dai_link->symmetric_samplebits;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200300
301 for (i = 0; i < rtd->num_codecs; i++)
302 symmetry |= rtd->codec_dais[i]->driver->symmetric_samplebits;
303
Nicolin Chen3635bf02013-11-13 18:56:24 +0800304 if (symmetry && cpu_dai->sample_bits && cpu_dai->sample_bits != sample_bits) {
305 dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n",
306 cpu_dai->sample_bits, sample_bits);
307 return -EINVAL;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100308 }
309
310 return 0;
311}
312
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100313static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream)
314{
315 struct snd_soc_pcm_runtime *rtd = substream->private_data;
316 struct snd_soc_dai_driver *cpu_driver = rtd->cpu_dai->driver;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100317 struct snd_soc_dai_link *link = rtd->dai_link;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200318 unsigned int symmetry, i;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100319
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200320 symmetry = cpu_driver->symmetric_rates || link->symmetric_rates ||
321 cpu_driver->symmetric_channels || link->symmetric_channels ||
322 cpu_driver->symmetric_samplebits || link->symmetric_samplebits;
323
324 for (i = 0; i < rtd->num_codecs; i++)
325 symmetry = symmetry ||
326 rtd->codec_dais[i]->driver->symmetric_rates ||
327 rtd->codec_dais[i]->driver->symmetric_channels ||
328 rtd->codec_dais[i]->driver->symmetric_samplebits;
329
330 return symmetry;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100331}
332
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200333static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits)
Mark Brown58ba9b22012-01-16 18:38:51 +0000334{
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200335 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Takashi Iwaic6068d32014-12-31 17:10:34 +0100336 int ret;
Mark Brown58ba9b22012-01-16 18:38:51 +0000337
338 if (!bits)
339 return;
340
Lars-Peter Clausen0e2a3752014-12-29 18:43:38 +0100341 ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 0, bits);
342 if (ret != 0)
343 dev_warn(rtd->dev, "ASoC: Failed to set MSB %d: %d\n",
344 bits, ret);
Mark Brown58ba9b22012-01-16 18:38:51 +0000345}
346
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200347static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200348{
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200349 struct snd_soc_pcm_runtime *rtd = substream->private_data;
350 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200351 struct snd_soc_dai *codec_dai;
352 int i;
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200353 unsigned int bits = 0, cpu_bits;
354
355 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200356 for (i = 0; i < rtd->num_codecs; i++) {
357 codec_dai = rtd->codec_dais[i];
358 if (codec_dai->driver->playback.sig_bits == 0) {
359 bits = 0;
360 break;
361 }
362 bits = max(codec_dai->driver->playback.sig_bits, bits);
363 }
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200364 cpu_bits = cpu_dai->driver->playback.sig_bits;
365 } else {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200366 for (i = 0; i < rtd->num_codecs; i++) {
367 codec_dai = rtd->codec_dais[i];
Daniel Mack5e63dfc2014-10-07 14:33:46 +0200368 if (codec_dai->driver->capture.sig_bits == 0) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200369 bits = 0;
370 break;
371 }
372 bits = max(codec_dai->driver->capture.sig_bits, bits);
373 }
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200374 cpu_bits = cpu_dai->driver->capture.sig_bits;
375 }
376
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200377 soc_pcm_set_msb(substream, bits);
378 soc_pcm_set_msb(substream, cpu_bits);
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200379}
380
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200381static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200382{
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200383 struct snd_pcm_runtime *runtime = substream->runtime;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100384 struct snd_pcm_hardware *hw = &runtime->hw;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200385 struct snd_soc_pcm_runtime *rtd = substream->private_data;
386 struct snd_soc_dai_driver *cpu_dai_drv = rtd->cpu_dai->driver;
387 struct snd_soc_dai_driver *codec_dai_drv;
388 struct snd_soc_pcm_stream *codec_stream;
389 struct snd_soc_pcm_stream *cpu_stream;
390 unsigned int chan_min = 0, chan_max = UINT_MAX;
391 unsigned int rate_min = 0, rate_max = UINT_MAX;
392 unsigned int rates = UINT_MAX;
393 u64 formats = ULLONG_MAX;
394 int i;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100395
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200396 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
397 cpu_stream = &cpu_dai_drv->playback;
Lars-Peter Clausen16d7ea92014-01-06 14:19:16 +0100398 else
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200399 cpu_stream = &cpu_dai_drv->capture;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100400
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200401 /* first calculate min/max only for CODECs in the DAI link */
402 for (i = 0; i < rtd->num_codecs; i++) {
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200403
404 /*
405 * Skip CODECs which don't support the current stream type.
406 * Otherwise, since the rate, channel, and format values will
407 * zero in that case, we would have no usable settings left,
408 * causing the resulting setup to fail.
409 * At least one CODEC should match, otherwise we should have
410 * bailed out on a higher level, since there would be no
411 * CODEC to support the transfer direction in that case.
412 */
413 if (!snd_soc_dai_stream_valid(rtd->codec_dais[i],
414 substream->stream))
415 continue;
416
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200417 codec_dai_drv = rtd->codec_dais[i]->driver;
418 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
419 codec_stream = &codec_dai_drv->playback;
420 else
421 codec_stream = &codec_dai_drv->capture;
422 chan_min = max(chan_min, codec_stream->channels_min);
423 chan_max = min(chan_max, codec_stream->channels_max);
424 rate_min = max(rate_min, codec_stream->rate_min);
425 rate_max = min_not_zero(rate_max, codec_stream->rate_max);
426 formats &= codec_stream->formats;
427 rates = snd_pcm_rate_mask_intersect(codec_stream->rates, rates);
428 }
429
430 /*
431 * chan min/max cannot be enforced if there are multiple CODEC DAIs
432 * connected to a single CPU DAI, use CPU DAI's directly and let
433 * channel allocation be fixed up later
434 */
435 if (rtd->num_codecs > 1) {
436 chan_min = cpu_stream->channels_min;
437 chan_max = cpu_stream->channels_max;
438 }
439
440 hw->channels_min = max(chan_min, cpu_stream->channels_min);
441 hw->channels_max = min(chan_max, cpu_stream->channels_max);
442 if (hw->formats)
443 hw->formats &= formats & cpu_stream->formats;
444 else
445 hw->formats = formats & cpu_stream->formats;
446 hw->rates = snd_pcm_rate_mask_intersect(rates, cpu_stream->rates);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100447
448 snd_pcm_limit_hw_rates(runtime);
449
450 hw->rate_min = max(hw->rate_min, cpu_stream->rate_min);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200451 hw->rate_min = max(hw->rate_min, rate_min);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100452 hw->rate_max = min_not_zero(hw->rate_max, cpu_stream->rate_max);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200453 hw->rate_max = min_not_zero(hw->rate_max, rate_max);
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200454}
455
Mark Brown58ba9b22012-01-16 18:38:51 +0000456/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100457 * Called by ALSA when a PCM substream is opened, the runtime->hw record is
458 * then initialized and any private data can be allocated. This also calls
Charles Keepaxef050be2018-04-24 16:39:02 +0100459 * startup for the cpu DAI, component, machine and codec DAI.
Liam Girdwoodddee6272011-06-09 14:45:53 +0100460 */
461static int soc_pcm_open(struct snd_pcm_substream *substream)
462{
463 struct snd_soc_pcm_runtime *rtd = substream->private_data;
464 struct snd_pcm_runtime *runtime = substream->runtime;
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000465 struct snd_soc_component *component;
466 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100467 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200468 struct snd_soc_dai *codec_dai;
469 const char *codec_dai_name = "multicodec";
Kuninori Morimotob8135862017-10-11 01:37:23 +0000470 int i, ret = 0, __ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100471
Nicolin Chen988e8cc2013-11-04 14:57:31 +0800472 pinctrl_pm_select_default_state(cpu_dai->dev);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200473 for (i = 0; i < rtd->num_codecs; i++)
474 pinctrl_pm_select_default_state(rtd->codec_dais[i]->dev);
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000475
476 for_each_rtdcom(rtd, rtdcom) {
477 component = rtdcom->component;
478
479 pm_runtime_get_sync(component->dev);
480 }
Mark Brownd6652ef2011-12-03 20:14:31 +0000481
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100482 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100483
484 /* startup the audio subsystem */
Kuninori Morimoto9900a422017-09-25 01:38:54 +0000485 if (cpu_dai->driver->ops->startup) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100486 ret = cpu_dai->driver->ops->startup(substream, cpu_dai);
487 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000488 dev_err(cpu_dai->dev, "ASoC: can't open interface"
489 " %s: %d\n", cpu_dai->name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100490 goto out;
491 }
492 }
493
Kuninori Morimotob8135862017-10-11 01:37:23 +0000494 ret = 0;
495 for_each_rtdcom(rtd, rtdcom) {
496 component = rtdcom->component;
497
Kuninori Morimotob8135862017-10-11 01:37:23 +0000498 if (!component->driver->ops ||
499 !component->driver->ops->open)
500 continue;
501
502 __ret = component->driver->ops->open(substream);
503 if (__ret < 0) {
504 dev_err(component->dev,
505 "ASoC: can't open component %s: %d\n",
506 component->name, ret);
507 ret = __ret;
508 }
509 }
510 if (ret < 0)
511 goto component_err;
512
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200513 for (i = 0; i < rtd->num_codecs; i++) {
514 codec_dai = rtd->codec_dais[i];
Kuninori Morimoto9900a422017-09-25 01:38:54 +0000515 if (codec_dai->driver->ops->startup) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200516 ret = codec_dai->driver->ops->startup(substream,
517 codec_dai);
518 if (ret < 0) {
519 dev_err(codec_dai->dev,
520 "ASoC: can't open codec %s: %d\n",
521 codec_dai->name, ret);
522 goto codec_dai_err;
523 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100524 }
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200525
526 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
527 codec_dai->tx_mask = 0;
528 else
529 codec_dai->rx_mask = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100530 }
531
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000532 if (rtd->dai_link->ops->startup) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100533 ret = rtd->dai_link->ops->startup(substream);
534 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000535 pr_err("ASoC: %s startup failed: %d\n",
Mark Brown25bfe662012-02-01 21:30:32 +0000536 rtd->dai_link->name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100537 goto machine_err;
538 }
539 }
540
Liam Girdwood01d75842012-04-25 12:12:49 +0100541 /* Dynamic PCM DAI links compat checks use dynamic capabilities */
542 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm)
543 goto dynamic;
544
Liam Girdwoodddee6272011-06-09 14:45:53 +0100545 /* Check that the codec and cpu DAIs are compatible */
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200546 soc_pcm_init_runtime_hw(substream);
547
548 if (rtd->num_codecs == 1)
549 codec_dai_name = rtd->codec_dai->name;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100550
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100551 if (soc_pcm_has_symmetry(substream))
552 runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
553
Liam Girdwoodddee6272011-06-09 14:45:53 +0100554 ret = -EINVAL;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100555 if (!runtime->hw.rates) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000556 printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200557 codec_dai_name, cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100558 goto config_err;
559 }
560 if (!runtime->hw.formats) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000561 printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200562 codec_dai_name, cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100563 goto config_err;
564 }
565 if (!runtime->hw.channels_min || !runtime->hw.channels_max ||
566 runtime->hw.channels_min > runtime->hw.channels_max) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000567 printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200568 codec_dai_name, cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100569 goto config_err;
570 }
571
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200572 soc_pcm_apply_msb(substream);
Mark Brown58ba9b22012-01-16 18:38:51 +0000573
Liam Girdwoodddee6272011-06-09 14:45:53 +0100574 /* Symmetry only applies if we've already got an active stream. */
Dong Aisheng17841022011-08-29 17:15:14 +0800575 if (cpu_dai->active) {
576 ret = soc_pcm_apply_symmetry(substream, cpu_dai);
577 if (ret != 0)
578 goto config_err;
579 }
580
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200581 for (i = 0; i < rtd->num_codecs; i++) {
582 if (rtd->codec_dais[i]->active) {
583 ret = soc_pcm_apply_symmetry(substream,
584 rtd->codec_dais[i]);
585 if (ret != 0)
586 goto config_err;
587 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100588 }
589
Liam Girdwood103d84a2012-11-19 14:39:15 +0000590 pr_debug("ASoC: %s <-> %s info:\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200591 codec_dai_name, cpu_dai->name);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000592 pr_debug("ASoC: rate mask 0x%x\n", runtime->hw.rates);
593 pr_debug("ASoC: min ch %d max ch %d\n", runtime->hw.channels_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100594 runtime->hw.channels_max);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000595 pr_debug("ASoC: min rate %d max rate %d\n", runtime->hw.rate_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100596 runtime->hw.rate_max);
597
Liam Girdwood01d75842012-04-25 12:12:49 +0100598dynamic:
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100599
600 snd_soc_runtime_activate(rtd, substream->stream);
601
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100602 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100603 return 0;
604
605config_err:
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000606 if (rtd->dai_link->ops->shutdown)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100607 rtd->dai_link->ops->shutdown(substream);
608
609machine_err:
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200610 i = rtd->num_codecs;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100611
612codec_dai_err:
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200613 while (--i >= 0) {
614 codec_dai = rtd->codec_dais[i];
615 if (codec_dai->driver->ops->shutdown)
616 codec_dai->driver->ops->shutdown(substream, codec_dai);
617 }
618
Kuninori Morimotob8135862017-10-11 01:37:23 +0000619component_err:
620 for_each_rtdcom(rtd, rtdcom) {
621 component = rtdcom->component;
622
Kuninori Morimotob8135862017-10-11 01:37:23 +0000623 if (!component->driver->ops ||
624 !component->driver->ops->close)
625 continue;
626
627 component->driver->ops->close(substream);
628 }
629
Liam Girdwoodddee6272011-06-09 14:45:53 +0100630 if (cpu_dai->driver->ops->shutdown)
631 cpu_dai->driver->ops->shutdown(substream, cpu_dai);
632out:
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100633 mutex_unlock(&rtd->pcm_mutex);
Mark Brownd6652ef2011-12-03 20:14:31 +0000634
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000635 for_each_rtdcom(rtd, rtdcom) {
636 component = rtdcom->component;
637
638 pm_runtime_mark_last_busy(component->dev);
639 pm_runtime_put_autosuspend(component->dev);
Sanyog Kale3f809782016-01-05 17:14:49 +0530640 }
641
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200642 for (i = 0; i < rtd->num_codecs; i++) {
643 if (!rtd->codec_dais[i]->active)
644 pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev);
645 }
Nicolin Chen988e8cc2013-11-04 14:57:31 +0800646 if (!cpu_dai->active)
647 pinctrl_pm_select_sleep_state(cpu_dai->dev);
Mark Brownd6652ef2011-12-03 20:14:31 +0000648
Liam Girdwoodddee6272011-06-09 14:45:53 +0100649 return ret;
650}
651
652/*
653 * Power down the audio subsystem pmdown_time msecs after close is called.
654 * This is to ensure there are no pops or clicks in between any music tracks
655 * due to DAPM power cycling.
656 */
657static void close_delayed_work(struct work_struct *work)
658{
659 struct snd_soc_pcm_runtime *rtd =
660 container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200661 struct snd_soc_dai *codec_dai = rtd->codec_dais[0];
Liam Girdwoodddee6272011-06-09 14:45:53 +0100662
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100663 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100664
Liam Girdwood103d84a2012-11-19 14:39:15 +0000665 dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n",
Liam Girdwoodddee6272011-06-09 14:45:53 +0100666 codec_dai->driver->playback.stream_name,
667 codec_dai->playback_active ? "active" : "inactive",
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600668 rtd->pop_wait ? "yes" : "no");
Liam Girdwoodddee6272011-06-09 14:45:53 +0100669
670 /* are we waiting on this codec DAI stream */
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600671 if (rtd->pop_wait == 1) {
672 rtd->pop_wait = 0;
Mark Brown7bd3a6f2012-02-16 15:03:27 -0800673 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000674 SND_SOC_DAPM_STREAM_STOP);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100675 }
676
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100677 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100678}
679
680/*
681 * Called by ALSA when a PCM substream is closed. Private data can be
Charles Keepaxef050be2018-04-24 16:39:02 +0100682 * freed here. The cpu DAI, codec DAI, machine and components are also
Liam Girdwoodddee6272011-06-09 14:45:53 +0100683 * shutdown.
684 */
Liam Girdwood91d5e6b2011-06-09 17:04:59 +0100685static int soc_pcm_close(struct snd_pcm_substream *substream)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100686{
687 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000688 struct snd_soc_component *component;
689 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100690 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200691 struct snd_soc_dai *codec_dai;
692 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100693
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100694 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100695
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100696 snd_soc_runtime_deactivate(rtd, substream->stream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100697
Dong Aisheng17841022011-08-29 17:15:14 +0800698 /* clear the corresponding DAIs rate when inactive */
699 if (!cpu_dai->active)
700 cpu_dai->rate = 0;
701
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200702 for (i = 0; i < rtd->num_codecs; i++) {
703 codec_dai = rtd->codec_dais[i];
704 if (!codec_dai->active)
705 codec_dai->rate = 0;
706 }
Sascha Hauer25b76792011-08-17 09:20:01 +0200707
Ramesh Babuae116012014-10-15 12:34:59 +0530708 snd_soc_dai_digital_mute(cpu_dai, 1, substream->stream);
709
Liam Girdwoodddee6272011-06-09 14:45:53 +0100710 if (cpu_dai->driver->ops->shutdown)
711 cpu_dai->driver->ops->shutdown(substream, cpu_dai);
712
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200713 for (i = 0; i < rtd->num_codecs; i++) {
714 codec_dai = rtd->codec_dais[i];
715 if (codec_dai->driver->ops->shutdown)
716 codec_dai->driver->ops->shutdown(substream, codec_dai);
717 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100718
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000719 if (rtd->dai_link->ops->shutdown)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100720 rtd->dai_link->ops->shutdown(substream);
721
Kuninori Morimotob8135862017-10-11 01:37:23 +0000722 for_each_rtdcom(rtd, rtdcom) {
723 component = rtdcom->component;
724
Kuninori Morimotob8135862017-10-11 01:37:23 +0000725 if (!component->driver->ops ||
726 !component->driver->ops->close)
727 continue;
728
729 component->driver->ops->close(substream);
730 }
731
Liam Girdwoodddee6272011-06-09 14:45:53 +0100732 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100733 if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
Peter Ujfalusi1d69c5c2011-10-14 14:43:33 +0300734 /* powered down playback stream now */
735 snd_soc_dapm_stream_event(rtd,
Mark Brown7bd3a6f2012-02-16 15:03:27 -0800736 SNDRV_PCM_STREAM_PLAYBACK,
Mark Brown7bd3a6f2012-02-16 15:03:27 -0800737 SND_SOC_DAPM_STREAM_STOP);
Peter Ujfalusi1d69c5c2011-10-14 14:43:33 +0300738 } else {
739 /* start delayed pop wq here for playback streams */
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600740 rtd->pop_wait = 1;
Mark Brownd4e1a732013-07-18 11:52:17 +0100741 queue_delayed_work(system_power_efficient_wq,
742 &rtd->delayed_work,
743 msecs_to_jiffies(rtd->pmdown_time));
Peter Ujfalusi1d69c5c2011-10-14 14:43:33 +0300744 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100745 } else {
746 /* capture streams can be powered down now */
Mark Brown7bd3a6f2012-02-16 15:03:27 -0800747 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000748 SND_SOC_DAPM_STREAM_STOP);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100749 }
750
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100751 mutex_unlock(&rtd->pcm_mutex);
Mark Brownd6652ef2011-12-03 20:14:31 +0000752
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000753 for_each_rtdcom(rtd, rtdcom) {
754 component = rtdcom->component;
Sanyog Kale3f809782016-01-05 17:14:49 +0530755
Kuninori Morimoto90be7112017-08-08 06:18:10 +0000756 pm_runtime_mark_last_busy(component->dev);
757 pm_runtime_put_autosuspend(component->dev);
Sanyog Kale3f809782016-01-05 17:14:49 +0530758 }
759
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200760 for (i = 0; i < rtd->num_codecs; i++) {
761 if (!rtd->codec_dais[i]->active)
762 pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev);
763 }
Nicolin Chen988e8cc2013-11-04 14:57:31 +0800764 if (!cpu_dai->active)
765 pinctrl_pm_select_sleep_state(cpu_dai->dev);
Mark Brownd6652ef2011-12-03 20:14:31 +0000766
Liam Girdwoodddee6272011-06-09 14:45:53 +0100767 return 0;
768}
769
770/*
771 * Called by ALSA when the PCM substream is prepared, can set format, sample
772 * rate, etc. This function is non atomic and can be called multiple times,
773 * it can refer to the runtime info.
774 */
775static int soc_pcm_prepare(struct snd_pcm_substream *substream)
776{
777 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000778 struct snd_soc_component *component;
779 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100780 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200781 struct snd_soc_dai *codec_dai;
782 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100783
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100784 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100785
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000786 if (rtd->dai_link->ops->prepare) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100787 ret = rtd->dai_link->ops->prepare(substream);
788 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000789 dev_err(rtd->card->dev, "ASoC: machine prepare error:"
790 " %d\n", ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100791 goto out;
792 }
793 }
794
Kuninori Morimotob8135862017-10-11 01:37:23 +0000795 for_each_rtdcom(rtd, rtdcom) {
796 component = rtdcom->component;
797
Kuninori Morimotob8135862017-10-11 01:37:23 +0000798 if (!component->driver->ops ||
799 !component->driver->ops->prepare)
800 continue;
801
802 ret = component->driver->ops->prepare(substream);
803 if (ret < 0) {
804 dev_err(component->dev,
805 "ASoC: platform prepare error: %d\n", ret);
806 goto out;
807 }
808 }
809
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200810 for (i = 0; i < rtd->num_codecs; i++) {
811 codec_dai = rtd->codec_dais[i];
Kuninori Morimoto9900a422017-09-25 01:38:54 +0000812 if (codec_dai->driver->ops->prepare) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200813 ret = codec_dai->driver->ops->prepare(substream,
814 codec_dai);
815 if (ret < 0) {
816 dev_err(codec_dai->dev,
Jarkko Nikula90cc7f12014-12-23 11:04:41 +0200817 "ASoC: codec DAI prepare error: %d\n",
818 ret);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200819 goto out;
820 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100821 }
822 }
823
Kuninori Morimoto9900a422017-09-25 01:38:54 +0000824 if (cpu_dai->driver->ops->prepare) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100825 ret = cpu_dai->driver->ops->prepare(substream, cpu_dai);
826 if (ret < 0) {
Jarkko Nikula90cc7f12014-12-23 11:04:41 +0200827 dev_err(cpu_dai->dev,
828 "ASoC: cpu DAI prepare error: %d\n", ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100829 goto out;
830 }
831 }
832
833 /* cancel any delayed stream shutdown that is pending */
834 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600835 rtd->pop_wait) {
836 rtd->pop_wait = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100837 cancel_delayed_work(&rtd->delayed_work);
838 }
839
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000840 snd_soc_dapm_stream_event(rtd, substream->stream,
841 SND_SOC_DAPM_STREAM_START);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100842
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200843 for (i = 0; i < rtd->num_codecs; i++)
844 snd_soc_dai_digital_mute(rtd->codec_dais[i], 0,
845 substream->stream);
Ramesh Babuae116012014-10-15 12:34:59 +0530846 snd_soc_dai_digital_mute(cpu_dai, 0, substream->stream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100847
848out:
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100849 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100850 return ret;
851}
852
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200853static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params,
854 unsigned int mask)
855{
856 struct snd_interval *interval;
857 int channels = hweight_long(mask);
858
859 interval = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
860 interval->min = channels;
861 interval->max = channels;
862}
863
Benoit Cousson93e69582014-07-08 23:19:38 +0200864int soc_dai_hw_params(struct snd_pcm_substream *substream,
865 struct snd_pcm_hw_params *params,
866 struct snd_soc_dai *dai)
867{
868 int ret;
869
Kuninori Morimoto9900a422017-09-25 01:38:54 +0000870 if (dai->driver->ops->hw_params) {
Benoit Cousson93e69582014-07-08 23:19:38 +0200871 ret = dai->driver->ops->hw_params(substream, params, dai);
872 if (ret < 0) {
873 dev_err(dai->dev, "ASoC: can't set %s hw params: %d\n",
874 dai->name, ret);
875 return ret;
876 }
877 }
878
879 return 0;
880}
881
Liam Girdwoodddee6272011-06-09 14:45:53 +0100882/*
883 * Called by ALSA when the hardware params are set by application. This
884 * function can also be called multiple times and can allocate buffers
885 * (using snd_pcm_lib_* ). It's non-atomic.
886 */
887static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
888 struct snd_pcm_hw_params *params)
889{
890 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000891 struct snd_soc_component *component;
892 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100893 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimotob8135862017-10-11 01:37:23 +0000894 int i, ret = 0, __ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100895
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100896 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +0000897 if (rtd->dai_link->ops->hw_params) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100898 ret = rtd->dai_link->ops->hw_params(substream, params);
899 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000900 dev_err(rtd->card->dev, "ASoC: machine hw_params"
901 " failed: %d\n", ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100902 goto out;
903 }
904 }
905
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200906 for (i = 0; i < rtd->num_codecs; i++) {
907 struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
908 struct snd_pcm_hw_params codec_params;
909
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200910 /*
911 * Skip CODECs which don't support the current stream type,
912 * the idea being that if a CODEC is not used for the currently
913 * set up transfer direction, it should not need to be
914 * configured, especially since the configuration used might
915 * not even be supported by that CODEC. There may be cases
916 * however where a CODEC needs to be set up although it is
917 * actually not being used for the transfer, e.g. if a
918 * capture-only CODEC is acting as an LRCLK and/or BCLK master
919 * for the DAI link including a playback-only CODEC.
920 * If this becomes necessary, we will have to augment the
921 * machine driver setup with information on how to act, so
922 * we can do the right thing here.
923 */
924 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
925 continue;
926
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200927 /* copy params for each codec */
928 codec_params = *params;
929
930 /* fixup params based on TDM slot masks */
931 if (codec_dai->tx_mask)
932 soc_pcm_codec_params_fixup(&codec_params,
933 codec_dai->tx_mask);
934 if (codec_dai->rx_mask)
935 soc_pcm_codec_params_fixup(&codec_params,
936 codec_dai->rx_mask);
937
Benoit Cousson93e69582014-07-08 23:19:38 +0200938 ret = soc_dai_hw_params(substream, &codec_params, codec_dai);
939 if(ret < 0)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100940 goto codec_err;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200941
942 codec_dai->rate = params_rate(&codec_params);
943 codec_dai->channels = params_channels(&codec_params);
944 codec_dai->sample_bits = snd_pcm_format_physical_width(
945 params_format(&codec_params));
Liam Girdwoodddee6272011-06-09 14:45:53 +0100946 }
947
Benoit Cousson93e69582014-07-08 23:19:38 +0200948 ret = soc_dai_hw_params(substream, params, cpu_dai);
949 if (ret < 0)
950 goto interface_err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100951
Kuninori Morimotob8135862017-10-11 01:37:23 +0000952 ret = 0;
953 for_each_rtdcom(rtd, rtdcom) {
954 component = rtdcom->component;
955
Kuninori Morimotob8135862017-10-11 01:37:23 +0000956 if (!component->driver->ops ||
957 !component->driver->ops->hw_params)
958 continue;
959
960 __ret = component->driver->ops->hw_params(substream, params);
961 if (__ret < 0) {
962 dev_err(component->dev,
963 "ASoC: %s hw params failed: %d\n",
964 component->name, ret);
965 ret = __ret;
966 }
967 }
968 if (ret < 0)
969 goto component_err;
970
Nicolin Chen3635bf02013-11-13 18:56:24 +0800971 /* store the parameters for each DAIs */
Dong Aisheng17841022011-08-29 17:15:14 +0800972 cpu_dai->rate = params_rate(params);
Nicolin Chen3635bf02013-11-13 18:56:24 +0800973 cpu_dai->channels = params_channels(params);
974 cpu_dai->sample_bits =
975 snd_pcm_format_physical_width(params_format(params));
976
jiada wang957ce0c2017-09-20 15:25:30 +0900977 ret = soc_pcm_params_symmetry(substream, params);
978 if (ret)
Kuninori Morimotob8135862017-10-11 01:37:23 +0000979 goto component_err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100980out:
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100981 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100982 return ret;
983
Kuninori Morimotob8135862017-10-11 01:37:23 +0000984component_err:
985 for_each_rtdcom(rtd, rtdcom) {
986 component = rtdcom->component;
987
Kuninori Morimotob8135862017-10-11 01:37:23 +0000988 if (!component->driver->ops ||
989 !component->driver->ops->hw_free)
990 continue;
991
992 component->driver->ops->hw_free(substream);
993 }
994
Kuninori Morimoto9900a422017-09-25 01:38:54 +0000995 if (cpu_dai->driver->ops->hw_free)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100996 cpu_dai->driver->ops->hw_free(substream, cpu_dai);
997
998interface_err:
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200999 i = rtd->num_codecs;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001000
1001codec_err:
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001002 while (--i >= 0) {
1003 struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001004 if (codec_dai->driver->ops->hw_free)
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001005 codec_dai->driver->ops->hw_free(substream, codec_dai);
1006 codec_dai->rate = 0;
1007 }
1008
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +00001009 if (rtd->dai_link->ops->hw_free)
Liam Girdwoodddee6272011-06-09 14:45:53 +01001010 rtd->dai_link->ops->hw_free(substream);
1011
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +01001012 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001013 return ret;
1014}
1015
1016/*
1017 * Frees resources allocated by hw_params, can be called multiple times
1018 */
1019static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
1020{
1021 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +00001022 struct snd_soc_component *component;
1023 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001024 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001025 struct snd_soc_dai *codec_dai;
Nicolin Chen7f62b6e2013-12-04 11:18:36 +08001026 bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001027 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001028
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +01001029 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001030
Nicolin Chend3383422013-11-20 18:37:09 +08001031 /* clear the corresponding DAIs parameters when going to be inactive */
1032 if (cpu_dai->active == 1) {
1033 cpu_dai->rate = 0;
1034 cpu_dai->channels = 0;
1035 cpu_dai->sample_bits = 0;
1036 }
1037
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001038 for (i = 0; i < rtd->num_codecs; i++) {
1039 codec_dai = rtd->codec_dais[i];
1040 if (codec_dai->active == 1) {
1041 codec_dai->rate = 0;
1042 codec_dai->channels = 0;
1043 codec_dai->sample_bits = 0;
1044 }
Nicolin Chend3383422013-11-20 18:37:09 +08001045 }
1046
Liam Girdwoodddee6272011-06-09 14:45:53 +01001047 /* apply codec digital mute */
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001048 for (i = 0; i < rtd->num_codecs; i++) {
1049 if ((playback && rtd->codec_dais[i]->playback_active == 1) ||
1050 (!playback && rtd->codec_dais[i]->capture_active == 1))
1051 snd_soc_dai_digital_mute(rtd->codec_dais[i], 1,
1052 substream->stream);
1053 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01001054
1055 /* free any machine hw params */
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +00001056 if (rtd->dai_link->ops->hw_free)
Liam Girdwoodddee6272011-06-09 14:45:53 +01001057 rtd->dai_link->ops->hw_free(substream);
1058
Kuninori Morimotob8135862017-10-11 01:37:23 +00001059 /* free any component resources */
1060 for_each_rtdcom(rtd, rtdcom) {
1061 component = rtdcom->component;
1062
Kuninori Morimotob8135862017-10-11 01:37:23 +00001063 if (!component->driver->ops ||
1064 !component->driver->ops->hw_free)
1065 continue;
1066
1067 component->driver->ops->hw_free(substream);
1068 }
1069
Liam Girdwoodddee6272011-06-09 14:45:53 +01001070 /* now free hw params for the DAIs */
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001071 for (i = 0; i < rtd->num_codecs; i++) {
1072 codec_dai = rtd->codec_dais[i];
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001073 if (codec_dai->driver->ops->hw_free)
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001074 codec_dai->driver->ops->hw_free(substream, codec_dai);
1075 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01001076
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001077 if (cpu_dai->driver->ops->hw_free)
Liam Girdwoodddee6272011-06-09 14:45:53 +01001078 cpu_dai->driver->ops->hw_free(substream, cpu_dai);
1079
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +01001080 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001081 return 0;
1082}
1083
1084static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1085{
1086 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +00001087 struct snd_soc_component *component;
1088 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001089 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001090 struct snd_soc_dai *codec_dai;
1091 int i, ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001092
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001093 for (i = 0; i < rtd->num_codecs; i++) {
1094 codec_dai = rtd->codec_dais[i];
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001095 if (codec_dai->driver->ops->trigger) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001096 ret = codec_dai->driver->ops->trigger(substream,
1097 cmd, codec_dai);
1098 if (ret < 0)
1099 return ret;
1100 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01001101 }
1102
Kuninori Morimotob8135862017-10-11 01:37:23 +00001103 for_each_rtdcom(rtd, rtdcom) {
1104 component = rtdcom->component;
1105
Kuninori Morimotob8135862017-10-11 01:37:23 +00001106 if (!component->driver->ops ||
1107 !component->driver->ops->trigger)
1108 continue;
1109
1110 ret = component->driver->ops->trigger(substream, cmd);
1111 if (ret < 0)
1112 return ret;
1113 }
1114
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001115 if (cpu_dai->driver->ops->trigger) {
Liam Girdwoodddee6272011-06-09 14:45:53 +01001116 ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai);
1117 if (ret < 0)
1118 return ret;
1119 }
Jarkko Nikula4792b0d2014-04-28 14:17:52 +02001120
Kuninori Morimoto75ab9eb2017-09-26 00:40:42 +00001121 if (rtd->dai_link->ops->trigger) {
Jarkko Nikula4792b0d2014-04-28 14:17:52 +02001122 ret = rtd->dai_link->ops->trigger(substream, cmd);
1123 if (ret < 0)
1124 return ret;
1125 }
1126
Liam Girdwoodddee6272011-06-09 14:45:53 +01001127 return 0;
1128}
1129
Mark Brown45c0a182012-05-09 21:46:27 +01001130static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
1131 int cmd)
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001132{
1133 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001134 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001135 struct snd_soc_dai *codec_dai;
1136 int i, ret;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001137
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001138 for (i = 0; i < rtd->num_codecs; i++) {
1139 codec_dai = rtd->codec_dais[i];
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001140 if (codec_dai->driver->ops->bespoke_trigger) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001141 ret = codec_dai->driver->ops->bespoke_trigger(substream,
1142 cmd, codec_dai);
1143 if (ret < 0)
1144 return ret;
1145 }
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001146 }
1147
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001148 if (cpu_dai->driver->ops->bespoke_trigger) {
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001149 ret = cpu_dai->driver->ops->bespoke_trigger(substream, cmd, cpu_dai);
1150 if (ret < 0)
1151 return ret;
1152 }
1153 return 0;
1154}
Liam Girdwoodddee6272011-06-09 14:45:53 +01001155/*
1156 * soc level wrapper for pointer callback
Charles Keepaxef050be2018-04-24 16:39:02 +01001157 * If cpu_dai, codec_dai, component driver has the delay callback, then
Liam Girdwoodddee6272011-06-09 14:45:53 +01001158 * the runtime->delay will be updated accordingly.
1159 */
1160static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
1161{
1162 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +00001163 struct snd_soc_component *component;
1164 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001165 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001166 struct snd_soc_dai *codec_dai;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001167 struct snd_pcm_runtime *runtime = substream->runtime;
1168 snd_pcm_uframes_t offset = 0;
1169 snd_pcm_sframes_t delay = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001170 snd_pcm_sframes_t codec_delay = 0;
1171 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001172
Kuninori Morimotob8135862017-10-11 01:37:23 +00001173 for_each_rtdcom(rtd, rtdcom) {
1174 component = rtdcom->component;
1175
Kuninori Morimotob8135862017-10-11 01:37:23 +00001176 if (!component->driver->ops ||
1177 !component->driver->ops->pointer)
1178 continue;
1179
1180 /* FIXME: use 1st pointer */
1181 offset = component->driver->ops->pointer(substream);
1182 break;
1183 }
1184
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001185 if (cpu_dai->driver->ops->delay)
Liam Girdwoodddee6272011-06-09 14:45:53 +01001186 delay += cpu_dai->driver->ops->delay(substream, cpu_dai);
1187
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001188 for (i = 0; i < rtd->num_codecs; i++) {
1189 codec_dai = rtd->codec_dais[i];
Kuninori Morimoto9900a422017-09-25 01:38:54 +00001190 if (codec_dai->driver->ops->delay)
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001191 codec_delay = max(codec_delay,
1192 codec_dai->driver->ops->delay(substream,
1193 codec_dai));
1194 }
1195 delay += codec_delay;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001196
Liam Girdwoodddee6272011-06-09 14:45:53 +01001197 runtime->delay = delay;
1198
1199 return offset;
1200}
1201
Liam Girdwood01d75842012-04-25 12:12:49 +01001202/* connect a FE and BE */
1203static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
1204 struct snd_soc_pcm_runtime *be, int stream)
1205{
1206 struct snd_soc_dpcm *dpcm;
1207
1208 /* only add new dpcms */
1209 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1210 if (dpcm->be == be && dpcm->fe == fe)
1211 return 0;
1212 }
1213
1214 dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_KERNEL);
1215 if (!dpcm)
1216 return -ENOMEM;
1217
1218 dpcm->be = be;
1219 dpcm->fe = fe;
1220 be->dpcm[stream].runtime = fe->dpcm[stream].runtime;
1221 dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW;
1222 list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients);
1223 list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients);
1224
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001225 dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001226 stream ? "capture" : "playback", fe->dai_link->name,
1227 stream ? "<-" : "->", be->dai_link->name);
1228
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001229#ifdef CONFIG_DEBUG_FS
Lars-Peter Clausen6553bf062015-04-09 10:52:38 +02001230 if (fe->debugfs_dpcm_root)
1231 dpcm->debugfs_state = debugfs_create_u32(be->dai_link->name, 0644,
1232 fe->debugfs_dpcm_root, &dpcm->state);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001233#endif
Liam Girdwood01d75842012-04-25 12:12:49 +01001234 return 1;
1235}
1236
1237/* reparent a BE onto another FE */
1238static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
1239 struct snd_soc_pcm_runtime *be, int stream)
1240{
1241 struct snd_soc_dpcm *dpcm;
1242 struct snd_pcm_substream *fe_substream, *be_substream;
1243
1244 /* reparent if BE is connected to other FEs */
1245 if (!be->dpcm[stream].users)
1246 return;
1247
1248 be_substream = snd_soc_dpcm_get_substream(be, stream);
1249
1250 list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {
1251 if (dpcm->fe == fe)
1252 continue;
1253
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001254 dev_dbg(fe->dev, "reparent %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001255 stream ? "capture" : "playback",
1256 dpcm->fe->dai_link->name,
1257 stream ? "<-" : "->", dpcm->be->dai_link->name);
1258
1259 fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, stream);
1260 be_substream->runtime = fe_substream->runtime;
1261 break;
1262 }
1263}
1264
1265/* disconnect a BE and FE */
Liam Girdwood23607022014-01-17 17:03:55 +00001266void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001267{
1268 struct snd_soc_dpcm *dpcm, *d;
1269
1270 list_for_each_entry_safe(dpcm, d, &fe->dpcm[stream].be_clients, list_be) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001271 dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001272 stream ? "capture" : "playback",
1273 dpcm->be->dai_link->name);
1274
1275 if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE)
1276 continue;
1277
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001278 dev_dbg(fe->dev, "freed DSP %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001279 stream ? "capture" : "playback", fe->dai_link->name,
1280 stream ? "<-" : "->", dpcm->be->dai_link->name);
1281
1282 /* BEs still alive need new FE */
1283 dpcm_be_reparent(fe, dpcm->be, stream);
1284
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001285#ifdef CONFIG_DEBUG_FS
1286 debugfs_remove(dpcm->debugfs_state);
1287#endif
Liam Girdwood01d75842012-04-25 12:12:49 +01001288 list_del(&dpcm->list_be);
1289 list_del(&dpcm->list_fe);
1290 kfree(dpcm);
1291 }
1292}
1293
1294/* get BE for DAI widget and stream */
1295static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
1296 struct snd_soc_dapm_widget *widget, int stream)
1297{
1298 struct snd_soc_pcm_runtime *be;
Mengdong Lin1a497982015-11-18 02:34:11 -05001299 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01001300
Liam Girdwood3c146462018-03-14 20:43:51 +00001301 dev_dbg(card->dev, "ASoC: find BE for widget %s\n", widget->name);
1302
Liam Girdwood01d75842012-04-25 12:12:49 +01001303 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
Mengdong Lin1a497982015-11-18 02:34:11 -05001304 list_for_each_entry(be, &card->rtd_list, list) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001305
Liam Girdwood35ea0652012-06-05 19:26:59 +01001306 if (!be->dai_link->no_pcm)
1307 continue;
1308
Liam Girdwood3c146462018-03-14 20:43:51 +00001309 dev_dbg(card->dev, "ASoC: try BE : %s\n",
1310 be->cpu_dai->playback_widget ?
1311 be->cpu_dai->playback_widget->name : "(not set)");
1312
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001313 if (be->cpu_dai->playback_widget == widget)
Liam Girdwood01d75842012-04-25 12:12:49 +01001314 return be;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001315
Mengdong Lin1a497982015-11-18 02:34:11 -05001316 for (i = 0; i < be->num_codecs; i++) {
1317 struct snd_soc_dai *dai = be->codec_dais[i];
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001318 if (dai->playback_widget == widget)
1319 return be;
1320 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001321 }
1322 } else {
1323
Mengdong Lin1a497982015-11-18 02:34:11 -05001324 list_for_each_entry(be, &card->rtd_list, list) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001325
Liam Girdwood35ea0652012-06-05 19:26:59 +01001326 if (!be->dai_link->no_pcm)
1327 continue;
1328
Liam Girdwood3c146462018-03-14 20:43:51 +00001329 dev_dbg(card->dev, "ASoC: try BE %s\n",
1330 be->cpu_dai->capture_widget ?
1331 be->cpu_dai->capture_widget->name : "(not set)");
1332
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001333 if (be->cpu_dai->capture_widget == widget)
Liam Girdwood01d75842012-04-25 12:12:49 +01001334 return be;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001335
Mengdong Lin1a497982015-11-18 02:34:11 -05001336 for (i = 0; i < be->num_codecs; i++) {
1337 struct snd_soc_dai *dai = be->codec_dais[i];
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001338 if (dai->capture_widget == widget)
1339 return be;
1340 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001341 }
1342 }
1343
Liam Girdwood3c146462018-03-14 20:43:51 +00001344 /* dai link name and stream name set correctly ? */
Liam Girdwood103d84a2012-11-19 14:39:15 +00001345 dev_err(card->dev, "ASoC: can't get %s BE for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001346 stream ? "capture" : "playback", widget->name);
1347 return NULL;
1348}
1349
1350static inline struct snd_soc_dapm_widget *
Benoit Cousson37018612014-04-24 14:01:45 +02001351 dai_get_widget(struct snd_soc_dai *dai, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001352{
1353 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
Benoit Cousson37018612014-04-24 14:01:45 +02001354 return dai->playback_widget;
Liam Girdwood01d75842012-04-25 12:12:49 +01001355 else
Benoit Cousson37018612014-04-24 14:01:45 +02001356 return dai->capture_widget;
Liam Girdwood01d75842012-04-25 12:12:49 +01001357}
1358
1359static int widget_in_list(struct snd_soc_dapm_widget_list *list,
1360 struct snd_soc_dapm_widget *widget)
1361{
1362 int i;
1363
1364 for (i = 0; i < list->num_widgets; i++) {
1365 if (widget == list->widgets[i])
1366 return 1;
1367 }
1368
1369 return 0;
1370}
1371
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001372static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget,
1373 enum snd_soc_dapm_direction dir)
1374{
1375 struct snd_soc_card *card = widget->dapm->card;
1376 struct snd_soc_pcm_runtime *rtd;
1377 int i;
1378
1379 if (dir == SND_SOC_DAPM_DIR_OUT) {
1380 list_for_each_entry(rtd, &card->rtd_list, list) {
1381 if (!rtd->dai_link->no_pcm)
1382 continue;
1383
1384 if (rtd->cpu_dai->playback_widget == widget)
1385 return true;
1386
1387 for (i = 0; i < rtd->num_codecs; ++i) {
1388 struct snd_soc_dai *dai = rtd->codec_dais[i];
1389 if (dai->playback_widget == widget)
1390 return true;
1391 }
1392 }
1393 } else { /* SND_SOC_DAPM_DIR_IN */
1394 list_for_each_entry(rtd, &card->rtd_list, list) {
1395 if (!rtd->dai_link->no_pcm)
1396 continue;
1397
1398 if (rtd->cpu_dai->capture_widget == widget)
1399 return true;
1400
1401 for (i = 0; i < rtd->num_codecs; ++i) {
1402 struct snd_soc_dai *dai = rtd->codec_dais[i];
1403 if (dai->capture_widget == widget)
1404 return true;
1405 }
1406 }
1407 }
1408
1409 return false;
1410}
1411
Liam Girdwood23607022014-01-17 17:03:55 +00001412int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001413 int stream, struct snd_soc_dapm_widget_list **list)
Liam Girdwood01d75842012-04-25 12:12:49 +01001414{
1415 struct snd_soc_dai *cpu_dai = fe->cpu_dai;
Liam Girdwood01d75842012-04-25 12:12:49 +01001416 int paths;
1417
Liam Girdwood01d75842012-04-25 12:12:49 +01001418 /* get number of valid DAI paths and their widgets */
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001419 paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list,
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001420 dpcm_end_walk_at_be);
Liam Girdwood01d75842012-04-25 12:12:49 +01001421
Liam Girdwood103d84a2012-11-19 14:39:15 +00001422 dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths,
Liam Girdwood01d75842012-04-25 12:12:49 +01001423 stream ? "capture" : "playback");
1424
Liam Girdwood01d75842012-04-25 12:12:49 +01001425 return paths;
1426}
1427
Liam Girdwood01d75842012-04-25 12:12:49 +01001428static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
1429 struct snd_soc_dapm_widget_list **list_)
1430{
1431 struct snd_soc_dpcm *dpcm;
1432 struct snd_soc_dapm_widget_list *list = *list_;
1433 struct snd_soc_dapm_widget *widget;
1434 int prune = 0;
1435
1436 /* Destroy any old FE <--> BE connections */
1437 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001438 unsigned int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01001439
1440 /* is there a valid CPU DAI widget for this BE */
Benoit Cousson37018612014-04-24 14:01:45 +02001441 widget = dai_get_widget(dpcm->be->cpu_dai, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001442
1443 /* prune the BE if it's no longer in our active list */
1444 if (widget && widget_in_list(list, widget))
1445 continue;
1446
1447 /* is there a valid CODEC DAI widget for this BE */
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001448 for (i = 0; i < dpcm->be->num_codecs; i++) {
1449 struct snd_soc_dai *dai = dpcm->be->codec_dais[i];
1450 widget = dai_get_widget(dai, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001451
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001452 /* prune the BE if it's no longer in our active list */
1453 if (widget && widget_in_list(list, widget))
1454 continue;
1455 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001456
Liam Girdwood103d84a2012-11-19 14:39:15 +00001457 dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001458 stream ? "capture" : "playback",
1459 dpcm->be->dai_link->name, fe->dai_link->name);
1460 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
1461 dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1462 prune++;
1463 }
1464
Liam Girdwood103d84a2012-11-19 14:39:15 +00001465 dev_dbg(fe->dev, "ASoC: found %d old BE paths for pruning\n", prune);
Liam Girdwood01d75842012-04-25 12:12:49 +01001466 return prune;
1467}
1468
1469static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
1470 struct snd_soc_dapm_widget_list **list_)
1471{
1472 struct snd_soc_card *card = fe->card;
1473 struct snd_soc_dapm_widget_list *list = *list_;
1474 struct snd_soc_pcm_runtime *be;
1475 int i, new = 0, err;
1476
1477 /* Create any new FE <--> BE connections */
1478 for (i = 0; i < list->num_widgets; i++) {
1479
Mark Brown46162742013-06-05 19:36:11 +01001480 switch (list->widgets[i]->id) {
1481 case snd_soc_dapm_dai_in:
Koro Chenc5b85402015-07-06 10:02:10 +08001482 if (stream != SNDRV_PCM_STREAM_PLAYBACK)
1483 continue;
1484 break;
Mark Brown46162742013-06-05 19:36:11 +01001485 case snd_soc_dapm_dai_out:
Koro Chenc5b85402015-07-06 10:02:10 +08001486 if (stream != SNDRV_PCM_STREAM_CAPTURE)
1487 continue;
Mark Brown46162742013-06-05 19:36:11 +01001488 break;
1489 default:
Liam Girdwood01d75842012-04-25 12:12:49 +01001490 continue;
Mark Brown46162742013-06-05 19:36:11 +01001491 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001492
1493 /* is there a valid BE rtd for this widget */
1494 be = dpcm_get_be(card, list->widgets[i], stream);
1495 if (!be) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001496 dev_err(fe->dev, "ASoC: no BE found for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001497 list->widgets[i]->name);
1498 continue;
1499 }
1500
1501 /* make sure BE is a real BE */
1502 if (!be->dai_link->no_pcm)
1503 continue;
1504
1505 /* don't connect if FE is not running */
Liam Girdwood23607022014-01-17 17:03:55 +00001506 if (!fe->dpcm[stream].runtime && !fe->fe_compr)
Liam Girdwood01d75842012-04-25 12:12:49 +01001507 continue;
1508
1509 /* newly connected FE and BE */
1510 err = dpcm_be_connect(fe, be, stream);
1511 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001512 dev_err(fe->dev, "ASoC: can't connect %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001513 list->widgets[i]->name);
1514 break;
1515 } else if (err == 0) /* already connected */
1516 continue;
1517
1518 /* new */
1519 be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1520 new++;
1521 }
1522
Liam Girdwood103d84a2012-11-19 14:39:15 +00001523 dev_dbg(fe->dev, "ASoC: found %d new BE paths\n", new);
Liam Girdwood01d75842012-04-25 12:12:49 +01001524 return new;
1525}
1526
1527/*
1528 * Find the corresponding BE DAIs that source or sink audio to this
1529 * FE substream.
1530 */
Liam Girdwood23607022014-01-17 17:03:55 +00001531int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
Liam Girdwood01d75842012-04-25 12:12:49 +01001532 int stream, struct snd_soc_dapm_widget_list **list, int new)
1533{
1534 if (new)
1535 return dpcm_add_paths(fe, stream, list);
1536 else
1537 return dpcm_prune_paths(fe, stream, list);
1538}
1539
Liam Girdwood23607022014-01-17 17:03:55 +00001540void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001541{
1542 struct snd_soc_dpcm *dpcm;
1543
1544 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
1545 dpcm->be->dpcm[stream].runtime_update =
1546 SND_SOC_DPCM_UPDATE_NO;
1547}
1548
1549static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe,
1550 int stream)
1551{
1552 struct snd_soc_dpcm *dpcm;
1553
1554 /* disable any enabled and non active backends */
1555 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1556
1557 struct snd_soc_pcm_runtime *be = dpcm->be;
1558 struct snd_pcm_substream *be_substream =
1559 snd_soc_dpcm_get_substream(be, stream);
1560
1561 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001562 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001563 stream ? "capture" : "playback",
1564 be->dpcm[stream].state);
1565
1566 if (--be->dpcm[stream].users != 0)
1567 continue;
1568
1569 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1570 continue;
1571
1572 soc_pcm_close(be_substream);
1573 be_substream->runtime = NULL;
1574 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1575 }
1576}
1577
Liam Girdwood23607022014-01-17 17:03:55 +00001578int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001579{
1580 struct snd_soc_dpcm *dpcm;
1581 int err, count = 0;
1582
1583 /* only startup BE DAIs that are either sinks or sources to this FE DAI */
1584 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1585
1586 struct snd_soc_pcm_runtime *be = dpcm->be;
1587 struct snd_pcm_substream *be_substream =
1588 snd_soc_dpcm_get_substream(be, stream);
1589
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001590 if (!be_substream) {
1591 dev_err(be->dev, "ASoC: no backend %s stream\n",
1592 stream ? "capture" : "playback");
1593 continue;
1594 }
1595
Liam Girdwood01d75842012-04-25 12:12:49 +01001596 /* is this op for this BE ? */
1597 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1598 continue;
1599
1600 /* first time the dpcm is open ? */
1601 if (be->dpcm[stream].users == DPCM_MAX_BE_USERS)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001602 dev_err(be->dev, "ASoC: too many users %s at open %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001603 stream ? "capture" : "playback",
1604 be->dpcm[stream].state);
1605
1606 if (be->dpcm[stream].users++ != 0)
1607 continue;
1608
1609 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
1610 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
1611 continue;
1612
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001613 dev_dbg(be->dev, "ASoC: open %s BE %s\n",
1614 stream ? "capture" : "playback", be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001615
1616 be_substream->runtime = be->dpcm[stream].runtime;
1617 err = soc_pcm_open(be_substream);
1618 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001619 dev_err(be->dev, "ASoC: BE open failed %d\n", err);
Liam Girdwood01d75842012-04-25 12:12:49 +01001620 be->dpcm[stream].users--;
1621 if (be->dpcm[stream].users < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001622 dev_err(be->dev, "ASoC: no users %s at unwind %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001623 stream ? "capture" : "playback",
1624 be->dpcm[stream].state);
1625
1626 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1627 goto unwind;
1628 }
1629
1630 be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1631 count++;
1632 }
1633
1634 return count;
1635
1636unwind:
1637 /* disable any enabled and non active backends */
1638 list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1639 struct snd_soc_pcm_runtime *be = dpcm->be;
1640 struct snd_pcm_substream *be_substream =
1641 snd_soc_dpcm_get_substream(be, stream);
1642
1643 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1644 continue;
1645
1646 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001647 dev_err(be->dev, "ASoC: no users %s at close %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001648 stream ? "capture" : "playback",
1649 be->dpcm[stream].state);
1650
1651 if (--be->dpcm[stream].users != 0)
1652 continue;
1653
1654 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1655 continue;
1656
1657 soc_pcm_close(be_substream);
1658 be_substream->runtime = NULL;
1659 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1660 }
1661
1662 return err;
1663}
1664
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001665static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001666 struct snd_soc_pcm_stream *stream,
1667 u64 formats)
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001668{
1669 runtime->hw.rate_min = stream->rate_min;
1670 runtime->hw.rate_max = stream->rate_max;
1671 runtime->hw.channels_min = stream->channels_min;
1672 runtime->hw.channels_max = stream->channels_max;
Lars-Peter Clausen002220a2014-01-06 14:19:07 +01001673 if (runtime->hw.formats)
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001674 runtime->hw.formats &= formats & stream->formats;
Lars-Peter Clausen002220a2014-01-06 14:19:07 +01001675 else
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001676 runtime->hw.formats = formats & stream->formats;
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001677 runtime->hw.rates = stream->rates;
1678}
1679
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001680static u64 dpcm_runtime_base_format(struct snd_pcm_substream *substream)
1681{
1682 struct snd_soc_pcm_runtime *fe = substream->private_data;
1683 struct snd_soc_dpcm *dpcm;
1684 u64 formats = ULLONG_MAX;
1685 int stream = substream->stream;
1686
1687 if (!fe->dai_link->dpcm_merged_format)
1688 return formats;
1689
1690 /*
1691 * It returns merged BE codec format
1692 * if FE want to use it (= dpcm_merged_format)
1693 */
1694
1695 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1696 struct snd_soc_pcm_runtime *be = dpcm->be;
1697 struct snd_soc_dai_driver *codec_dai_drv;
1698 struct snd_soc_pcm_stream *codec_stream;
1699 int i;
1700
1701 for (i = 0; i < be->num_codecs; i++) {
1702 codec_dai_drv = be->codec_dais[i]->driver;
1703 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1704 codec_stream = &codec_dai_drv->playback;
1705 else
1706 codec_stream = &codec_dai_drv->capture;
1707
1708 formats &= codec_stream->formats;
1709 }
1710 }
1711
1712 return formats;
1713}
1714
Mark Brown45c0a182012-05-09 21:46:27 +01001715static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001716{
1717 struct snd_pcm_runtime *runtime = substream->runtime;
1718 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1719 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
1720 struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001721 u64 format = dpcm_runtime_base_format(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001722
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001723 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001724 dpcm_init_runtime_hw(runtime, &cpu_dai_drv->playback, format);
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001725 else
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001726 dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture, format);
Liam Girdwood01d75842012-04-25 12:12:49 +01001727}
1728
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001729static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
1730
1731/* Set FE's runtime_update state; the state is protected via PCM stream lock
1732 * for avoiding the race with trigger callback.
1733 * If the state is unset and a trigger is pending while the previous operation,
1734 * process the pending trigger action here.
1735 */
1736static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
1737 int stream, enum snd_soc_dpcm_update state)
1738{
1739 struct snd_pcm_substream *substream =
1740 snd_soc_dpcm_get_substream(fe, stream);
1741
1742 snd_pcm_stream_lock_irq(substream);
1743 if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) {
1744 dpcm_fe_dai_do_trigger(substream,
1745 fe->dpcm[stream].trigger_pending - 1);
1746 fe->dpcm[stream].trigger_pending = 0;
1747 }
1748 fe->dpcm[stream].runtime_update = state;
1749 snd_pcm_stream_unlock_irq(substream);
1750}
1751
PC Liao906c7d62015-12-11 11:33:51 +08001752static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
1753 int stream)
1754{
1755 struct snd_soc_dpcm *dpcm;
1756 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
1757 struct snd_soc_dai *fe_cpu_dai = fe->cpu_dai;
1758 int err;
1759
1760 /* apply symmetry for FE */
1761 if (soc_pcm_has_symmetry(fe_substream))
1762 fe_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1763
1764 /* Symmetry only applies if we've got an active stream. */
1765 if (fe_cpu_dai->active) {
1766 err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai);
1767 if (err < 0)
1768 return err;
1769 }
1770
1771 /* apply symmetry for BE */
1772 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1773 struct snd_soc_pcm_runtime *be = dpcm->be;
1774 struct snd_pcm_substream *be_substream =
1775 snd_soc_dpcm_get_substream(be, stream);
1776 struct snd_soc_pcm_runtime *rtd = be_substream->private_data;
1777 int i;
1778
Jeeja KPf1176612016-09-06 14:17:55 +05301779 if (rtd->dai_link->be_hw_params_fixup)
1780 continue;
1781
PC Liao906c7d62015-12-11 11:33:51 +08001782 if (soc_pcm_has_symmetry(be_substream))
1783 be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1784
1785 /* Symmetry only applies if we've got an active stream. */
1786 if (rtd->cpu_dai->active) {
1787 err = soc_pcm_apply_symmetry(be_substream, rtd->cpu_dai);
1788 if (err < 0)
1789 return err;
1790 }
1791
1792 for (i = 0; i < rtd->num_codecs; i++) {
1793 if (rtd->codec_dais[i]->active) {
1794 err = soc_pcm_apply_symmetry(be_substream,
1795 rtd->codec_dais[i]);
1796 if (err < 0)
1797 return err;
1798 }
1799 }
1800 }
1801
1802 return 0;
1803}
1804
Liam Girdwood01d75842012-04-25 12:12:49 +01001805static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
1806{
1807 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
1808 struct snd_pcm_runtime *runtime = fe_substream->runtime;
1809 int stream = fe_substream->stream, ret = 0;
1810
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001811 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001812
1813 ret = dpcm_be_dai_startup(fe, fe_substream->stream);
1814 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001815 dev_err(fe->dev,"ASoC: failed to start some BEs %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001816 goto be_err;
1817 }
1818
Liam Girdwood103d84a2012-11-19 14:39:15 +00001819 dev_dbg(fe->dev, "ASoC: open FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001820
1821 /* start the DAI frontend */
1822 ret = soc_pcm_open(fe_substream);
1823 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001824 dev_err(fe->dev,"ASoC: failed to start FE %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001825 goto unwind;
1826 }
1827
1828 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1829
1830 dpcm_set_fe_runtime(fe_substream);
1831 snd_pcm_limit_hw_rates(runtime);
1832
PC Liao906c7d62015-12-11 11:33:51 +08001833 ret = dpcm_apply_symmetry(fe_substream, stream);
1834 if (ret < 0) {
1835 dev_err(fe->dev, "ASoC: failed to apply dpcm symmetry %d\n",
1836 ret);
1837 goto unwind;
1838 }
1839
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001840 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001841 return 0;
1842
1843unwind:
1844 dpcm_be_dai_startup_unwind(fe, fe_substream->stream);
1845be_err:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001846 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001847 return ret;
1848}
1849
Liam Girdwood23607022014-01-17 17:03:55 +00001850int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001851{
1852 struct snd_soc_dpcm *dpcm;
1853
1854 /* only shutdown BEs that are either sinks or sources to this FE DAI */
1855 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1856
1857 struct snd_soc_pcm_runtime *be = dpcm->be;
1858 struct snd_pcm_substream *be_substream =
1859 snd_soc_dpcm_get_substream(be, stream);
1860
1861 /* is this op for this BE ? */
1862 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1863 continue;
1864
1865 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001866 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001867 stream ? "capture" : "playback",
1868 be->dpcm[stream].state);
1869
1870 if (--be->dpcm[stream].users != 0)
1871 continue;
1872
1873 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
1874 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN))
1875 continue;
1876
Liam Girdwood103d84a2012-11-19 14:39:15 +00001877 dev_dbg(be->dev, "ASoC: close BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001878 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001879
1880 soc_pcm_close(be_substream);
1881 be_substream->runtime = NULL;
1882
1883 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1884 }
1885 return 0;
1886}
1887
1888static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
1889{
1890 struct snd_soc_pcm_runtime *fe = substream->private_data;
1891 int stream = substream->stream;
1892
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001893 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001894
1895 /* shutdown the BEs */
1896 dpcm_be_dai_shutdown(fe, substream->stream);
1897
Liam Girdwood103d84a2012-11-19 14:39:15 +00001898 dev_dbg(fe->dev, "ASoC: close FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001899
1900 /* now shutdown the frontend */
1901 soc_pcm_close(substream);
1902
1903 /* run the stream event for each BE */
1904 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
1905
1906 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001907 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001908 return 0;
1909}
1910
Liam Girdwood23607022014-01-17 17:03:55 +00001911int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001912{
1913 struct snd_soc_dpcm *dpcm;
1914
1915 /* only hw_params backends that are either sinks or sources
1916 * to this frontend DAI */
1917 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1918
1919 struct snd_soc_pcm_runtime *be = dpcm->be;
1920 struct snd_pcm_substream *be_substream =
1921 snd_soc_dpcm_get_substream(be, stream);
1922
1923 /* is this op for this BE ? */
1924 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1925 continue;
1926
1927 /* only free hw when no longer used - check all FEs */
1928 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1929 continue;
1930
Qiao Zhou36fba622014-12-03 10:13:43 +08001931 /* do not free hw if this BE is used by other FE */
1932 if (be->dpcm[stream].users > 1)
1933 continue;
1934
Liam Girdwood01d75842012-04-25 12:12:49 +01001935 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1936 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
1937 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Patrick Lai08b27842012-12-19 19:36:02 -08001938 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
Vinod Koul5e82d2b2016-02-01 22:26:40 +05301939 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
1940 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
Liam Girdwood01d75842012-04-25 12:12:49 +01001941 continue;
1942
Liam Girdwood103d84a2012-11-19 14:39:15 +00001943 dev_dbg(be->dev, "ASoC: hw_free BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001944 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001945
1946 soc_pcm_hw_free(be_substream);
1947
1948 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1949 }
1950
1951 return 0;
1952}
1953
Mark Brown45c0a182012-05-09 21:46:27 +01001954static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001955{
1956 struct snd_soc_pcm_runtime *fe = substream->private_data;
1957 int err, stream = substream->stream;
1958
1959 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001960 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001961
Liam Girdwood103d84a2012-11-19 14:39:15 +00001962 dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001963
1964 /* call hw_free on the frontend */
1965 err = soc_pcm_hw_free(substream);
1966 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001967 dev_err(fe->dev,"ASoC: hw_free FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001968 fe->dai_link->name);
1969
1970 /* only hw_params backends that are either sinks or sources
1971 * to this frontend DAI */
1972 err = dpcm_be_dai_hw_free(fe, stream);
1973
1974 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001975 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001976
1977 mutex_unlock(&fe->card->mutex);
1978 return 0;
1979}
1980
Liam Girdwood23607022014-01-17 17:03:55 +00001981int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001982{
1983 struct snd_soc_dpcm *dpcm;
1984 int ret;
1985
1986 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1987
1988 struct snd_soc_pcm_runtime *be = dpcm->be;
1989 struct snd_pcm_substream *be_substream =
1990 snd_soc_dpcm_get_substream(be, stream);
1991
1992 /* is this op for this BE ? */
1993 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1994 continue;
1995
Liam Girdwood01d75842012-04-25 12:12:49 +01001996 /* copy params for each dpcm */
1997 memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params,
1998 sizeof(struct snd_pcm_hw_params));
1999
2000 /* perform any hw_params fixups */
2001 if (be->dai_link->be_hw_params_fixup) {
2002 ret = be->dai_link->be_hw_params_fixup(be,
2003 &dpcm->hw_params);
2004 if (ret < 0) {
2005 dev_err(be->dev,
Liam Girdwood103d84a2012-11-19 14:39:15 +00002006 "ASoC: hw_params BE fixup failed %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002007 ret);
2008 goto unwind;
2009 }
2010 }
2011
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00002012 /* only allow hw_params() if no connected FEs are running */
2013 if (!snd_soc_dpcm_can_be_params(fe, be, stream))
2014 continue;
2015
2016 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
2017 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2018 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE))
2019 continue;
2020
2021 dev_dbg(be->dev, "ASoC: hw_params BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002022 be->dai_link->name);
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00002023
Liam Girdwood01d75842012-04-25 12:12:49 +01002024 ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params);
2025 if (ret < 0) {
2026 dev_err(dpcm->be->dev,
Liam Girdwood103d84a2012-11-19 14:39:15 +00002027 "ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002028 goto unwind;
2029 }
2030
2031 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2032 }
2033 return 0;
2034
2035unwind:
2036 /* disable any enabled and non active backends */
2037 list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) {
2038 struct snd_soc_pcm_runtime *be = dpcm->be;
2039 struct snd_pcm_substream *be_substream =
2040 snd_soc_dpcm_get_substream(be, stream);
2041
2042 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2043 continue;
2044
2045 /* only allow hw_free() if no connected FEs are running */
2046 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2047 continue;
2048
2049 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
2050 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2051 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
2052 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
2053 continue;
2054
2055 soc_pcm_hw_free(be_substream);
2056 }
2057
2058 return ret;
2059}
2060
Mark Brown45c0a182012-05-09 21:46:27 +01002061static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
2062 struct snd_pcm_hw_params *params)
Liam Girdwood01d75842012-04-25 12:12:49 +01002063{
2064 struct snd_soc_pcm_runtime *fe = substream->private_data;
2065 int ret, stream = substream->stream;
2066
2067 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002068 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002069
2070 memcpy(&fe->dpcm[substream->stream].hw_params, params,
2071 sizeof(struct snd_pcm_hw_params));
2072 ret = dpcm_be_dai_hw_params(fe, substream->stream);
2073 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002074 dev_err(fe->dev,"ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002075 goto out;
2076 }
2077
Liam Girdwood103d84a2012-11-19 14:39:15 +00002078 dev_dbg(fe->dev, "ASoC: hw_params FE %s rate %d chan %x fmt %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002079 fe->dai_link->name, params_rate(params),
2080 params_channels(params), params_format(params));
2081
2082 /* call hw_params on the frontend */
2083 ret = soc_pcm_hw_params(substream, params);
2084 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002085 dev_err(fe->dev,"ASoC: hw_params FE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002086 dpcm_be_dai_hw_free(fe, stream);
2087 } else
2088 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2089
2090out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002091 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002092 mutex_unlock(&fe->card->mutex);
2093 return ret;
2094}
2095
2096static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm,
2097 struct snd_pcm_substream *substream, int cmd)
2098{
2099 int ret;
2100
Liam Girdwood103d84a2012-11-19 14:39:15 +00002101 dev_dbg(dpcm->be->dev, "ASoC: trigger BE %s cmd %d\n",
彭东林94d215c2016-09-26 08:29:31 +00002102 dpcm->be->dai_link->name, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002103
2104 ret = soc_pcm_trigger(substream, cmd);
2105 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002106 dev_err(dpcm->be->dev,"ASoC: trigger BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002107
2108 return ret;
2109}
2110
Liam Girdwood23607022014-01-17 17:03:55 +00002111int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
Mark Brown45c0a182012-05-09 21:46:27 +01002112 int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002113{
2114 struct snd_soc_dpcm *dpcm;
2115 int ret = 0;
2116
2117 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
2118
2119 struct snd_soc_pcm_runtime *be = dpcm->be;
2120 struct snd_pcm_substream *be_substream =
2121 snd_soc_dpcm_get_substream(be, stream);
2122
2123 /* is this op for this BE ? */
2124 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2125 continue;
2126
2127 switch (cmd) {
2128 case SNDRV_PCM_TRIGGER_START:
2129 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
2130 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
2131 continue;
2132
2133 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2134 if (ret)
2135 return ret;
2136
2137 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2138 break;
2139 case SNDRV_PCM_TRIGGER_RESUME:
2140 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
2141 continue;
2142
2143 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2144 if (ret)
2145 return ret;
2146
2147 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2148 break;
2149 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2150 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
2151 continue;
2152
2153 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2154 if (ret)
2155 return ret;
2156
2157 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2158 break;
2159 case SNDRV_PCM_TRIGGER_STOP:
2160 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2161 continue;
2162
2163 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2164 continue;
2165
2166 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2167 if (ret)
2168 return ret;
2169
2170 be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2171 break;
2172 case SNDRV_PCM_TRIGGER_SUSPEND:
Nicolin Chen868a6ca2014-05-12 20:12:05 +08002173 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
Liam Girdwood01d75842012-04-25 12:12:49 +01002174 continue;
2175
2176 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2177 continue;
2178
2179 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2180 if (ret)
2181 return ret;
2182
2183 be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND;
2184 break;
2185 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2186 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2187 continue;
2188
2189 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2190 continue;
2191
2192 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2193 if (ret)
2194 return ret;
2195
2196 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2197 break;
2198 }
2199 }
2200
2201 return ret;
2202}
2203EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
2204
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002205static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002206{
2207 struct snd_soc_pcm_runtime *fe = substream->private_data;
2208 int stream = substream->stream, ret;
2209 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
2210
2211 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
2212
2213 switch (trigger) {
2214 case SND_SOC_DPCM_TRIGGER_PRE:
2215 /* call trigger on the frontend before the backend. */
2216
Liam Girdwood103d84a2012-11-19 14:39:15 +00002217 dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002218 fe->dai_link->name, cmd);
2219
2220 ret = soc_pcm_trigger(substream, cmd);
2221 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002222 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002223 goto out;
2224 }
2225
2226 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2227 break;
2228 case SND_SOC_DPCM_TRIGGER_POST:
2229 /* call trigger on the frontend after the backend. */
2230
2231 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2232 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002233 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002234 goto out;
2235 }
2236
Liam Girdwood103d84a2012-11-19 14:39:15 +00002237 dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002238 fe->dai_link->name, cmd);
2239
2240 ret = soc_pcm_trigger(substream, cmd);
2241 break;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002242 case SND_SOC_DPCM_TRIGGER_BESPOKE:
2243 /* bespoke trigger() - handles both FE and BEs */
2244
Liam Girdwood103d84a2012-11-19 14:39:15 +00002245 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd %d\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002246 fe->dai_link->name, cmd);
2247
2248 ret = soc_pcm_bespoke_trigger(substream, cmd);
2249 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002250 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002251 goto out;
2252 }
2253 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002254 default:
Liam Girdwood103d84a2012-11-19 14:39:15 +00002255 dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd,
Liam Girdwood01d75842012-04-25 12:12:49 +01002256 fe->dai_link->name);
2257 ret = -EINVAL;
2258 goto out;
2259 }
2260
2261 switch (cmd) {
2262 case SNDRV_PCM_TRIGGER_START:
2263 case SNDRV_PCM_TRIGGER_RESUME:
2264 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2265 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2266 break;
2267 case SNDRV_PCM_TRIGGER_STOP:
2268 case SNDRV_PCM_TRIGGER_SUSPEND:
Liam Girdwood01d75842012-04-25 12:12:49 +01002269 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2270 break;
Patrick Lai9f169b92016-12-31 22:44:39 -08002271 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2272 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2273 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002274 }
2275
2276out:
2277 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
2278 return ret;
2279}
2280
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002281static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
2282{
2283 struct snd_soc_pcm_runtime *fe = substream->private_data;
2284 int stream = substream->stream;
2285
2286 /* if FE's runtime_update is already set, we're in race;
2287 * process this trigger later at exit
2288 */
2289 if (fe->dpcm[stream].runtime_update != SND_SOC_DPCM_UPDATE_NO) {
2290 fe->dpcm[stream].trigger_pending = cmd + 1;
2291 return 0; /* delayed, assuming it's successful */
2292 }
2293
2294 /* we're alone, let's trigger */
2295 return dpcm_fe_dai_do_trigger(substream, cmd);
2296}
2297
Liam Girdwood23607022014-01-17 17:03:55 +00002298int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002299{
2300 struct snd_soc_dpcm *dpcm;
2301 int ret = 0;
2302
2303 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
2304
2305 struct snd_soc_pcm_runtime *be = dpcm->be;
2306 struct snd_pcm_substream *be_substream =
2307 snd_soc_dpcm_get_substream(be, stream);
2308
2309 /* is this op for this BE ? */
2310 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2311 continue;
2312
2313 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
Koro Chen95f444d2015-10-28 10:15:34 +08002314 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
2315 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
Liam Girdwood01d75842012-04-25 12:12:49 +01002316 continue;
2317
Liam Girdwood103d84a2012-11-19 14:39:15 +00002318 dev_dbg(be->dev, "ASoC: prepare BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002319 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002320
2321 ret = soc_pcm_prepare(be_substream);
2322 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002323 dev_err(be->dev, "ASoC: backend prepare failed %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002324 ret);
2325 break;
2326 }
2327
2328 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2329 }
2330 return ret;
2331}
2332
Mark Brown45c0a182012-05-09 21:46:27 +01002333static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002334{
2335 struct snd_soc_pcm_runtime *fe = substream->private_data;
2336 int stream = substream->stream, ret = 0;
2337
2338 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2339
Liam Girdwood103d84a2012-11-19 14:39:15 +00002340 dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002341
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002342 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002343
2344 /* there is no point preparing this FE if there are no BEs */
2345 if (list_empty(&fe->dpcm[stream].be_clients)) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002346 dev_err(fe->dev, "ASoC: no backend DAIs enabled for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002347 fe->dai_link->name);
2348 ret = -EINVAL;
2349 goto out;
2350 }
2351
2352 ret = dpcm_be_dai_prepare(fe, substream->stream);
2353 if (ret < 0)
2354 goto out;
2355
2356 /* call prepare on the frontend */
2357 ret = soc_pcm_prepare(substream);
2358 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002359 dev_err(fe->dev,"ASoC: prepare FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002360 fe->dai_link->name);
2361 goto out;
2362 }
2363
2364 /* run the stream event for each BE */
2365 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
2366 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2367
2368out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002369 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002370 mutex_unlock(&fe->card->mutex);
2371
2372 return ret;
2373}
2374
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01002375static int soc_pcm_ioctl(struct snd_pcm_substream *substream,
2376 unsigned int cmd, void *arg)
2377{
2378 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Kuninori Morimotob8135862017-10-11 01:37:23 +00002379 struct snd_soc_component *component;
2380 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01002381
Kuninori Morimotob8135862017-10-11 01:37:23 +00002382 for_each_rtdcom(rtd, rtdcom) {
2383 component = rtdcom->component;
2384
Kuninori Morimotob8135862017-10-11 01:37:23 +00002385 if (!component->driver->ops ||
2386 !component->driver->ops->ioctl)
2387 continue;
2388
2389 /* FIXME: use 1st ioctl */
2390 return component->driver->ops->ioctl(substream, cmd, arg);
2391 }
2392
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01002393 return snd_pcm_lib_ioctl(substream, cmd, arg);
2394}
2395
Liam Girdwood618dae12012-04-25 12:12:51 +01002396static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
2397{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002398 struct snd_pcm_substream *substream =
2399 snd_soc_dpcm_get_substream(fe, stream);
2400 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01002401 int err;
Liam Girdwood01d75842012-04-25 12:12:49 +01002402
Liam Girdwood103d84a2012-11-19 14:39:15 +00002403 dev_dbg(fe->dev, "ASoC: runtime %s close on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002404 stream ? "capture" : "playback", fe->dai_link->name);
2405
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002406 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2407 /* call bespoke trigger - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002408 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002409 fe->dai_link->name);
2410
2411 err = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
2412 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002413 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002414 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002415 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002416 fe->dai_link->name);
2417
2418 err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
2419 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002420 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002421 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002422
2423 err = dpcm_be_dai_hw_free(fe, stream);
2424 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002425 dev_err(fe->dev,"ASoC: hw_free FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002426
2427 err = dpcm_be_dai_shutdown(fe, stream);
2428 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002429 dev_err(fe->dev,"ASoC: shutdown FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002430
2431 /* run the stream event for each BE */
2432 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2433
2434 return 0;
2435}
2436
2437static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
2438{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002439 struct snd_pcm_substream *substream =
2440 snd_soc_dpcm_get_substream(fe, stream);
Liam Girdwood618dae12012-04-25 12:12:51 +01002441 struct snd_soc_dpcm *dpcm;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002442 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01002443 int ret;
2444
Liam Girdwood103d84a2012-11-19 14:39:15 +00002445 dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002446 stream ? "capture" : "playback", fe->dai_link->name);
2447
2448 /* Only start the BE if the FE is ready */
2449 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
2450 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE)
2451 return -EINVAL;
2452
2453 /* startup must always be called for new BEs */
2454 ret = dpcm_be_dai_startup(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002455 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002456 goto disconnect;
Liam Girdwood618dae12012-04-25 12:12:51 +01002457
2458 /* keep going if FE state is > open */
2459 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN)
2460 return 0;
2461
2462 ret = dpcm_be_dai_hw_params(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002463 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002464 goto close;
Liam Girdwood618dae12012-04-25 12:12:51 +01002465
2466 /* keep going if FE state is > hw_params */
2467 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS)
2468 return 0;
2469
2470
2471 ret = dpcm_be_dai_prepare(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002472 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002473 goto hw_free;
Liam Girdwood618dae12012-04-25 12:12:51 +01002474
2475 /* run the stream event for each BE */
2476 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2477
2478 /* keep going if FE state is > prepare */
2479 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE ||
2480 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP)
2481 return 0;
2482
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002483 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2484 /* call trigger on the frontend - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002485 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002486 fe->dai_link->name);
Liam Girdwood618dae12012-04-25 12:12:51 +01002487
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002488 ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
2489 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002490 dev_err(fe->dev,"ASoC: bespoke trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002491 goto hw_free;
2492 }
2493 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002494 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002495 fe->dai_link->name);
2496
2497 ret = dpcm_be_dai_trigger(fe, stream,
2498 SNDRV_PCM_TRIGGER_START);
2499 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002500 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002501 goto hw_free;
2502 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002503 }
2504
2505 return 0;
2506
2507hw_free:
2508 dpcm_be_dai_hw_free(fe, stream);
2509close:
2510 dpcm_be_dai_shutdown(fe, stream);
2511disconnect:
2512 /* disconnect any non started BEs */
2513 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
2514 struct snd_soc_pcm_runtime *be = dpcm->be;
2515 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2516 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2517 }
2518
2519 return ret;
2520}
2521
2522static int dpcm_run_new_update(struct snd_soc_pcm_runtime *fe, int stream)
2523{
2524 int ret;
2525
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002526 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood618dae12012-04-25 12:12:51 +01002527 ret = dpcm_run_update_startup(fe, stream);
2528 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002529 dev_err(fe->dev, "ASoC: failed to startup some BEs\n");
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002530 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood618dae12012-04-25 12:12:51 +01002531
2532 return ret;
2533}
2534
2535static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream)
2536{
2537 int ret;
2538
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002539 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood618dae12012-04-25 12:12:51 +01002540 ret = dpcm_run_update_shutdown(fe, stream);
2541 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002542 dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n");
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002543 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood618dae12012-04-25 12:12:51 +01002544
2545 return ret;
2546}
2547
2548/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
2549 * any DAI links.
2550 */
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002551int soc_dpcm_runtime_update(struct snd_soc_card *card)
Liam Girdwood618dae12012-04-25 12:12:51 +01002552{
Mengdong Lin1a497982015-11-18 02:34:11 -05002553 struct snd_soc_pcm_runtime *fe;
2554 int old, new, paths;
Liam Girdwood618dae12012-04-25 12:12:51 +01002555
Liam Girdwood618dae12012-04-25 12:12:51 +01002556 mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Mengdong Lin1a497982015-11-18 02:34:11 -05002557 list_for_each_entry(fe, &card->rtd_list, list) {
Liam Girdwood618dae12012-04-25 12:12:51 +01002558 struct snd_soc_dapm_widget_list *list;
Liam Girdwood618dae12012-04-25 12:12:51 +01002559
2560 /* make sure link is FE */
2561 if (!fe->dai_link->dynamic)
2562 continue;
2563
2564 /* only check active links */
2565 if (!fe->cpu_dai->active)
2566 continue;
2567
2568 /* DAPM sync will call this to update DSP paths */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002569 dev_dbg(fe->dev, "ASoC: DPCM runtime update for FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002570 fe->dai_link->name);
2571
2572 /* skip if FE doesn't have playback capability */
Qiao Zhou075207d2014-11-17 16:02:57 +08002573 if (!fe->cpu_dai->driver->playback.channels_min
2574 || !fe->codec_dai->driver->playback.channels_min)
2575 goto capture;
2576
2577 /* skip if FE isn't currently playing */
2578 if (!fe->cpu_dai->playback_active
2579 || !fe->codec_dai->playback_active)
Liam Girdwood618dae12012-04-25 12:12:51 +01002580 goto capture;
2581
2582 paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list);
2583 if (paths < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002584 dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002585 fe->dai_link->name, "playback");
2586 mutex_unlock(&card->mutex);
2587 return paths;
2588 }
2589
2590 /* update any new playback paths */
2591 new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 1);
2592 if (new) {
2593 dpcm_run_new_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
2594 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
2595 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
2596 }
2597
2598 /* update any old playback paths */
2599 old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 0);
2600 if (old) {
2601 dpcm_run_old_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
2602 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
2603 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
2604 }
2605
Qiao Zhou7ed9de72014-06-04 19:42:06 +08002606 dpcm_path_put(&list);
Liam Girdwood618dae12012-04-25 12:12:51 +01002607capture:
2608 /* skip if FE doesn't have capture capability */
Qiao Zhou075207d2014-11-17 16:02:57 +08002609 if (!fe->cpu_dai->driver->capture.channels_min
2610 || !fe->codec_dai->driver->capture.channels_min)
2611 continue;
2612
2613 /* skip if FE isn't currently capturing */
2614 if (!fe->cpu_dai->capture_active
2615 || !fe->codec_dai->capture_active)
Liam Girdwood618dae12012-04-25 12:12:51 +01002616 continue;
2617
2618 paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list);
2619 if (paths < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002620 dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002621 fe->dai_link->name, "capture");
2622 mutex_unlock(&card->mutex);
2623 return paths;
2624 }
2625
2626 /* update any new capture paths */
2627 new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 1);
2628 if (new) {
2629 dpcm_run_new_update(fe, SNDRV_PCM_STREAM_CAPTURE);
2630 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
2631 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
2632 }
2633
2634 /* update any old capture paths */
2635 old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 0);
2636 if (old) {
2637 dpcm_run_old_update(fe, SNDRV_PCM_STREAM_CAPTURE);
2638 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
2639 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
2640 }
2641
2642 dpcm_path_put(&list);
2643 }
2644
2645 mutex_unlock(&card->mutex);
2646 return 0;
2647}
Liam Girdwood01d75842012-04-25 12:12:49 +01002648int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute)
2649{
2650 struct snd_soc_dpcm *dpcm;
2651 struct list_head *clients =
2652 &fe->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients;
2653
2654 list_for_each_entry(dpcm, clients, list_be) {
2655
2656 struct snd_soc_pcm_runtime *be = dpcm->be;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002657 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01002658
2659 if (be->dai_link->ignore_suspend)
2660 continue;
2661
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002662 for (i = 0; i < be->num_codecs; i++) {
2663 struct snd_soc_dai *dai = be->codec_dais[i];
2664 struct snd_soc_dai_driver *drv = dai->driver;
Liam Girdwood01d75842012-04-25 12:12:49 +01002665
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002666 dev_dbg(be->dev, "ASoC: BE digital mute %s\n",
2667 be->dai_link->name);
2668
2669 if (drv->ops && drv->ops->digital_mute &&
2670 dai->playback_active)
2671 drv->ops->digital_mute(dai, mute);
2672 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002673 }
2674
2675 return 0;
2676}
2677
Mark Brown45c0a182012-05-09 21:46:27 +01002678static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002679{
2680 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
2681 struct snd_soc_dpcm *dpcm;
2682 struct snd_soc_dapm_widget_list *list;
2683 int ret;
2684 int stream = fe_substream->stream;
2685
2686 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2687 fe->dpcm[stream].runtime = fe_substream->runtime;
2688
Qiao Zhou8f70e512014-09-10 17:54:07 +08002689 ret = dpcm_path_get(fe, stream, &list);
2690 if (ret < 0) {
2691 mutex_unlock(&fe->card->mutex);
2692 return ret;
2693 } else if (ret == 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002694 dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002695 fe->dai_link->name, stream ? "capture" : "playback");
Liam Girdwood01d75842012-04-25 12:12:49 +01002696 }
2697
2698 /* calculate valid and active FE <-> BE dpcms */
2699 dpcm_process_paths(fe, stream, &list, 1);
2700
2701 ret = dpcm_fe_dai_startup(fe_substream);
2702 if (ret < 0) {
2703 /* clean up all links */
2704 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
2705 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2706
2707 dpcm_be_disconnect(fe, stream);
2708 fe->dpcm[stream].runtime = NULL;
2709 }
2710
2711 dpcm_clear_pending_state(fe, stream);
2712 dpcm_path_put(&list);
2713 mutex_unlock(&fe->card->mutex);
2714 return ret;
2715}
2716
Mark Brown45c0a182012-05-09 21:46:27 +01002717static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002718{
2719 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
2720 struct snd_soc_dpcm *dpcm;
2721 int stream = fe_substream->stream, ret;
2722
2723 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2724 ret = dpcm_fe_dai_shutdown(fe_substream);
2725
2726 /* mark FE's links ready to prune */
2727 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
2728 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2729
2730 dpcm_be_disconnect(fe, stream);
2731
2732 fe->dpcm[stream].runtime = NULL;
2733 mutex_unlock(&fe->card->mutex);
2734 return ret;
2735}
2736
Takashi Iwai5d61f0b2017-08-25 12:04:07 +02002737static void soc_pcm_private_free(struct snd_pcm *pcm)
2738{
2739 struct snd_soc_pcm_runtime *rtd = pcm->private_data;
Kuninori Morimotof523ace2017-09-26 01:00:53 +00002740 struct snd_soc_rtdcom_list *rtdcom;
2741 struct snd_soc_component *component;
Takashi Iwai5d61f0b2017-08-25 12:04:07 +02002742
Kuninori Morimotof30a4c32018-01-24 05:18:46 +00002743 /* need to sync the delayed work before releasing resources */
2744 flush_delayed_work(&rtd->delayed_work);
Kuninori Morimotof523ace2017-09-26 01:00:53 +00002745 for_each_rtdcom(rtd, rtdcom) {
Kuninori Morimotof523ace2017-09-26 01:00:53 +00002746 component = rtdcom->component;
2747
Kuninori Morimoto11fb14f2018-05-08 03:19:49 +00002748 if (component->driver->pcm_free)
2749 component->driver->pcm_free(pcm);
Kuninori Morimotof523ace2017-09-26 01:00:53 +00002750 }
Takashi Iwai5d61f0b2017-08-25 12:04:07 +02002751}
2752
Kuninori Morimotob8135862017-10-11 01:37:23 +00002753static int soc_rtdcom_ack(struct snd_pcm_substream *substream)
2754{
2755 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2756 struct snd_soc_rtdcom_list *rtdcom;
2757 struct snd_soc_component *component;
2758
2759 for_each_rtdcom(rtd, rtdcom) {
2760 component = rtdcom->component;
2761
2762 if (!component->driver->ops ||
2763 !component->driver->ops->ack)
2764 continue;
2765
2766 /* FIXME. it returns 1st ask now */
2767 return component->driver->ops->ack(substream);
2768 }
2769
2770 return -EINVAL;
2771}
2772
2773static int soc_rtdcom_copy_user(struct snd_pcm_substream *substream, int channel,
2774 unsigned long pos, void __user *buf,
2775 unsigned long bytes)
2776{
2777 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2778 struct snd_soc_rtdcom_list *rtdcom;
2779 struct snd_soc_component *component;
2780
2781 for_each_rtdcom(rtd, rtdcom) {
2782 component = rtdcom->component;
2783
2784 if (!component->driver->ops ||
2785 !component->driver->ops->copy_user)
2786 continue;
2787
2788 /* FIXME. it returns 1st copy now */
2789 return component->driver->ops->copy_user(substream, channel,
2790 pos, buf, bytes);
2791 }
2792
2793 return -EINVAL;
2794}
2795
2796static int soc_rtdcom_copy_kernel(struct snd_pcm_substream *substream, int channel,
2797 unsigned long pos, void *buf, unsigned long bytes)
2798{
2799 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2800 struct snd_soc_rtdcom_list *rtdcom;
2801 struct snd_soc_component *component;
2802
2803 for_each_rtdcom(rtd, rtdcom) {
2804 component = rtdcom->component;
2805
2806 if (!component->driver->ops ||
2807 !component->driver->ops->copy_kernel)
2808 continue;
2809
2810 /* FIXME. it returns 1st copy now */
2811 return component->driver->ops->copy_kernel(substream, channel,
2812 pos, buf, bytes);
2813 }
2814
2815 return -EINVAL;
2816}
2817
2818static int soc_rtdcom_fill_silence(struct snd_pcm_substream *substream, int channel,
2819 unsigned long pos, unsigned long bytes)
2820{
2821 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2822 struct snd_soc_rtdcom_list *rtdcom;
2823 struct snd_soc_component *component;
2824
2825 for_each_rtdcom(rtd, rtdcom) {
2826 component = rtdcom->component;
2827
2828 if (!component->driver->ops ||
2829 !component->driver->ops->fill_silence)
2830 continue;
2831
2832 /* FIXME. it returns 1st silence now */
2833 return component->driver->ops->fill_silence(substream, channel,
2834 pos, bytes);
2835 }
2836
2837 return -EINVAL;
2838}
2839
2840static struct page *soc_rtdcom_page(struct snd_pcm_substream *substream,
2841 unsigned long offset)
2842{
2843 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2844 struct snd_soc_rtdcom_list *rtdcom;
2845 struct snd_soc_component *component;
2846 struct page *page;
2847
2848 for_each_rtdcom(rtd, rtdcom) {
2849 component = rtdcom->component;
2850
2851 if (!component->driver->ops ||
2852 !component->driver->ops->page)
2853 continue;
2854
2855 /* FIXME. it returns 1st page now */
2856 page = component->driver->ops->page(substream, offset);
2857 if (page)
2858 return page;
2859 }
2860
2861 return NULL;
2862}
2863
2864static int soc_rtdcom_mmap(struct snd_pcm_substream *substream,
2865 struct vm_area_struct *vma)
2866{
2867 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2868 struct snd_soc_rtdcom_list *rtdcom;
2869 struct snd_soc_component *component;
2870
2871 for_each_rtdcom(rtd, rtdcom) {
2872 component = rtdcom->component;
2873
2874 if (!component->driver->ops ||
2875 !component->driver->ops->mmap)
2876 continue;
2877
2878 /* FIXME. it returns 1st mmap now */
2879 return component->driver->ops->mmap(substream, vma);
2880 }
2881
2882 return -EINVAL;
2883}
2884
Liam Girdwoodddee6272011-06-09 14:45:53 +01002885/* create a new pcm */
2886int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
2887{
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002888 struct snd_soc_dai *codec_dai;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002889 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimotof523ace2017-09-26 01:00:53 +00002890 struct snd_soc_component *component;
2891 struct snd_soc_rtdcom_list *rtdcom;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002892 struct snd_pcm *pcm;
2893 char new_name[64];
2894 int ret = 0, playback = 0, capture = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002895 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002896
Liam Girdwood01d75842012-04-25 12:12:49 +01002897 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
Liam Girdwood1e9de422014-01-07 17:51:42 +00002898 playback = rtd->dai_link->dpcm_playback;
2899 capture = rtd->dai_link->dpcm_capture;
Liam Girdwood01d75842012-04-25 12:12:49 +01002900 } else {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002901 for (i = 0; i < rtd->num_codecs; i++) {
2902 codec_dai = rtd->codec_dais[i];
2903 if (codec_dai->driver->playback.channels_min)
2904 playback = 1;
2905 if (codec_dai->driver->capture.channels_min)
2906 capture = 1;
2907 }
2908
2909 capture = capture && cpu_dai->driver->capture.channels_min;
2910 playback = playback && cpu_dai->driver->playback.channels_min;
Liam Girdwood01d75842012-04-25 12:12:49 +01002911 }
Sangsu Parka5002312012-01-02 17:15:10 +09002912
Fabio Estevamd6bead02013-08-29 10:32:13 -03002913 if (rtd->dai_link->playback_only) {
2914 playback = 1;
2915 capture = 0;
2916 }
2917
2918 if (rtd->dai_link->capture_only) {
2919 playback = 0;
2920 capture = 1;
2921 }
2922
Liam Girdwood01d75842012-04-25 12:12:49 +01002923 /* create the PCM */
2924 if (rtd->dai_link->no_pcm) {
2925 snprintf(new_name, sizeof(new_name), "(%s)",
2926 rtd->dai_link->stream_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002927
Liam Girdwood01d75842012-04-25 12:12:49 +01002928 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
2929 playback, capture, &pcm);
2930 } else {
2931 if (rtd->dai_link->dynamic)
2932 snprintf(new_name, sizeof(new_name), "%s (*)",
2933 rtd->dai_link->stream_name);
2934 else
2935 snprintf(new_name, sizeof(new_name), "%s %s-%d",
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002936 rtd->dai_link->stream_name,
2937 (rtd->num_codecs > 1) ?
2938 "multicodec" : rtd->codec_dai->name, num);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002939
Liam Girdwood01d75842012-04-25 12:12:49 +01002940 ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
2941 capture, &pcm);
2942 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01002943 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002944 dev_err(rtd->card->dev, "ASoC: can't create pcm for %s\n",
Liam Girdwood5cb9b742012-07-06 16:54:52 +01002945 rtd->dai_link->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002946 return ret;
2947 }
Liam Girdwood103d84a2012-11-19 14:39:15 +00002948 dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01002949
2950 /* DAPM dai link stream work */
2951 INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
2952
Vinod Koul48c76992015-02-12 09:59:53 +05302953 pcm->nonatomic = rtd->dai_link->nonatomic;
Liam Girdwoodddee6272011-06-09 14:45:53 +01002954 rtd->pcm = pcm;
2955 pcm->private_data = rtd;
Liam Girdwood01d75842012-04-25 12:12:49 +01002956
2957 if (rtd->dai_link->no_pcm) {
2958 if (playback)
2959 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
2960 if (capture)
2961 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
2962 goto out;
2963 }
2964
2965 /* ASoC PCM operations */
2966 if (rtd->dai_link->dynamic) {
2967 rtd->ops.open = dpcm_fe_dai_open;
2968 rtd->ops.hw_params = dpcm_fe_dai_hw_params;
2969 rtd->ops.prepare = dpcm_fe_dai_prepare;
2970 rtd->ops.trigger = dpcm_fe_dai_trigger;
2971 rtd->ops.hw_free = dpcm_fe_dai_hw_free;
2972 rtd->ops.close = dpcm_fe_dai_close;
2973 rtd->ops.pointer = soc_pcm_pointer;
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01002974 rtd->ops.ioctl = soc_pcm_ioctl;
Liam Girdwood01d75842012-04-25 12:12:49 +01002975 } else {
2976 rtd->ops.open = soc_pcm_open;
2977 rtd->ops.hw_params = soc_pcm_hw_params;
2978 rtd->ops.prepare = soc_pcm_prepare;
2979 rtd->ops.trigger = soc_pcm_trigger;
2980 rtd->ops.hw_free = soc_pcm_hw_free;
2981 rtd->ops.close = soc_pcm_close;
2982 rtd->ops.pointer = soc_pcm_pointer;
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01002983 rtd->ops.ioctl = soc_pcm_ioctl;
Liam Girdwood01d75842012-04-25 12:12:49 +01002984 }
2985
Kuninori Morimotob8135862017-10-11 01:37:23 +00002986 for_each_rtdcom(rtd, rtdcom) {
2987 const struct snd_pcm_ops *ops = rtdcom->component->driver->ops;
2988
2989 if (!ops)
2990 continue;
2991
2992 if (ops->ack)
2993 rtd->ops.ack = soc_rtdcom_ack;
2994 if (ops->copy_user)
2995 rtd->ops.copy_user = soc_rtdcom_copy_user;
2996 if (ops->copy_kernel)
2997 rtd->ops.copy_kernel = soc_rtdcom_copy_kernel;
2998 if (ops->fill_silence)
2999 rtd->ops.fill_silence = soc_rtdcom_fill_silence;
3000 if (ops->page)
3001 rtd->ops.page = soc_rtdcom_page;
3002 if (ops->mmap)
3003 rtd->ops.mmap = soc_rtdcom_mmap;
3004 }
3005
Liam Girdwoodddee6272011-06-09 14:45:53 +01003006 if (playback)
Liam Girdwood01d75842012-04-25 12:12:49 +01003007 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003008
3009 if (capture)
Liam Girdwood01d75842012-04-25 12:12:49 +01003010 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003011
Kuninori Morimotof523ace2017-09-26 01:00:53 +00003012 for_each_rtdcom(rtd, rtdcom) {
3013 component = rtdcom->component;
3014
Kuninori Morimoto11fb14f2018-05-08 03:19:49 +00003015 if (!component->driver->pcm_new)
Kuninori Morimotof523ace2017-09-26 01:00:53 +00003016 continue;
3017
Kuninori Morimoto11fb14f2018-05-08 03:19:49 +00003018 ret = component->driver->pcm_new(rtd);
Johan Hovoldc641e5b2017-07-12 17:55:29 +02003019 if (ret < 0) {
Kuninori Morimotof523ace2017-09-26 01:00:53 +00003020 dev_err(component->dev,
Johan Hovoldc641e5b2017-07-12 17:55:29 +02003021 "ASoC: pcm constructor failed: %d\n",
3022 ret);
3023 return ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +01003024 }
3025 }
Johan Hovoldc641e5b2017-07-12 17:55:29 +02003026
Takashi Iwai5d61f0b2017-08-25 12:04:07 +02003027 pcm->private_free = soc_pcm_private_free;
Liam Girdwood01d75842012-04-25 12:12:49 +01003028out:
Benoit Cousson2e5894d2014-07-08 23:19:35 +02003029 dev_info(rtd->card->dev, "%s <-> %s mapping ok\n",
3030 (rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name,
3031 cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003032 return ret;
3033}
Liam Girdwood01d75842012-04-25 12:12:49 +01003034
3035/* is the current PCM operation for this FE ? */
3036int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream)
3037{
3038 if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE)
3039 return 1;
3040 return 0;
3041}
3042EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update);
3043
3044/* is the current PCM operation for this BE ? */
3045int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
3046 struct snd_soc_pcm_runtime *be, int stream)
3047{
3048 if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) ||
3049 ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) &&
3050 be->dpcm[stream].runtime_update))
3051 return 1;
3052 return 0;
3053}
3054EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update);
3055
3056/* get the substream for this BE */
3057struct snd_pcm_substream *
3058 snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream)
3059{
3060 return be->pcm->streams[stream].substream;
3061}
3062EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream);
3063
3064/* get the BE runtime state */
3065enum snd_soc_dpcm_state
3066 snd_soc_dpcm_be_get_state(struct snd_soc_pcm_runtime *be, int stream)
3067{
3068 return be->dpcm[stream].state;
3069}
3070EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_get_state);
3071
3072/* set the BE runtime state */
3073void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be,
3074 int stream, enum snd_soc_dpcm_state state)
3075{
3076 be->dpcm[stream].state = state;
3077}
3078EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_set_state);
3079
3080/*
3081 * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE
3082 * are not running, paused or suspended for the specified stream direction.
3083 */
3084int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
3085 struct snd_soc_pcm_runtime *be, int stream)
3086{
3087 struct snd_soc_dpcm *dpcm;
3088 int state;
3089
3090 list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {
3091
3092 if (dpcm->fe == fe)
3093 continue;
3094
3095 state = dpcm->fe->dpcm[stream].state;
3096 if (state == SND_SOC_DPCM_STATE_START ||
3097 state == SND_SOC_DPCM_STATE_PAUSED ||
3098 state == SND_SOC_DPCM_STATE_SUSPEND)
3099 return 0;
3100 }
3101
3102 /* it's safe to free/stop this BE DAI */
3103 return 1;
3104}
3105EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop);
3106
3107/*
3108 * We can only change hw params a BE DAI if any of it's FE are not prepared,
3109 * running, paused or suspended for the specified stream direction.
3110 */
3111int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
3112 struct snd_soc_pcm_runtime *be, int stream)
3113{
3114 struct snd_soc_dpcm *dpcm;
3115 int state;
3116
3117 list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {
3118
3119 if (dpcm->fe == fe)
3120 continue;
3121
3122 state = dpcm->fe->dpcm[stream].state;
3123 if (state == SND_SOC_DPCM_STATE_START ||
3124 state == SND_SOC_DPCM_STATE_PAUSED ||
3125 state == SND_SOC_DPCM_STATE_SUSPEND ||
3126 state == SND_SOC_DPCM_STATE_PREPARE)
3127 return 0;
3128 }
3129
3130 /* it's safe to change hw_params */
3131 return 1;
3132}
3133EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003134
3135#ifdef CONFIG_DEBUG_FS
Lars-Peter Clausen852801412016-11-22 11:29:14 +01003136static const char *dpcm_state_string(enum snd_soc_dpcm_state state)
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003137{
3138 switch (state) {
3139 case SND_SOC_DPCM_STATE_NEW:
3140 return "new";
3141 case SND_SOC_DPCM_STATE_OPEN:
3142 return "open";
3143 case SND_SOC_DPCM_STATE_HW_PARAMS:
3144 return "hw_params";
3145 case SND_SOC_DPCM_STATE_PREPARE:
3146 return "prepare";
3147 case SND_SOC_DPCM_STATE_START:
3148 return "start";
3149 case SND_SOC_DPCM_STATE_STOP:
3150 return "stop";
3151 case SND_SOC_DPCM_STATE_SUSPEND:
3152 return "suspend";
3153 case SND_SOC_DPCM_STATE_PAUSED:
3154 return "paused";
3155 case SND_SOC_DPCM_STATE_HW_FREE:
3156 return "hw_free";
3157 case SND_SOC_DPCM_STATE_CLOSE:
3158 return "close";
3159 }
3160
3161 return "unknown";
3162}
3163
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003164static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
3165 int stream, char *buf, size_t size)
3166{
3167 struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params;
3168 struct snd_soc_dpcm *dpcm;
3169 ssize_t offset = 0;
3170
3171 /* FE state */
3172 offset += snprintf(buf + offset, size - offset,
3173 "[%s - %s]\n", fe->dai_link->name,
3174 stream ? "Capture" : "Playback");
3175
3176 offset += snprintf(buf + offset, size - offset, "State: %s\n",
3177 dpcm_state_string(fe->dpcm[stream].state));
3178
3179 if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
3180 (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
3181 offset += snprintf(buf + offset, size - offset,
3182 "Hardware Params: "
3183 "Format = %s, Channels = %d, Rate = %d\n",
3184 snd_pcm_format_name(params_format(params)),
3185 params_channels(params),
3186 params_rate(params));
3187
3188 /* BEs state */
3189 offset += snprintf(buf + offset, size - offset, "Backends:\n");
3190
3191 if (list_empty(&fe->dpcm[stream].be_clients)) {
3192 offset += snprintf(buf + offset, size - offset,
3193 " No active DSP links\n");
3194 goto out;
3195 }
3196
3197 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
3198 struct snd_soc_pcm_runtime *be = dpcm->be;
3199 params = &dpcm->hw_params;
3200
3201 offset += snprintf(buf + offset, size - offset,
3202 "- %s\n", be->dai_link->name);
3203
3204 offset += snprintf(buf + offset, size - offset,
3205 " State: %s\n",
3206 dpcm_state_string(be->dpcm[stream].state));
3207
3208 if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
3209 (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
3210 offset += snprintf(buf + offset, size - offset,
3211 " Hardware Params: "
3212 "Format = %s, Channels = %d, Rate = %d\n",
3213 snd_pcm_format_name(params_format(params)),
3214 params_channels(params),
3215 params_rate(params));
3216 }
3217
3218out:
3219 return offset;
3220}
3221
3222static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf,
3223 size_t count, loff_t *ppos)
3224{
3225 struct snd_soc_pcm_runtime *fe = file->private_data;
3226 ssize_t out_count = PAGE_SIZE, offset = 0, ret = 0;
3227 char *buf;
3228
3229 buf = kmalloc(out_count, GFP_KERNEL);
3230 if (!buf)
3231 return -ENOMEM;
3232
3233 if (fe->cpu_dai->driver->playback.channels_min)
3234 offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_PLAYBACK,
3235 buf + offset, out_count - offset);
3236
3237 if (fe->cpu_dai->driver->capture.channels_min)
3238 offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_CAPTURE,
3239 buf + offset, out_count - offset);
3240
Liam Girdwoodf57b8482012-04-27 11:33:46 +01003241 ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003242
Liam Girdwoodf57b8482012-04-27 11:33:46 +01003243 kfree(buf);
3244 return ret;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003245}
3246
3247static const struct file_operations dpcm_state_fops = {
Liam Girdwoodf57b8482012-04-27 11:33:46 +01003248 .open = simple_open,
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003249 .read = dpcm_state_read_file,
3250 .llseek = default_llseek,
3251};
3252
Lars-Peter Clausen2e55b902015-04-09 10:52:37 +02003253void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003254{
Mark Brownb3bba9a2012-05-08 10:33:47 +01003255 if (!rtd->dai_link)
Lars-Peter Clausen2e55b902015-04-09 10:52:37 +02003256 return;
Mark Brownb3bba9a2012-05-08 10:33:47 +01003257
Lars-Peter Clausen6553bf062015-04-09 10:52:38 +02003258 if (!rtd->card->debugfs_card_root)
3259 return;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003260
3261 rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name,
3262 rtd->card->debugfs_card_root);
3263 if (!rtd->debugfs_dpcm_root) {
3264 dev_dbg(rtd->dev,
3265 "ASoC: Failed to create dpcm debugfs directory %s\n",
3266 rtd->dai_link->name);
Lars-Peter Clausen2e55b902015-04-09 10:52:37 +02003267 return;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003268 }
3269
Fabio Estevamf1e3f402017-07-29 11:40:55 -03003270 debugfs_create_file("state", 0444, rtd->debugfs_dpcm_root,
3271 rtd, &dpcm_state_fops);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003272}
3273#endif