blob: d444dba25cddce2ba62cb8697e6a8f63ba740e0f [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>
Banajit Goswami7ffe84e2017-01-10 17:28:14 -080028#include <linux/dma-mapping.h>
Liam Girdwoodddee6272011-06-09 14:45:53 +010029#include <sound/core.h>
30#include <sound/pcm.h>
31#include <sound/pcm_params.h>
32#include <sound/soc.h>
Liam Girdwood01d75842012-04-25 12:12:49 +010033#include <sound/soc-dpcm.h>
Liam Girdwoodddee6272011-06-09 14:45:53 +010034#include <sound/initval.h>
35
Liam Girdwood01d75842012-04-25 12:12:49 +010036#define DPCM_MAX_BE_USERS 8
37
Ricard Wanderlofcde79032015-08-24 14:16:51 +020038/*
Liam Girdwoodf5b50e72017-01-10 17:10:17 -080039 * ASoC no host IO hardware.
40 * TODO: fine tune these values for all host less transfers.
41 */
42static const struct snd_pcm_hardware no_host_hardware = {
43 .info = SNDRV_PCM_INFO_MMAP |
44 SNDRV_PCM_INFO_MMAP_VALID |
45 SNDRV_PCM_INFO_INTERLEAVED |
46 SNDRV_PCM_INFO_PAUSE |
47 SNDRV_PCM_INFO_RESUME,
48 .formats = SNDRV_PCM_FMTBIT_S16_LE |
49 SNDRV_PCM_FMTBIT_S32_LE,
50 .period_bytes_min = PAGE_SIZE >> 2,
51 .period_bytes_max = PAGE_SIZE >> 1,
52 .periods_min = 2,
53 .periods_max = 4,
Banajit Goswami7ffe84e2017-01-10 17:28:14 -080054 /*
55 * Increase the max buffer bytes as PAGE_SIZE bytes is
56 * not enough to encompass all the scenarios sent by
57 * userspapce.
58 */
59 .buffer_bytes_max = PAGE_SIZE * 4,
Liam Girdwoodf5b50e72017-01-10 17:10:17 -080060};
61
62/*
Ricard Wanderlofcde79032015-08-24 14:16:51 +020063 * snd_soc_dai_stream_valid() - check if a DAI supports the given stream
64 *
65 * Returns true if the DAI supports the indicated stream type.
66 */
67static bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream)
68{
69 struct snd_soc_pcm_stream *codec_stream;
70
71 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
72 codec_stream = &dai->driver->playback;
73 else
74 codec_stream = &dai->driver->capture;
75
Jerome Brunet1ff98902019-04-29 11:47:49 +020076 /* If the codec specifies any channels at all, it supports the stream */
77 return codec_stream->channels_min;
Ricard Wanderlofcde79032015-08-24 14:16:51 +020078}
79
Lars-Peter Clausen90996f42013-05-14 11:05:30 +020080/**
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010081 * snd_soc_runtime_activate() - Increment active count for PCM runtime components
82 * @rtd: ASoC PCM runtime that is activated
83 * @stream: Direction of the PCM stream
84 *
85 * Increments the active count for all the DAIs and components attached to a PCM
86 * runtime. Should typically be called when a stream is opened.
87 *
88 * Must be called with the rtd->pcm_mutex being held
89 */
90void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream)
91{
92 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +020093 int i;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010094
95 lockdep_assert_held(&rtd->pcm_mutex);
96
97 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
98 cpu_dai->playback_active++;
Benoit Cousson2e5894d2014-07-08 23:19:35 +020099 for (i = 0; i < rtd->num_codecs; i++)
100 rtd->codec_dais[i]->playback_active++;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100101 } else {
102 cpu_dai->capture_active++;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200103 for (i = 0; i < rtd->num_codecs; i++)
104 rtd->codec_dais[i]->capture_active++;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100105 }
106
107 cpu_dai->active++;
Lars-Peter Clausencdde4cc2014-03-05 13:17:47 +0100108 cpu_dai->component->active++;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200109 for (i = 0; i < rtd->num_codecs; i++) {
110 rtd->codec_dais[i]->active++;
111 rtd->codec_dais[i]->component->active++;
112 }
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100113}
114
115/**
116 * snd_soc_runtime_deactivate() - Decrement active count for PCM runtime components
117 * @rtd: ASoC PCM runtime that is deactivated
118 * @stream: Direction of the PCM stream
119 *
120 * Decrements the active count for all the DAIs and components attached to a PCM
121 * runtime. Should typically be called when a stream is closed.
122 *
123 * Must be called with the rtd->pcm_mutex being held
124 */
125void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream)
126{
127 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200128 int i;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100129
130 lockdep_assert_held(&rtd->pcm_mutex);
131
132 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
133 cpu_dai->playback_active--;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200134 for (i = 0; i < rtd->num_codecs; i++)
135 rtd->codec_dais[i]->playback_active--;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100136 } else {
137 cpu_dai->capture_active--;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200138 for (i = 0; i < rtd->num_codecs; i++)
139 rtd->codec_dais[i]->capture_active--;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100140 }
141
142 cpu_dai->active--;
Lars-Peter Clausencdde4cc2014-03-05 13:17:47 +0100143 cpu_dai->component->active--;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200144 for (i = 0; i < rtd->num_codecs; i++) {
145 rtd->codec_dais[i]->component->active--;
146 rtd->codec_dais[i]->active--;
147 }
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100148}
149
150/**
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100151 * snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay
152 * @rtd: The ASoC PCM runtime that should be checked.
153 *
154 * This function checks whether the power down delay should be ignored for a
155 * specific PCM runtime. Returns true if the delay is 0, if it the DAI link has
156 * been configured to ignore the delay, or if none of the components benefits
157 * from having the delay.
158 */
159bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
160{
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200161 int i;
162 bool ignore = true;
163
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100164 if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
165 return true;
166
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200167 for (i = 0; i < rtd->num_codecs; i++)
168 ignore &= rtd->codec_dais[i]->component->ignore_pmdown_time;
169
170 return rtd->cpu_dai->component->ignore_pmdown_time && ignore;
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100171}
172
173/**
Lars-Peter Clausen90996f42013-05-14 11:05:30 +0200174 * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
175 * @substream: the pcm substream
176 * @hw: the hardware parameters
177 *
178 * Sets the substream runtime hardware parameters.
179 */
180int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
181 const struct snd_pcm_hardware *hw)
182{
183 struct snd_pcm_runtime *runtime = substream->runtime;
Banajit Goswami7ffe84e2017-01-10 17:28:14 -0800184 if (!runtime)
185 return 0;
Lars-Peter Clausen90996f42013-05-14 11:05:30 +0200186 runtime->hw.info = hw->info;
187 runtime->hw.formats = hw->formats;
188 runtime->hw.period_bytes_min = hw->period_bytes_min;
189 runtime->hw.period_bytes_max = hw->period_bytes_max;
190 runtime->hw.periods_min = hw->periods_min;
191 runtime->hw.periods_max = hw->periods_max;
192 runtime->hw.buffer_bytes_max = hw->buffer_bytes_max;
193 runtime->hw.fifo_size = hw->fifo_size;
194 return 0;
195}
196EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
197
Liam Girdwood01d75842012-04-25 12:12:49 +0100198/* DPCM stream event, send event to FE and all active BEs. */
Liam Girdwood23607022014-01-17 17:03:55 +0000199int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
Liam Girdwood01d75842012-04-25 12:12:49 +0100200 int event)
201{
202 struct snd_soc_dpcm *dpcm;
203
204 list_for_each_entry(dpcm, &fe->dpcm[dir].be_clients, list_be) {
205
206 struct snd_soc_pcm_runtime *be = dpcm->be;
207
Liam Girdwood103d84a2012-11-19 14:39:15 +0000208 dev_dbg(be->dev, "ASoC: BE %s event %d dir %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +0100209 be->dai_link->name, event, dir);
Banajit Goswamia5945772014-08-20 18:23:46 -0700210 if ((event == SND_SOC_DAPM_STREAM_STOP) &&
211 (be->dpcm[dir].users >= 1)) {
212 pr_debug("%s Don't close BE\n", __func__);
213 continue;
214 }
Banajit Goswami650c7632017-07-14 23:15:05 -0700215
Liam Girdwood01d75842012-04-25 12:12:49 +0100216 snd_soc_dapm_stream_event(be, dir, event);
217 }
218
219 snd_soc_dapm_stream_event(fe, dir, event);
220
221 return 0;
222}
223
Dong Aisheng17841022011-08-29 17:15:14 +0800224static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
225 struct snd_soc_dai *soc_dai)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100226{
227 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100228 int ret;
229
Nicolin Chen3635bf02013-11-13 18:56:24 +0800230 if (soc_dai->rate && (soc_dai->driver->symmetric_rates ||
231 rtd->dai_link->symmetric_rates)) {
232 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n",
233 soc_dai->rate);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100234
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200235 ret = snd_pcm_hw_constraint_single(substream->runtime,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800236 SNDRV_PCM_HW_PARAM_RATE,
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200237 soc_dai->rate);
Nicolin Chen3635bf02013-11-13 18:56:24 +0800238 if (ret < 0) {
239 dev_err(soc_dai->dev,
240 "ASoC: Unable to apply rate constraint: %d\n",
241 ret);
242 return ret;
243 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100244 }
245
Nicolin Chen3635bf02013-11-13 18:56:24 +0800246 if (soc_dai->channels && (soc_dai->driver->symmetric_channels ||
247 rtd->dai_link->symmetric_channels)) {
248 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d channel(s)\n",
249 soc_dai->channels);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100250
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200251 ret = snd_pcm_hw_constraint_single(substream->runtime,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800252 SNDRV_PCM_HW_PARAM_CHANNELS,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800253 soc_dai->channels);
254 if (ret < 0) {
255 dev_err(soc_dai->dev,
256 "ASoC: Unable to apply channel symmetry constraint: %d\n",
257 ret);
258 return ret;
259 }
260 }
261
262 if (soc_dai->sample_bits && (soc_dai->driver->symmetric_samplebits ||
263 rtd->dai_link->symmetric_samplebits)) {
264 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d sample bits\n",
265 soc_dai->sample_bits);
266
Lars-Peter Clausen4dcdd432015-10-18 15:39:28 +0200267 ret = snd_pcm_hw_constraint_single(substream->runtime,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800268 SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
Nicolin Chen3635bf02013-11-13 18:56:24 +0800269 soc_dai->sample_bits);
270 if (ret < 0) {
271 dev_err(soc_dai->dev,
272 "ASoC: Unable to apply sample bits symmetry constraint: %d\n",
273 ret);
274 return ret;
275 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100276 }
277
278 return 0;
279}
280
Nicolin Chen3635bf02013-11-13 18:56:24 +0800281static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
282 struct snd_pcm_hw_params *params)
283{
284 struct snd_soc_pcm_runtime *rtd = substream->private_data;
285 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200286 unsigned int rate, channels, sample_bits, symmetry, i;
Nicolin Chen3635bf02013-11-13 18:56:24 +0800287
288 rate = params_rate(params);
289 channels = params_channels(params);
290 sample_bits = snd_pcm_format_physical_width(params_format(params));
291
292 /* reject unmatched parameters when applying symmetry */
293 symmetry = cpu_dai->driver->symmetric_rates ||
Nicolin Chen3635bf02013-11-13 18:56:24 +0800294 rtd->dai_link->symmetric_rates;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200295
296 for (i = 0; i < rtd->num_codecs; i++)
297 symmetry |= rtd->codec_dais[i]->driver->symmetric_rates;
298
Nicolin Chen3635bf02013-11-13 18:56:24 +0800299 if (symmetry && cpu_dai->rate && cpu_dai->rate != rate) {
300 dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n",
301 cpu_dai->rate, rate);
302 return -EINVAL;
303 }
304
305 symmetry = cpu_dai->driver->symmetric_channels ||
Nicolin Chen3635bf02013-11-13 18:56:24 +0800306 rtd->dai_link->symmetric_channels;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200307
308 for (i = 0; i < rtd->num_codecs; i++)
309 symmetry |= rtd->codec_dais[i]->driver->symmetric_channels;
310
Nicolin Chen3635bf02013-11-13 18:56:24 +0800311 if (symmetry && cpu_dai->channels && cpu_dai->channels != channels) {
312 dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n",
313 cpu_dai->channels, channels);
314 return -EINVAL;
315 }
316
317 symmetry = cpu_dai->driver->symmetric_samplebits ||
Nicolin Chen3635bf02013-11-13 18:56:24 +0800318 rtd->dai_link->symmetric_samplebits;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200319
320 for (i = 0; i < rtd->num_codecs; i++)
321 symmetry |= rtd->codec_dais[i]->driver->symmetric_samplebits;
322
Nicolin Chen3635bf02013-11-13 18:56:24 +0800323 if (symmetry && cpu_dai->sample_bits && cpu_dai->sample_bits != sample_bits) {
324 dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n",
325 cpu_dai->sample_bits, sample_bits);
326 return -EINVAL;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100327 }
328
329 return 0;
330}
331
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100332static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream)
333{
334 struct snd_soc_pcm_runtime *rtd = substream->private_data;
335 struct snd_soc_dai_driver *cpu_driver = rtd->cpu_dai->driver;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100336 struct snd_soc_dai_link *link = rtd->dai_link;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200337 unsigned int symmetry, i;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100338
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200339 symmetry = cpu_driver->symmetric_rates || link->symmetric_rates ||
340 cpu_driver->symmetric_channels || link->symmetric_channels ||
341 cpu_driver->symmetric_samplebits || link->symmetric_samplebits;
342
343 for (i = 0; i < rtd->num_codecs; i++)
344 symmetry = symmetry ||
345 rtd->codec_dais[i]->driver->symmetric_rates ||
346 rtd->codec_dais[i]->driver->symmetric_channels ||
347 rtd->codec_dais[i]->driver->symmetric_samplebits;
348
349 return symmetry;
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100350}
351
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200352static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits)
Mark Brown58ba9b22012-01-16 18:38:51 +0000353{
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200354 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Takashi Iwaic6068d32014-12-31 17:10:34 +0100355 int ret;
Mark Brown58ba9b22012-01-16 18:38:51 +0000356
357 if (!bits)
358 return;
359
Lars-Peter Clausen0e2a3752014-12-29 18:43:38 +0100360 ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 0, bits);
361 if (ret != 0)
362 dev_warn(rtd->dev, "ASoC: Failed to set MSB %d: %d\n",
363 bits, ret);
Mark Brown58ba9b22012-01-16 18:38:51 +0000364}
365
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200366static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200367{
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200368 struct snd_soc_pcm_runtime *rtd = substream->private_data;
369 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200370 struct snd_soc_dai *codec_dai;
371 int i;
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200372 unsigned int bits = 0, cpu_bits;
373
374 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200375 for (i = 0; i < rtd->num_codecs; i++) {
376 codec_dai = rtd->codec_dais[i];
377 if (codec_dai->driver->playback.sig_bits == 0) {
378 bits = 0;
379 break;
380 }
381 bits = max(codec_dai->driver->playback.sig_bits, bits);
382 }
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200383 cpu_bits = cpu_dai->driver->playback.sig_bits;
384 } else {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200385 for (i = 0; i < rtd->num_codecs; i++) {
386 codec_dai = rtd->codec_dais[i];
Daniel Mack5e63dfc2014-10-07 14:33:46 +0200387 if (codec_dai->driver->capture.sig_bits == 0) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200388 bits = 0;
389 break;
390 }
391 bits = max(codec_dai->driver->capture.sig_bits, bits);
392 }
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200393 cpu_bits = cpu_dai->driver->capture.sig_bits;
394 }
395
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200396 soc_pcm_set_msb(substream, bits);
397 soc_pcm_set_msb(substream, cpu_bits);
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200398}
399
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200400static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200401{
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200402 struct snd_pcm_runtime *runtime = substream->runtime;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100403 struct snd_pcm_hardware *hw = &runtime->hw;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200404 struct snd_soc_pcm_runtime *rtd = substream->private_data;
405 struct snd_soc_dai_driver *cpu_dai_drv = rtd->cpu_dai->driver;
406 struct snd_soc_dai_driver *codec_dai_drv;
407 struct snd_soc_pcm_stream *codec_stream;
408 struct snd_soc_pcm_stream *cpu_stream;
409 unsigned int chan_min = 0, chan_max = UINT_MAX;
410 unsigned int rate_min = 0, rate_max = UINT_MAX;
411 unsigned int rates = UINT_MAX;
412 u64 formats = ULLONG_MAX;
413 int i;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100414
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200415 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
416 cpu_stream = &cpu_dai_drv->playback;
Lars-Peter Clausen16d7ea92014-01-06 14:19:16 +0100417 else
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200418 cpu_stream = &cpu_dai_drv->capture;
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100419
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200420 /* first calculate min/max only for CODECs in the DAI link */
421 for (i = 0; i < rtd->num_codecs; i++) {
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200422
423 /*
424 * Skip CODECs which don't support the current stream type.
425 * Otherwise, since the rate, channel, and format values will
426 * zero in that case, we would have no usable settings left,
427 * causing the resulting setup to fail.
428 * At least one CODEC should match, otherwise we should have
429 * bailed out on a higher level, since there would be no
430 * CODEC to support the transfer direction in that case.
431 */
432 if (!snd_soc_dai_stream_valid(rtd->codec_dais[i],
433 substream->stream))
434 continue;
435
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200436 codec_dai_drv = rtd->codec_dais[i]->driver;
437 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
438 codec_stream = &codec_dai_drv->playback;
439 else
440 codec_stream = &codec_dai_drv->capture;
441 chan_min = max(chan_min, codec_stream->channels_min);
442 chan_max = min(chan_max, codec_stream->channels_max);
443 rate_min = max(rate_min, codec_stream->rate_min);
444 rate_max = min_not_zero(rate_max, codec_stream->rate_max);
445 formats &= codec_stream->formats;
446 rates = snd_pcm_rate_mask_intersect(codec_stream->rates, rates);
447 }
448
449 /*
450 * chan min/max cannot be enforced if there are multiple CODEC DAIs
451 * connected to a single CPU DAI, use CPU DAI's directly and let
452 * channel allocation be fixed up later
453 */
454 if (rtd->num_codecs > 1) {
455 chan_min = cpu_stream->channels_min;
456 chan_max = cpu_stream->channels_max;
457 }
458
459 hw->channels_min = max(chan_min, cpu_stream->channels_min);
460 hw->channels_max = min(chan_max, cpu_stream->channels_max);
461 if (hw->formats)
462 hw->formats &= formats & cpu_stream->formats;
463 else
464 hw->formats = formats & cpu_stream->formats;
465 hw->rates = snd_pcm_rate_mask_intersect(rates, cpu_stream->rates);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100466
467 snd_pcm_limit_hw_rates(runtime);
468
469 hw->rate_min = max(hw->rate_min, cpu_stream->rate_min);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200470 hw->rate_min = max(hw->rate_min, rate_min);
Lars-Peter Clausen78e45c92013-11-27 09:58:18 +0100471 hw->rate_max = min_not_zero(hw->rate_max, cpu_stream->rate_max);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200472 hw->rate_max = min_not_zero(hw->rate_max, rate_max);
Lars-Peter Clausenbd477c32013-05-14 11:05:31 +0200473}
474
Mark Brown58ba9b22012-01-16 18:38:51 +0000475/*
Liam Girdwoodddee6272011-06-09 14:45:53 +0100476 * Called by ALSA when a PCM substream is opened, the runtime->hw record is
477 * then initialized and any private data can be allocated. This also calls
478 * startup for the cpu DAI, platform, machine and codec DAI.
479 */
480static int soc_pcm_open(struct snd_pcm_substream *substream)
481{
482 struct snd_soc_pcm_runtime *rtd = substream->private_data;
483 struct snd_pcm_runtime *runtime = substream->runtime;
484 struct snd_soc_platform *platform = rtd->platform;
485 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200486 struct snd_soc_dai *codec_dai;
487 const char *codec_dai_name = "multicodec";
488 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100489
Nicolin Chen988e8cc2013-11-04 14:57:31 +0800490 pinctrl_pm_select_default_state(cpu_dai->dev);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200491 for (i = 0; i < rtd->num_codecs; i++)
492 pinctrl_pm_select_default_state(rtd->codec_dais[i]->dev);
Mark Brownd6652ef2011-12-03 20:14:31 +0000493 pm_runtime_get_sync(cpu_dai->dev);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200494 for (i = 0; i < rtd->num_codecs; i++)
495 pm_runtime_get_sync(rtd->codec_dais[i]->dev);
Mark Brownd6652ef2011-12-03 20:14:31 +0000496 pm_runtime_get_sync(platform->dev);
497
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100498 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100499
Liam Girdwoodf5b50e72017-01-10 17:10:17 -0800500 if (rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST)
501 snd_soc_set_runtime_hwparams(substream, &no_host_hardware);
502
Liam Girdwoodddee6272011-06-09 14:45:53 +0100503 /* startup the audio subsystem */
Mark Brownc5914b02013-10-30 17:47:39 -0700504 if (cpu_dai->driver->ops && cpu_dai->driver->ops->startup) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100505 ret = cpu_dai->driver->ops->startup(substream, cpu_dai);
506 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000507 dev_err(cpu_dai->dev, "ASoC: can't open interface"
508 " %s: %d\n", cpu_dai->name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100509 goto out;
510 }
511 }
512
513 if (platform->driver->ops && platform->driver->ops->open) {
514 ret = platform->driver->ops->open(substream);
515 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000516 dev_err(platform->dev, "ASoC: can't open platform"
Lars-Peter Clausenf4333202014-06-16 18:13:02 +0200517 " %s: %d\n", platform->component.name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100518 goto platform_err;
519 }
520 }
521
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200522 for (i = 0; i < rtd->num_codecs; i++) {
523 codec_dai = rtd->codec_dais[i];
524 if (codec_dai->driver->ops && codec_dai->driver->ops->startup) {
525 ret = codec_dai->driver->ops->startup(substream,
526 codec_dai);
527 if (ret < 0) {
528 dev_err(codec_dai->dev,
529 "ASoC: can't open codec %s: %d\n",
530 codec_dai->name, ret);
531 goto codec_dai_err;
532 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100533 }
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200534
535 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
536 codec_dai->tx_mask = 0;
537 else
538 codec_dai->rx_mask = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100539 }
540
541 if (rtd->dai_link->ops && rtd->dai_link->ops->startup) {
542 ret = rtd->dai_link->ops->startup(substream);
543 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000544 pr_err("ASoC: %s startup failed: %d\n",
Mark Brown25bfe662012-02-01 21:30:32 +0000545 rtd->dai_link->name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100546 goto machine_err;
547 }
548 }
549
Liam Girdwood01d75842012-04-25 12:12:49 +0100550 /* Dynamic PCM DAI links compat checks use dynamic capabilities */
551 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm)
552 goto dynamic;
553
Liam Girdwoodddee6272011-06-09 14:45:53 +0100554 /* Check that the codec and cpu DAIs are compatible */
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200555 soc_pcm_init_runtime_hw(substream);
556
557 if (rtd->num_codecs == 1)
558 codec_dai_name = rtd->codec_dai->name;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100559
Lars-Peter Clausen62e5f672013-11-30 17:38:58 +0100560 if (soc_pcm_has_symmetry(substream))
561 runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
562
Liam Girdwoodddee6272011-06-09 14:45:53 +0100563 ret = -EINVAL;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100564 if (!runtime->hw.rates) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000565 printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200566 codec_dai_name, cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100567 goto config_err;
568 }
569 if (!runtime->hw.formats) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000570 printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200571 codec_dai_name, cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100572 goto config_err;
573 }
574 if (!runtime->hw.channels_min || !runtime->hw.channels_max ||
575 runtime->hw.channels_min > runtime->hw.channels_max) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000576 printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200577 codec_dai_name, cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100578 goto config_err;
579 }
580
Benoit Coussonc8dd1fe2014-07-01 09:47:55 +0200581 soc_pcm_apply_msb(substream);
Mark Brown58ba9b22012-01-16 18:38:51 +0000582
Liam Girdwoodddee6272011-06-09 14:45:53 +0100583 /* Symmetry only applies if we've already got an active stream. */
Dong Aisheng17841022011-08-29 17:15:14 +0800584 if (cpu_dai->active) {
585 ret = soc_pcm_apply_symmetry(substream, cpu_dai);
586 if (ret != 0)
587 goto config_err;
588 }
589
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200590 for (i = 0; i < rtd->num_codecs; i++) {
591 if (rtd->codec_dais[i]->active) {
592 ret = soc_pcm_apply_symmetry(substream,
593 rtd->codec_dais[i]);
594 if (ret != 0)
595 goto config_err;
596 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100597 }
598
Liam Girdwood103d84a2012-11-19 14:39:15 +0000599 pr_debug("ASoC: %s <-> %s info:\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200600 codec_dai_name, cpu_dai->name);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000601 pr_debug("ASoC: rate mask 0x%x\n", runtime->hw.rates);
602 pr_debug("ASoC: min ch %d max ch %d\n", runtime->hw.channels_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100603 runtime->hw.channels_max);
Liam Girdwood103d84a2012-11-19 14:39:15 +0000604 pr_debug("ASoC: min rate %d max rate %d\n", runtime->hw.rate_min,
Liam Girdwoodddee6272011-06-09 14:45:53 +0100605 runtime->hw.rate_max);
606
Liam Girdwood01d75842012-04-25 12:12:49 +0100607dynamic:
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100608
609 snd_soc_runtime_activate(rtd, substream->stream);
610
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100611 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100612 return 0;
613
614config_err:
615 if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
616 rtd->dai_link->ops->shutdown(substream);
617
618machine_err:
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200619 i = rtd->num_codecs;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100620
621codec_dai_err:
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200622 while (--i >= 0) {
623 codec_dai = rtd->codec_dais[i];
624 if (codec_dai->driver->ops->shutdown)
625 codec_dai->driver->ops->shutdown(substream, codec_dai);
626 }
627
Liam Girdwoodddee6272011-06-09 14:45:53 +0100628 if (platform->driver->ops && platform->driver->ops->close)
629 platform->driver->ops->close(substream);
630
631platform_err:
Viraja Kommarajuffbda0f2016-01-21 17:32:01 +0530632 if (cpu_dai->driver->ops && cpu_dai->driver->ops->shutdown)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100633 cpu_dai->driver->ops->shutdown(substream, cpu_dai);
634out:
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100635 mutex_unlock(&rtd->pcm_mutex);
Mark Brownd6652ef2011-12-03 20:14:31 +0000636
Sanyog Kale3f809782016-01-05 17:14:49 +0530637 pm_runtime_mark_last_busy(platform->dev);
638 pm_runtime_put_autosuspend(platform->dev);
639 for (i = 0; i < rtd->num_codecs; i++) {
640 pm_runtime_mark_last_busy(rtd->codec_dais[i]->dev);
641 pm_runtime_put_autosuspend(rtd->codec_dais[i]->dev);
642 }
643
644 pm_runtime_mark_last_busy(cpu_dai->dev);
645 pm_runtime_put_autosuspend(cpu_dai->dev);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200646 for (i = 0; i < rtd->num_codecs; i++) {
647 if (!rtd->codec_dais[i]->active)
648 pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev);
649 }
Nicolin Chen988e8cc2013-11-04 14:57:31 +0800650 if (!cpu_dai->active)
651 pinctrl_pm_select_sleep_state(cpu_dai->dev);
Mark Brownd6652ef2011-12-03 20:14:31 +0000652
Liam Girdwoodddee6272011-06-09 14:45:53 +0100653 return ret;
654}
655
656/*
657 * Power down the audio subsystem pmdown_time msecs after close is called.
658 * This is to ensure there are no pops or clicks in between any music tracks
659 * due to DAPM power cycling.
660 */
661static void close_delayed_work(struct work_struct *work)
662{
663 struct snd_soc_pcm_runtime *rtd =
664 container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200665 struct snd_soc_dai *codec_dai = rtd->codec_dais[0];
Liam Girdwoodddee6272011-06-09 14:45:53 +0100666
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100667 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100668
Liam Girdwood103d84a2012-11-19 14:39:15 +0000669 dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n",
Liam Girdwoodddee6272011-06-09 14:45:53 +0100670 codec_dai->driver->playback.stream_name,
671 codec_dai->playback_active ? "active" : "inactive",
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600672 rtd->pop_wait ? "yes" : "no");
Liam Girdwoodddee6272011-06-09 14:45:53 +0100673
674 /* are we waiting on this codec DAI stream */
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600675 if (rtd->pop_wait == 1) {
676 rtd->pop_wait = 0;
Mark Brown7bd3a6f2012-02-16 15:03:27 -0800677 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000678 SND_SOC_DAPM_STREAM_STOP);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100679 }
680
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100681 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100682}
683
684/*
685 * Called by ALSA when a PCM substream is closed. Private data can be
686 * freed here. The cpu DAI, codec DAI, machine and platform are also
687 * shutdown.
688 */
Liam Girdwood91d5e6b2011-06-09 17:04:59 +0100689static int soc_pcm_close(struct snd_pcm_substream *substream)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100690{
691 struct snd_soc_pcm_runtime *rtd = substream->private_data;
692 struct snd_soc_platform *platform = rtd->platform;
693 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200694 struct snd_soc_dai *codec_dai;
695 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100696
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100697 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100698
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100699 snd_soc_runtime_deactivate(rtd, substream->stream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100700
Dong Aisheng17841022011-08-29 17:15:14 +0800701 /* clear the corresponding DAIs rate when inactive */
702 if (!cpu_dai->active)
703 cpu_dai->rate = 0;
704
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200705 for (i = 0; i < rtd->num_codecs; i++) {
706 codec_dai = rtd->codec_dais[i];
707 if (!codec_dai->active)
708 codec_dai->rate = 0;
709 }
Sascha Hauer25b76792011-08-17 09:20:01 +0200710
Ramesh Babuae116012014-10-15 12:34:59 +0530711 snd_soc_dai_digital_mute(cpu_dai, 1, substream->stream);
712
Phani Kumar Uppalapati151230e2015-06-09 00:41:11 -0700713 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
714 if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
715 /* powered down playback stream now */
716 snd_soc_dapm_stream_event(rtd,
717 SNDRV_PCM_STREAM_PLAYBACK,
718 SND_SOC_DAPM_STREAM_STOP);
719 } else {
720 /* start delayed pop wq here for playback streams */
721 rtd->pop_wait = 1;
722 queue_delayed_work(system_power_efficient_wq,
723 &rtd->delayed_work,
724 msecs_to_jiffies(rtd->pmdown_time));
725 }
726 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100727 if (cpu_dai->driver->ops->shutdown)
728 cpu_dai->driver->ops->shutdown(substream, cpu_dai);
729
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200730 for (i = 0; i < rtd->num_codecs; i++) {
731 codec_dai = rtd->codec_dais[i];
732 if (codec_dai->driver->ops->shutdown)
733 codec_dai->driver->ops->shutdown(substream, codec_dai);
734 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100735
736 if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
737 rtd->dai_link->ops->shutdown(substream);
738
739 if (platform->driver->ops && platform->driver->ops->close)
740 platform->driver->ops->close(substream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100741
Phani Kumar Uppalapati151230e2015-06-09 00:41:11 -0700742 if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100743 /* capture streams can be powered down now */
Mark Brown7bd3a6f2012-02-16 15:03:27 -0800744 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
Liam Girdwoodd9b09512012-03-07 16:32:59 +0000745 SND_SOC_DAPM_STREAM_STOP);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100746 }
747
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100748 mutex_unlock(&rtd->pcm_mutex);
Mark Brownd6652ef2011-12-03 20:14:31 +0000749
Sanyog Kale3f809782016-01-05 17:14:49 +0530750 pm_runtime_mark_last_busy(platform->dev);
751 pm_runtime_put_autosuspend(platform->dev);
752
753 for (i = 0; i < rtd->num_codecs; i++) {
754 pm_runtime_mark_last_busy(rtd->codec_dais[i]->dev);
755 pm_runtime_put_autosuspend(rtd->codec_dais[i]->dev);
756 }
757
758 pm_runtime_mark_last_busy(cpu_dai->dev);
759 pm_runtime_put_autosuspend(cpu_dai->dev);
760
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200761 for (i = 0; i < rtd->num_codecs; i++) {
762 if (!rtd->codec_dais[i]->active)
763 pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev);
764 }
Nicolin Chen988e8cc2013-11-04 14:57:31 +0800765 if (!cpu_dai->active)
766 pinctrl_pm_select_sleep_state(cpu_dai->dev);
Mark Brownd6652ef2011-12-03 20:14:31 +0000767
Liam Girdwoodddee6272011-06-09 14:45:53 +0100768 return 0;
769}
770
771/*
772 * Called by ALSA when the PCM substream is prepared, can set format, sample
773 * rate, etc. This function is non atomic and can be called multiple times,
774 * it can refer to the runtime info.
775 */
776static int soc_pcm_prepare(struct snd_pcm_substream *substream)
777{
778 struct snd_soc_pcm_runtime *rtd = substream->private_data;
779 struct snd_soc_platform *platform = rtd->platform;
780 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
Sudheer Papothi70ef6c22016-01-29 06:21:36 +0530786 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
787 snd_soc_dapm_stream_event(rtd,
788 SNDRV_PCM_STREAM_PLAYBACK,
789 SND_SOC_DAPM_STREAM_START);
790
Liam Girdwoodddee6272011-06-09 14:45:53 +0100791 if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) {
792 ret = rtd->dai_link->ops->prepare(substream);
793 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000794 dev_err(rtd->card->dev, "ASoC: machine prepare error:"
795 " %d\n", ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100796 goto out;
797 }
798 }
799
800 if (platform->driver->ops && platform->driver->ops->prepare) {
801 ret = platform->driver->ops->prepare(substream);
802 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000803 dev_err(platform->dev, "ASoC: platform prepare error:"
804 " %d\n", ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100805 goto out;
806 }
807 }
808
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200809 for (i = 0; i < rtd->num_codecs; i++) {
810 codec_dai = rtd->codec_dais[i];
811 if (codec_dai->driver->ops && codec_dai->driver->ops->prepare) {
812 ret = codec_dai->driver->ops->prepare(substream,
813 codec_dai);
814 if (ret < 0) {
815 dev_err(codec_dai->dev,
Jarkko Nikula90cc7f12014-12-23 11:04:41 +0200816 "ASoC: codec DAI prepare error: %d\n",
817 ret);
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200818 goto out;
819 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100820 }
821 }
822
Mark Brownc5914b02013-10-30 17:47:39 -0700823 if (cpu_dai->driver->ops && cpu_dai->driver->ops->prepare) {
Liam Girdwoodddee6272011-06-09 14:45:53 +0100824 ret = cpu_dai->driver->ops->prepare(substream, cpu_dai);
825 if (ret < 0) {
Jarkko Nikula90cc7f12014-12-23 11:04:41 +0200826 dev_err(cpu_dai->dev,
827 "ASoC: cpu DAI prepare error: %d\n", ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100828 goto out;
829 }
830 }
831
832 /* cancel any delayed stream shutdown that is pending */
833 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600834 rtd->pop_wait) {
835 rtd->pop_wait = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100836 cancel_delayed_work(&rtd->delayed_work);
837 }
838
Sudheer Papothi70ef6c22016-01-29 06:21:36 +0530839 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
840 for (i = 0; i < rtd->num_codecs; i++) {
841 codec_dai = rtd->codec_dais[i];
842 if (codec_dai->capture_active == 1)
843 snd_soc_dapm_stream_event(rtd,
844 SNDRV_PCM_STREAM_CAPTURE,
845 SND_SOC_DAPM_STREAM_START);
846 }
847 }
Liam Girdwoodddee6272011-06-09 14:45:53 +0100848
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200849 for (i = 0; i < rtd->num_codecs; i++)
850 snd_soc_dai_digital_mute(rtd->codec_dais[i], 0,
851 substream->stream);
Ramesh Babuae116012014-10-15 12:34:59 +0530852 snd_soc_dai_digital_mute(cpu_dai, 0, substream->stream);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100853
854out:
Sudheer Papothi70ef6c22016-01-29 06:21:36 +0530855 if (ret < 0 && substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
856 pr_err("%s: Issue stop stream for codec_dai due to op failure %d = ret\n",
857 __func__, ret);
858 snd_soc_dapm_stream_event(rtd,
859 SNDRV_PCM_STREAM_PLAYBACK,
860 SND_SOC_DAPM_STREAM_STOP);
861 }
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100862 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100863 return ret;
864}
865
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200866static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params,
867 unsigned int mask)
868{
869 struct snd_interval *interval;
870 int channels = hweight_long(mask);
871
872 interval = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
873 interval->min = channels;
874 interval->max = channels;
875}
876
Benoit Cousson93e69582014-07-08 23:19:38 +0200877int soc_dai_hw_params(struct snd_pcm_substream *substream,
878 struct snd_pcm_hw_params *params,
879 struct snd_soc_dai *dai)
880{
881 int ret;
882
883 if (dai->driver->ops && dai->driver->ops->hw_params) {
884 ret = dai->driver->ops->hw_params(substream, params, dai);
885 if (ret < 0) {
886 dev_err(dai->dev, "ASoC: can't set %s hw params: %d\n",
887 dai->name, ret);
888 return ret;
889 }
890 }
891
892 return 0;
893}
894
Liam Girdwoodddee6272011-06-09 14:45:53 +0100895/*
896 * Called by ALSA when the hardware params are set by application. This
897 * function can also be called multiple times and can allocate buffers
898 * (using snd_pcm_lib_* ). It's non-atomic.
899 */
900static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
901 struct snd_pcm_hw_params *params)
902{
903 struct snd_soc_pcm_runtime *rtd = substream->private_data;
904 struct snd_soc_platform *platform = rtd->platform;
905 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200906 int i, ret = 0;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100907
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +0100908 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100909
Banajit Goswami7ffe84e2017-01-10 17:28:14 -0800910 /* perform any hw_params fixups */
911 if ((rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST) &&
912 rtd->dai_link->be_hw_params_fixup) {
913 ret = rtd->dai_link->be_hw_params_fixup(rtd,
914 params);
915 if (ret < 0)
916 dev_err(rtd->card->dev, "ASoC: fixup failed for %s\n",
917 rtd->dai_link->name);
918 }
919
Nicolin Chen3635bf02013-11-13 18:56:24 +0800920 ret = soc_pcm_params_symmetry(substream, params);
921 if (ret)
922 goto out;
923
Banajit Goswami7ffe84e2017-01-10 17:28:14 -0800924 /* perform any hw_params fixups */
925 if ((rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST) &&
926 rtd->dai_link->be_hw_params_fixup) {
927 ret = rtd->dai_link->be_hw_params_fixup(rtd,
928 params);
929 if (ret < 0) {
930 dev_err(rtd->card->dev, "ASoC: fixup failed for %s\n",
931 rtd->dai_link->name);
932 }
933 }
934
Liam Girdwoodddee6272011-06-09 14:45:53 +0100935 if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) {
936 ret = rtd->dai_link->ops->hw_params(substream, params);
937 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000938 dev_err(rtd->card->dev, "ASoC: machine hw_params"
939 " failed: %d\n", ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100940 goto out;
941 }
942 }
943
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200944 for (i = 0; i < rtd->num_codecs; i++) {
945 struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
946 struct snd_pcm_hw_params codec_params;
947
Ricard Wanderlofcde79032015-08-24 14:16:51 +0200948 /*
949 * Skip CODECs which don't support the current stream type,
950 * the idea being that if a CODEC is not used for the currently
951 * set up transfer direction, it should not need to be
952 * configured, especially since the configuration used might
953 * not even be supported by that CODEC. There may be cases
954 * however where a CODEC needs to be set up although it is
955 * actually not being used for the transfer, e.g. if a
956 * capture-only CODEC is acting as an LRCLK and/or BCLK master
957 * for the DAI link including a playback-only CODEC.
958 * If this becomes necessary, we will have to augment the
959 * machine driver setup with information on how to act, so
960 * we can do the right thing here.
961 */
962 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
963 continue;
964
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200965 /* copy params for each codec */
966 codec_params = *params;
967
968 /* fixup params based on TDM slot masks */
Rander Wang24428f82019-03-08 16:38:57 +0800969 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
970 codec_dai->tx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200971 soc_pcm_codec_params_fixup(&codec_params,
972 codec_dai->tx_mask);
Rander Wang24428f82019-03-08 16:38:57 +0800973
974 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
975 codec_dai->rx_mask)
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200976 soc_pcm_codec_params_fixup(&codec_params,
977 codec_dai->rx_mask);
978
Benoit Cousson93e69582014-07-08 23:19:38 +0200979 ret = soc_dai_hw_params(substream, &codec_params, codec_dai);
980 if(ret < 0)
Liam Girdwoodddee6272011-06-09 14:45:53 +0100981 goto codec_err;
Benoit Cousson2e5894d2014-07-08 23:19:35 +0200982
983 codec_dai->rate = params_rate(&codec_params);
984 codec_dai->channels = params_channels(&codec_params);
985 codec_dai->sample_bits = snd_pcm_format_physical_width(
986 params_format(&codec_params));
Liam Girdwoodddee6272011-06-09 14:45:53 +0100987 }
988
Benoit Cousson93e69582014-07-08 23:19:38 +0200989 ret = soc_dai_hw_params(substream, params, cpu_dai);
990 if (ret < 0)
991 goto interface_err;
Liam Girdwoodddee6272011-06-09 14:45:53 +0100992
993 if (platform->driver->ops && platform->driver->ops->hw_params) {
994 ret = platform->driver->ops->hw_params(substream, params);
995 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +0000996 dev_err(platform->dev, "ASoC: %s hw params failed: %d\n",
Lars-Peter Clausenf4333202014-06-16 18:13:02 +0200997 platform->component.name, ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +0100998 goto platform_err;
999 }
1000 }
1001
Nicolin Chen3635bf02013-11-13 18:56:24 +08001002 /* store the parameters for each DAIs */
Dong Aisheng17841022011-08-29 17:15:14 +08001003 cpu_dai->rate = params_rate(params);
Nicolin Chen3635bf02013-11-13 18:56:24 +08001004 cpu_dai->channels = params_channels(params);
1005 cpu_dai->sample_bits =
1006 snd_pcm_format_physical_width(params_format(params));
1007
Liam Girdwoodf5b50e72017-01-10 17:10:17 -08001008 /* malloc a page for hostless IO.
1009 * FIXME: rework with alsa-lib changes so that this malloc is
1010 * not required.
1011 */
1012 if (rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST) {
1013 substream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV;
1014 substream->dma_buffer.dev.dev = rtd->dev;
Banajit Goswami7ffe84e2017-01-10 17:28:14 -08001015 substream->dma_buffer.dev.dev->coherent_dma_mask =
1016 DMA_BIT_MASK(sizeof(dma_addr_t) * 8);
Liam Girdwoodf5b50e72017-01-10 17:10:17 -08001017 substream->dma_buffer.private_data = NULL;
1018
Banajit Goswami7ffe84e2017-01-10 17:28:14 -08001019 arch_setup_dma_ops(substream->dma_buffer.dev.dev,
1020 0, 0, NULL, 0);
Liam Girdwoodf5b50e72017-01-10 17:10:17 -08001021 ret = snd_pcm_lib_malloc_pages(substream, PAGE_SIZE);
1022 if (ret < 0)
1023 goto platform_err;
1024 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01001025out:
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +01001026 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001027 return ret;
1028
1029platform_err:
Mark Brownc5914b02013-10-30 17:47:39 -07001030 if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_free)
Liam Girdwoodddee6272011-06-09 14:45:53 +01001031 cpu_dai->driver->ops->hw_free(substream, cpu_dai);
1032
1033interface_err:
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001034 i = rtd->num_codecs;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001035
1036codec_err:
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001037 while (--i >= 0) {
1038 struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
1039 if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free)
1040 codec_dai->driver->ops->hw_free(substream, codec_dai);
1041 codec_dai->rate = 0;
1042 }
1043
Liam Girdwoodddee6272011-06-09 14:45:53 +01001044 if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
1045 rtd->dai_link->ops->hw_free(substream);
1046
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +01001047 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001048 return ret;
1049}
1050
1051/*
1052 * Frees resources allocated by hw_params, can be called multiple times
1053 */
1054static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
1055{
1056 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1057 struct snd_soc_platform *platform = rtd->platform;
1058 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001059 struct snd_soc_dai *codec_dai;
Nicolin Chen7f62b6e2013-12-04 11:18:36 +08001060 bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001061 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001062
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +01001063 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001064
Nicolin Chend3383422013-11-20 18:37:09 +08001065 /* clear the corresponding DAIs parameters when going to be inactive */
1066 if (cpu_dai->active == 1) {
1067 cpu_dai->rate = 0;
1068 cpu_dai->channels = 0;
1069 cpu_dai->sample_bits = 0;
1070 }
1071
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001072 for (i = 0; i < rtd->num_codecs; i++) {
1073 codec_dai = rtd->codec_dais[i];
1074 if (codec_dai->active == 1) {
1075 codec_dai->rate = 0;
1076 codec_dai->channels = 0;
1077 codec_dai->sample_bits = 0;
1078 }
Nicolin Chend3383422013-11-20 18:37:09 +08001079 }
1080
Liam Girdwoodddee6272011-06-09 14:45:53 +01001081 /* apply codec digital mute */
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001082 for (i = 0; i < rtd->num_codecs; i++) {
1083 if ((playback && rtd->codec_dais[i]->playback_active == 1) ||
1084 (!playback && rtd->codec_dais[i]->capture_active == 1))
1085 snd_soc_dai_digital_mute(rtd->codec_dais[i], 1,
1086 substream->stream);
1087 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01001088
1089 /* free any machine hw params */
1090 if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
1091 rtd->dai_link->ops->hw_free(substream);
1092
1093 /* free any DMA resources */
1094 if (platform->driver->ops && platform->driver->ops->hw_free)
1095 platform->driver->ops->hw_free(substream);
1096
1097 /* now free hw params for the DAIs */
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001098 for (i = 0; i < rtd->num_codecs; i++) {
1099 codec_dai = rtd->codec_dais[i];
1100 if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free)
1101 codec_dai->driver->ops->hw_free(substream, codec_dai);
1102 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01001103
Mark Brownc5914b02013-10-30 17:47:39 -07001104 if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_free)
Liam Girdwoodddee6272011-06-09 14:45:53 +01001105 cpu_dai->driver->ops->hw_free(substream, cpu_dai);
1106
Liam Girdwoodf5b50e72017-01-10 17:10:17 -08001107 if (rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST)
1108 snd_pcm_lib_free_pages(substream);
Liam Girdwoodb8c0dab2011-06-09 17:04:39 +01001109 mutex_unlock(&rtd->pcm_mutex);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001110 return 0;
1111}
1112
1113static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1114{
1115 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1116 struct snd_soc_platform *platform = rtd->platform;
1117 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001118 struct snd_soc_dai *codec_dai;
1119 int i, ret;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001120
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001121 for (i = 0; i < rtd->num_codecs; i++) {
1122 codec_dai = rtd->codec_dais[i];
1123 if (codec_dai->driver->ops && codec_dai->driver->ops->trigger) {
1124 ret = codec_dai->driver->ops->trigger(substream,
1125 cmd, codec_dai);
1126 if (ret < 0)
1127 return ret;
1128 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01001129 }
1130
1131 if (platform->driver->ops && platform->driver->ops->trigger) {
1132 ret = platform->driver->ops->trigger(substream, cmd);
1133 if (ret < 0)
1134 return ret;
1135 }
1136
Mark Brownc5914b02013-10-30 17:47:39 -07001137 if (cpu_dai->driver->ops && cpu_dai->driver->ops->trigger) {
Liam Girdwoodddee6272011-06-09 14:45:53 +01001138 ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai);
1139 if (ret < 0)
1140 return ret;
1141 }
Jarkko Nikula4792b0d2014-04-28 14:17:52 +02001142
1143 if (rtd->dai_link->ops && rtd->dai_link->ops->trigger) {
1144 ret = rtd->dai_link->ops->trigger(substream, cmd);
1145 if (ret < 0)
1146 return ret;
1147 }
1148
Liam Girdwoodddee6272011-06-09 14:45:53 +01001149 return 0;
1150}
1151
Mark Brown45c0a182012-05-09 21:46:27 +01001152static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
1153 int cmd)
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001154{
1155 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1156 struct snd_soc_platform *platform = rtd->platform;
1157 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001158 struct snd_soc_dai *codec_dai;
1159 int i, ret;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001160
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001161 for (i = 0; i < rtd->num_codecs; i++) {
1162 codec_dai = rtd->codec_dais[i];
1163 if (codec_dai->driver->ops &&
1164 codec_dai->driver->ops->bespoke_trigger) {
1165 ret = codec_dai->driver->ops->bespoke_trigger(substream,
1166 cmd, codec_dai);
1167 if (ret < 0)
1168 return ret;
1169 }
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001170 }
1171
Jean-Francois Moinedcf0fa22014-01-03 09:19:18 +01001172 if (platform->driver->bespoke_trigger) {
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001173 ret = platform->driver->bespoke_trigger(substream, cmd);
1174 if (ret < 0)
1175 return ret;
1176 }
1177
Mark Brownc5914b02013-10-30 17:47:39 -07001178 if (cpu_dai->driver->ops && cpu_dai->driver->ops->bespoke_trigger) {
Liam Girdwood07bf84a2012-04-25 12:12:52 +01001179 ret = cpu_dai->driver->ops->bespoke_trigger(substream, cmd, cpu_dai);
1180 if (ret < 0)
1181 return ret;
1182 }
1183 return 0;
1184}
Liam Girdwoodddee6272011-06-09 14:45:53 +01001185/*
1186 * soc level wrapper for pointer callback
1187 * If cpu_dai, codec_dai, platform driver has the delay callback, than
1188 * the runtime->delay will be updated accordingly.
1189 */
1190static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
1191{
1192 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1193 struct snd_soc_platform *platform = rtd->platform;
1194 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001195 struct snd_soc_dai *codec_dai;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001196 struct snd_pcm_runtime *runtime = substream->runtime;
1197 snd_pcm_uframes_t offset = 0;
1198 snd_pcm_sframes_t delay = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001199 snd_pcm_sframes_t codec_delay = 0;
1200 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001201
1202 if (platform->driver->ops && platform->driver->ops->pointer)
1203 offset = platform->driver->ops->pointer(substream);
1204
Kenneth Westfieldd6f99fa2015-05-19 12:03:55 -07001205 if (platform->driver->delay_blk)
1206 return offset;
1207
Mark Brownc5914b02013-10-30 17:47:39 -07001208 if (cpu_dai->driver->ops && cpu_dai->driver->ops->delay)
Liam Girdwoodddee6272011-06-09 14:45:53 +01001209 delay += cpu_dai->driver->ops->delay(substream, cpu_dai);
1210
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001211 for (i = 0; i < rtd->num_codecs; i++) {
1212 codec_dai = rtd->codec_dais[i];
1213 if (codec_dai->driver->ops && codec_dai->driver->ops->delay)
1214 codec_delay = max(codec_delay,
1215 codec_dai->driver->ops->delay(substream,
1216 codec_dai));
1217 }
1218 delay += codec_delay;
Liam Girdwoodddee6272011-06-09 14:45:53 +01001219
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001220 /*
1221 * None of the existing platform drivers implement delay(), so
1222 * for now the codec_dai of first multicodec entry is used
1223 */
Liam Girdwoodddee6272011-06-09 14:45:53 +01001224 if (platform->driver->delay)
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001225 delay += platform->driver->delay(substream, rtd->codec_dais[0]);
Liam Girdwoodddee6272011-06-09 14:45:53 +01001226
1227 runtime->delay = delay;
1228
1229 return offset;
1230}
1231
Kenneth Westfieldd6f99fa2015-05-19 12:03:55 -07001232static int soc_pcm_delay_blk(struct snd_pcm_substream *substream)
1233{
1234 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1235 struct snd_soc_platform *platform = rtd->platform;
1236 struct snd_pcm_runtime *runtime = substream->runtime;
1237 snd_pcm_sframes_t delay = 0;
1238
1239 if (platform->driver->delay_blk)
1240 delay = platform->driver->delay_blk(substream,
1241 rtd->codec_dais[0]);
1242
1243 runtime->delay = delay;
1244
1245 return 0;
1246}
1247
Liam Girdwood01d75842012-04-25 12:12:49 +01001248/* connect a FE and BE */
1249static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
1250 struct snd_soc_pcm_runtime *be, int stream)
1251{
1252 struct snd_soc_dpcm *dpcm;
1253
1254 /* only add new dpcms */
1255 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1256 if (dpcm->be == be && dpcm->fe == fe)
1257 return 0;
1258 }
1259
1260 dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_KERNEL);
1261 if (!dpcm)
1262 return -ENOMEM;
1263
1264 dpcm->be = be;
1265 dpcm->fe = fe;
1266 be->dpcm[stream].runtime = fe->dpcm[stream].runtime;
1267 dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW;
1268 list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients);
1269 list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients);
1270
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001271 dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001272 stream ? "capture" : "playback", fe->dai_link->name,
1273 stream ? "<-" : "->", be->dai_link->name);
1274
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001275#ifdef CONFIG_DEBUG_FS
Lars-Peter Clausen6553bf062015-04-09 10:52:38 +02001276 if (fe->debugfs_dpcm_root)
1277 dpcm->debugfs_state = debugfs_create_u32(be->dai_link->name, 0644,
1278 fe->debugfs_dpcm_root, &dpcm->state);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001279#endif
Liam Girdwood01d75842012-04-25 12:12:49 +01001280 return 1;
1281}
1282
1283/* reparent a BE onto another FE */
1284static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
1285 struct snd_soc_pcm_runtime *be, int stream)
1286{
1287 struct snd_soc_dpcm *dpcm;
1288 struct snd_pcm_substream *fe_substream, *be_substream;
1289
1290 /* reparent if BE is connected to other FEs */
1291 if (!be->dpcm[stream].users)
1292 return;
1293
1294 be_substream = snd_soc_dpcm_get_substream(be, stream);
1295
1296 list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {
1297 if (dpcm->fe == fe)
1298 continue;
1299
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001300 dev_dbg(fe->dev, "reparent %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001301 stream ? "capture" : "playback",
1302 dpcm->fe->dai_link->name,
1303 stream ? "<-" : "->", dpcm->be->dai_link->name);
1304
1305 fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, stream);
1306 be_substream->runtime = fe_substream->runtime;
1307 break;
1308 }
1309}
1310
1311/* disconnect a BE and FE */
Liam Girdwood23607022014-01-17 17:03:55 +00001312void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001313{
1314 struct snd_soc_dpcm *dpcm, *d;
1315
1316 list_for_each_entry_safe(dpcm, d, &fe->dpcm[stream].be_clients, list_be) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001317 dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001318 stream ? "capture" : "playback",
1319 dpcm->be->dai_link->name);
1320
1321 if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE)
1322 continue;
1323
Jarkko Nikula7cc302d2013-09-30 17:08:15 +03001324 dev_dbg(fe->dev, "freed DSP %s path %s %s %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001325 stream ? "capture" : "playback", fe->dai_link->name,
1326 stream ? "<-" : "->", dpcm->be->dai_link->name);
1327
1328 /* BEs still alive need new FE */
1329 dpcm_be_reparent(fe, dpcm->be, stream);
1330
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01001331#ifdef CONFIG_DEBUG_FS
1332 debugfs_remove(dpcm->debugfs_state);
1333#endif
Liam Girdwood01d75842012-04-25 12:12:49 +01001334 list_del(&dpcm->list_be);
1335 list_del(&dpcm->list_fe);
1336 kfree(dpcm);
1337 }
1338}
1339
1340/* get BE for DAI widget and stream */
1341static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
1342 struct snd_soc_dapm_widget *widget, int stream)
1343{
1344 struct snd_soc_pcm_runtime *be;
Mengdong Lin1a497982015-11-18 02:34:11 -05001345 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01001346
1347 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
Mengdong Lin1a497982015-11-18 02:34:11 -05001348 list_for_each_entry(be, &card->rtd_list, list) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001349
Liam Girdwood35ea0652012-06-05 19:26:59 +01001350 if (!be->dai_link->no_pcm)
1351 continue;
1352
Banajit Goswami4eff0792016-12-08 22:20:41 -08001353 if ((be->cpu_dai->playback_widget == widget &&
1354 (be->dai_link->stream_name &&
1355 !strcmp(be->dai_link->stream_name,
1356 be->cpu_dai->playback_widget->sname))) ||
1357 be->codec_dai->playback_widget == widget)
Liam Girdwood01d75842012-04-25 12:12:49 +01001358 return be;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001359
Mengdong Lin1a497982015-11-18 02:34:11 -05001360 for (i = 0; i < be->num_codecs; i++) {
1361 struct snd_soc_dai *dai = be->codec_dais[i];
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001362 if (dai->playback_widget == widget)
1363 return be;
1364 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001365 }
1366 } else {
1367
Mengdong Lin1a497982015-11-18 02:34:11 -05001368 list_for_each_entry(be, &card->rtd_list, list) {
Liam Girdwood01d75842012-04-25 12:12:49 +01001369
Liam Girdwood35ea0652012-06-05 19:26:59 +01001370 if (!be->dai_link->no_pcm)
1371 continue;
1372
Banajit Goswami4eff0792016-12-08 22:20:41 -08001373 if ((be->cpu_dai->capture_widget == widget &&
1374 (be->dai_link->stream_name &&
1375 !strcmp(be->dai_link->stream_name,
1376 be->cpu_dai->capture_widget->sname))) ||
1377 be->codec_dai->capture_widget == widget)
Liam Girdwood01d75842012-04-25 12:12:49 +01001378 return be;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001379
Mengdong Lin1a497982015-11-18 02:34:11 -05001380 for (i = 0; i < be->num_codecs; i++) {
1381 struct snd_soc_dai *dai = be->codec_dais[i];
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001382 if (dai->capture_widget == widget)
1383 return be;
1384 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001385 }
1386 }
1387
Liam Girdwood103d84a2012-11-19 14:39:15 +00001388 dev_err(card->dev, "ASoC: can't get %s BE for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001389 stream ? "capture" : "playback", widget->name);
1390 return NULL;
1391}
1392
1393static inline struct snd_soc_dapm_widget *
Benoit Cousson37018612014-04-24 14:01:45 +02001394 dai_get_widget(struct snd_soc_dai *dai, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001395{
1396 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
Benoit Cousson37018612014-04-24 14:01:45 +02001397 return dai->playback_widget;
Liam Girdwood01d75842012-04-25 12:12:49 +01001398 else
Benoit Cousson37018612014-04-24 14:01:45 +02001399 return dai->capture_widget;
Liam Girdwood01d75842012-04-25 12:12:49 +01001400}
1401
1402static int widget_in_list(struct snd_soc_dapm_widget_list *list,
1403 struct snd_soc_dapm_widget *widget)
1404{
1405 int i;
1406
1407 for (i = 0; i < list->num_widgets; i++) {
1408 if (widget == list->widgets[i])
1409 return 1;
1410 }
1411
1412 return 0;
1413}
1414
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001415static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget,
1416 enum snd_soc_dapm_direction dir)
1417{
1418 struct snd_soc_card *card = widget->dapm->card;
1419 struct snd_soc_pcm_runtime *rtd;
1420 int i;
1421
1422 if (dir == SND_SOC_DAPM_DIR_OUT) {
1423 list_for_each_entry(rtd, &card->rtd_list, list) {
1424 if (!rtd->dai_link->no_pcm)
1425 continue;
1426
1427 if (rtd->cpu_dai->playback_widget == widget)
1428 return true;
1429
1430 for (i = 0; i < rtd->num_codecs; ++i) {
1431 struct snd_soc_dai *dai = rtd->codec_dais[i];
1432 if (dai->playback_widget == widget)
1433 return true;
1434 }
1435 }
1436 } else { /* SND_SOC_DAPM_DIR_IN */
1437 list_for_each_entry(rtd, &card->rtd_list, list) {
1438 if (!rtd->dai_link->no_pcm)
1439 continue;
1440
1441 if (rtd->cpu_dai->capture_widget == widget)
1442 return true;
1443
1444 for (i = 0; i < rtd->num_codecs; ++i) {
1445 struct snd_soc_dai *dai = rtd->codec_dais[i];
1446 if (dai->capture_widget == widget)
1447 return true;
1448 }
1449 }
1450 }
1451
1452 return false;
1453}
1454
Liam Girdwood23607022014-01-17 17:03:55 +00001455int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001456 int stream, struct snd_soc_dapm_widget_list **list)
Liam Girdwood01d75842012-04-25 12:12:49 +01001457{
1458 struct snd_soc_dai *cpu_dai = fe->cpu_dai;
Liam Girdwood01d75842012-04-25 12:12:49 +01001459 int paths;
1460
Liam Girdwood01d75842012-04-25 12:12:49 +01001461 /* get number of valid DAI paths and their widgets */
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001462 paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list,
Piotr Stankiewicz5fdd0222016-05-13 17:03:56 +01001463 dpcm_end_walk_at_be);
Liam Girdwood01d75842012-04-25 12:12:49 +01001464
Liam Girdwood103d84a2012-11-19 14:39:15 +00001465 dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths,
Liam Girdwood01d75842012-04-25 12:12:49 +01001466 stream ? "capture" : "playback");
1467
Liam Girdwood01d75842012-04-25 12:12:49 +01001468 return paths;
1469}
1470
Liam Girdwood01d75842012-04-25 12:12:49 +01001471static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
1472 struct snd_soc_dapm_widget_list **list_)
1473{
1474 struct snd_soc_dpcm *dpcm;
1475 struct snd_soc_dapm_widget_list *list = *list_;
1476 struct snd_soc_dapm_widget *widget;
1477 int prune = 0;
1478
1479 /* Destroy any old FE <--> BE connections */
1480 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001481 unsigned int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01001482
1483 /* is there a valid CPU DAI widget for this BE */
Benoit Cousson37018612014-04-24 14:01:45 +02001484 widget = dai_get_widget(dpcm->be->cpu_dai, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001485
1486 /* prune the BE if it's no longer in our active list */
1487 if (widget && widget_in_list(list, widget))
1488 continue;
1489
1490 /* is there a valid CODEC DAI widget for this BE */
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001491 for (i = 0; i < dpcm->be->num_codecs; i++) {
1492 struct snd_soc_dai *dai = dpcm->be->codec_dais[i];
1493 widget = dai_get_widget(dai, stream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001494
Benoit Cousson2e5894d2014-07-08 23:19:35 +02001495 /* prune the BE if it's no longer in our active list */
1496 if (widget && widget_in_list(list, widget))
1497 continue;
1498 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001499
Liam Girdwood103d84a2012-11-19 14:39:15 +00001500 dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001501 stream ? "capture" : "playback",
1502 dpcm->be->dai_link->name, fe->dai_link->name);
1503 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
1504 dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1505 prune++;
1506 }
1507
Liam Girdwood103d84a2012-11-19 14:39:15 +00001508 dev_dbg(fe->dev, "ASoC: found %d old BE paths for pruning\n", prune);
Liam Girdwood01d75842012-04-25 12:12:49 +01001509 return prune;
1510}
1511
1512static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
1513 struct snd_soc_dapm_widget_list **list_)
1514{
1515 struct snd_soc_card *card = fe->card;
1516 struct snd_soc_dapm_widget_list *list = *list_;
1517 struct snd_soc_pcm_runtime *be;
1518 int i, new = 0, err;
1519
1520 /* Create any new FE <--> BE connections */
1521 for (i = 0; i < list->num_widgets; i++) {
1522
Mark Brown46162742013-06-05 19:36:11 +01001523 switch (list->widgets[i]->id) {
1524 case snd_soc_dapm_dai_in:
Koro Chenc5b85402015-07-06 10:02:10 +08001525 if (stream != SNDRV_PCM_STREAM_PLAYBACK)
1526 continue;
1527 break;
Mark Brown46162742013-06-05 19:36:11 +01001528 case snd_soc_dapm_dai_out:
Koro Chenc5b85402015-07-06 10:02:10 +08001529 if (stream != SNDRV_PCM_STREAM_CAPTURE)
1530 continue;
Mark Brown46162742013-06-05 19:36:11 +01001531 break;
1532 default:
Liam Girdwood01d75842012-04-25 12:12:49 +01001533 continue;
Mark Brown46162742013-06-05 19:36:11 +01001534 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001535
1536 /* is there a valid BE rtd for this widget */
1537 be = dpcm_get_be(card, list->widgets[i], stream);
1538 if (!be) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001539 dev_err(fe->dev, "ASoC: no BE found for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001540 list->widgets[i]->name);
1541 continue;
1542 }
1543
1544 /* make sure BE is a real BE */
1545 if (!be->dai_link->no_pcm)
1546 continue;
1547
1548 /* don't connect if FE is not running */
Liam Girdwood23607022014-01-17 17:03:55 +00001549 if (!fe->dpcm[stream].runtime && !fe->fe_compr)
Liam Girdwood01d75842012-04-25 12:12:49 +01001550 continue;
1551
1552 /* newly connected FE and BE */
1553 err = dpcm_be_connect(fe, be, stream);
1554 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001555 dev_err(fe->dev, "ASoC: can't connect %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001556 list->widgets[i]->name);
1557 break;
1558 } else if (err == 0) /* already connected */
1559 continue;
1560
1561 /* new */
1562 be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1563 new++;
1564 }
1565
Liam Girdwood103d84a2012-11-19 14:39:15 +00001566 dev_dbg(fe->dev, "ASoC: found %d new BE paths\n", new);
Liam Girdwood01d75842012-04-25 12:12:49 +01001567 return new;
1568}
1569
1570/*
1571 * Find the corresponding BE DAIs that source or sink audio to this
1572 * FE substream.
1573 */
Liam Girdwood23607022014-01-17 17:03:55 +00001574int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
Liam Girdwood01d75842012-04-25 12:12:49 +01001575 int stream, struct snd_soc_dapm_widget_list **list, int new)
1576{
1577 if (new)
1578 return dpcm_add_paths(fe, stream, list);
1579 else
1580 return dpcm_prune_paths(fe, stream, list);
1581}
1582
Liam Girdwood23607022014-01-17 17:03:55 +00001583void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001584{
1585 struct snd_soc_dpcm *dpcm;
1586
1587 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
1588 dpcm->be->dpcm[stream].runtime_update =
1589 SND_SOC_DPCM_UPDATE_NO;
1590}
1591
1592static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe,
1593 int stream)
1594{
1595 struct snd_soc_dpcm *dpcm;
1596
1597 /* disable any enabled and non active backends */
1598 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1599
1600 struct snd_soc_pcm_runtime *be = dpcm->be;
1601 struct snd_pcm_substream *be_substream =
1602 snd_soc_dpcm_get_substream(be, stream);
1603
1604 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001605 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001606 stream ? "capture" : "playback",
1607 be->dpcm[stream].state);
1608
1609 if (--be->dpcm[stream].users != 0)
1610 continue;
1611
1612 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1613 continue;
1614
1615 soc_pcm_close(be_substream);
1616 be_substream->runtime = NULL;
1617 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1618 }
1619}
1620
Liam Girdwood23607022014-01-17 17:03:55 +00001621int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001622{
1623 struct snd_soc_dpcm *dpcm;
1624 int err, count = 0;
1625
1626 /* only startup BE DAIs that are either sinks or sources to this FE DAI */
1627 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1628
1629 struct snd_soc_pcm_runtime *be = dpcm->be;
1630 struct snd_pcm_substream *be_substream =
1631 snd_soc_dpcm_get_substream(be, stream);
1632
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001633 if (!be_substream) {
1634 dev_err(be->dev, "ASoC: no backend %s stream\n",
1635 stream ? "capture" : "playback");
1636 continue;
1637 }
1638
Liam Girdwood01d75842012-04-25 12:12:49 +01001639 /* is this op for this BE ? */
1640 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1641 continue;
1642
1643 /* first time the dpcm is open ? */
1644 if (be->dpcm[stream].users == DPCM_MAX_BE_USERS)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001645 dev_err(be->dev, "ASoC: too many users %s at open %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001646 stream ? "capture" : "playback",
1647 be->dpcm[stream].state);
1648
1649 if (be->dpcm[stream].users++ != 0)
1650 continue;
1651
1652 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
1653 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
1654 continue;
1655
Russell King - ARM Linux2062b4c2013-10-31 15:09:20 +00001656 dev_dbg(be->dev, "ASoC: open %s BE %s\n",
1657 stream ? "capture" : "playback", be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001658
1659 be_substream->runtime = be->dpcm[stream].runtime;
1660 err = soc_pcm_open(be_substream);
1661 if (err < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001662 dev_err(be->dev, "ASoC: BE open failed %d\n", err);
Liam Girdwood01d75842012-04-25 12:12:49 +01001663 be->dpcm[stream].users--;
1664 if (be->dpcm[stream].users < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001665 dev_err(be->dev, "ASoC: no users %s at unwind %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001666 stream ? "capture" : "playback",
1667 be->dpcm[stream].state);
1668
1669 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1670 goto unwind;
1671 }
1672
1673 be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1674 count++;
1675 }
1676
1677 return count;
1678
1679unwind:
1680 /* disable any enabled and non active backends */
1681 list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1682 struct snd_soc_pcm_runtime *be = dpcm->be;
1683 struct snd_pcm_substream *be_substream =
1684 snd_soc_dpcm_get_substream(be, stream);
1685
1686 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1687 continue;
1688
1689 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001690 dev_err(be->dev, "ASoC: no users %s at close %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001691 stream ? "capture" : "playback",
1692 be->dpcm[stream].state);
1693
1694 if (--be->dpcm[stream].users != 0)
1695 continue;
1696
1697 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
1698 continue;
1699
1700 soc_pcm_close(be_substream);
1701 be_substream->runtime = NULL;
1702 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1703 }
1704
1705 return err;
1706}
1707
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001708static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001709 struct snd_soc_pcm_stream *stream,
1710 u64 formats)
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001711{
1712 runtime->hw.rate_min = stream->rate_min;
Charles Keepax807bd322018-08-27 14:26:47 +01001713 runtime->hw.rate_max = min_not_zero(stream->rate_max, UINT_MAX);
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001714 runtime->hw.channels_min = stream->channels_min;
1715 runtime->hw.channels_max = stream->channels_max;
Lars-Peter Clausen002220a2014-01-06 14:19:07 +01001716 if (runtime->hw.formats)
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001717 runtime->hw.formats &= formats & stream->formats;
Lars-Peter Clausen002220a2014-01-06 14:19:07 +01001718 else
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001719 runtime->hw.formats = formats & stream->formats;
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001720 runtime->hw.rates = stream->rates;
1721}
1722
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001723static u64 dpcm_runtime_base_format(struct snd_pcm_substream *substream)
1724{
1725 struct snd_soc_pcm_runtime *fe = substream->private_data;
1726 struct snd_soc_dpcm *dpcm;
1727 u64 formats = ULLONG_MAX;
1728 int stream = substream->stream;
1729
1730 if (!fe->dai_link->dpcm_merged_format)
1731 return formats;
1732
1733 /*
1734 * It returns merged BE codec format
1735 * if FE want to use it (= dpcm_merged_format)
1736 */
1737
1738 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1739 struct snd_soc_pcm_runtime *be = dpcm->be;
1740 struct snd_soc_dai_driver *codec_dai_drv;
1741 struct snd_soc_pcm_stream *codec_stream;
1742 int i;
1743
1744 for (i = 0; i < be->num_codecs; i++) {
Jerome Brunet5304f2a2018-06-27 17:36:38 +02001745 /*
1746 * Skip CODECs which don't support the current stream
1747 * type. See soc_pcm_init_runtime_hw() for more details
1748 */
1749 if (!snd_soc_dai_stream_valid(be->codec_dais[i],
1750 stream))
1751 continue;
1752
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001753 codec_dai_drv = be->codec_dais[i]->driver;
1754 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1755 codec_stream = &codec_dai_drv->playback;
1756 else
1757 codec_stream = &codec_dai_drv->capture;
1758
1759 formats &= codec_stream->formats;
1760 }
1761 }
1762
1763 return formats;
1764}
1765
Mark Brown45c0a182012-05-09 21:46:27 +01001766static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001767{
1768 struct snd_pcm_runtime *runtime = substream->runtime;
1769 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1770 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
1771 struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001772 u64 format = dpcm_runtime_base_format(substream);
Liam Girdwood01d75842012-04-25 12:12:49 +01001773
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001774 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001775 dpcm_init_runtime_hw(runtime, &cpu_dai_drv->playback, format);
Lars-Peter Clausen08ae9b42014-01-06 14:19:06 +01001776 else
Kuninori Morimotob073ed42015-05-12 02:03:33 +00001777 dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture, format);
Liam Girdwood01d75842012-04-25 12:12:49 +01001778}
1779
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001780static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
1781
1782/* Set FE's runtime_update state; the state is protected via PCM stream lock
1783 * for avoiding the race with trigger callback.
1784 * If the state is unset and a trigger is pending while the previous operation,
1785 * process the pending trigger action here.
1786 */
1787static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
1788 int stream, enum snd_soc_dpcm_update state)
1789{
1790 struct snd_pcm_substream *substream =
1791 snd_soc_dpcm_get_substream(fe, stream);
1792
1793 snd_pcm_stream_lock_irq(substream);
1794 if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) {
1795 dpcm_fe_dai_do_trigger(substream,
1796 fe->dpcm[stream].trigger_pending - 1);
1797 fe->dpcm[stream].trigger_pending = 0;
1798 }
1799 fe->dpcm[stream].runtime_update = state;
1800 snd_pcm_stream_unlock_irq(substream);
1801}
1802
PC Liao906c7d62015-12-11 11:33:51 +08001803static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
1804 int stream)
1805{
1806 struct snd_soc_dpcm *dpcm;
1807 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
1808 struct snd_soc_dai *fe_cpu_dai = fe->cpu_dai;
1809 int err;
1810
1811 /* apply symmetry for FE */
1812 if (soc_pcm_has_symmetry(fe_substream))
1813 fe_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1814
1815 /* Symmetry only applies if we've got an active stream. */
1816 if (fe_cpu_dai->active) {
1817 err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai);
1818 if (err < 0)
1819 return err;
1820 }
1821
1822 /* apply symmetry for BE */
1823 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1824 struct snd_soc_pcm_runtime *be = dpcm->be;
1825 struct snd_pcm_substream *be_substream =
1826 snd_soc_dpcm_get_substream(be, stream);
1827 struct snd_soc_pcm_runtime *rtd = be_substream->private_data;
1828 int i;
1829
Jeeja KPf1176612016-09-06 14:17:55 +05301830 if (rtd->dai_link->be_hw_params_fixup)
1831 continue;
1832
PC Liao906c7d62015-12-11 11:33:51 +08001833 if (soc_pcm_has_symmetry(be_substream))
1834 be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
1835
1836 /* Symmetry only applies if we've got an active stream. */
1837 if (rtd->cpu_dai->active) {
1838 err = soc_pcm_apply_symmetry(be_substream, rtd->cpu_dai);
1839 if (err < 0)
1840 return err;
1841 }
1842
1843 for (i = 0; i < rtd->num_codecs; i++) {
1844 if (rtd->codec_dais[i]->active) {
1845 err = soc_pcm_apply_symmetry(be_substream,
1846 rtd->codec_dais[i]);
1847 if (err < 0)
1848 return err;
1849 }
1850 }
1851 }
1852
1853 return 0;
1854}
1855
Liam Girdwood01d75842012-04-25 12:12:49 +01001856static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
1857{
1858 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
1859 struct snd_pcm_runtime *runtime = fe_substream->runtime;
1860 int stream = fe_substream->stream, ret = 0;
1861
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001862 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001863
1864 ret = dpcm_be_dai_startup(fe, fe_substream->stream);
1865 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001866 dev_err(fe->dev,"ASoC: failed to start some BEs %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001867 goto be_err;
1868 }
1869
Liam Girdwood103d84a2012-11-19 14:39:15 +00001870 dev_dbg(fe->dev, "ASoC: open FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001871
1872 /* start the DAI frontend */
1873 ret = soc_pcm_open(fe_substream);
1874 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00001875 dev_err(fe->dev,"ASoC: failed to start FE %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01001876 goto unwind;
1877 }
1878
1879 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1880
1881 dpcm_set_fe_runtime(fe_substream);
1882 snd_pcm_limit_hw_rates(runtime);
1883
PC Liao906c7d62015-12-11 11:33:51 +08001884 ret = dpcm_apply_symmetry(fe_substream, stream);
1885 if (ret < 0) {
1886 dev_err(fe->dev, "ASoC: failed to apply dpcm symmetry %d\n",
1887 ret);
1888 goto unwind;
1889 }
1890
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001891 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001892 return 0;
1893
1894unwind:
1895 dpcm_be_dai_startup_unwind(fe, fe_substream->stream);
1896be_err:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001897 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001898 return ret;
1899}
1900
Liam Girdwood23607022014-01-17 17:03:55 +00001901int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001902{
1903 struct snd_soc_dpcm *dpcm;
1904
1905 /* only shutdown BEs that are either sinks or sources to this FE DAI */
1906 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1907
1908 struct snd_soc_pcm_runtime *be = dpcm->be;
1909 struct snd_pcm_substream *be_substream =
1910 snd_soc_dpcm_get_substream(be, stream);
1911
1912 /* is this op for this BE ? */
1913 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1914 continue;
1915
1916 if (be->dpcm[stream].users == 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00001917 dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01001918 stream ? "capture" : "playback",
1919 be->dpcm[stream].state);
1920
1921 if (--be->dpcm[stream].users != 0)
1922 continue;
1923
1924 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Kai Chieh Chuang32b7d632018-05-28 10:18:18 +08001925 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) {
1926 soc_pcm_hw_free(be_substream);
1927 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1928 }
Liam Girdwood01d75842012-04-25 12:12:49 +01001929
Liam Girdwood103d84a2012-11-19 14:39:15 +00001930 dev_dbg(be->dev, "ASoC: close BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001931 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001932
1933 soc_pcm_close(be_substream);
1934 be_substream->runtime = NULL;
1935
1936 be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1937 }
1938 return 0;
1939}
1940
1941static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
1942{
1943 struct snd_soc_pcm_runtime *fe = substream->private_data;
1944 int stream = substream->stream;
1945
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001946 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01001947
Liam Girdwood103d84a2012-11-19 14:39:15 +00001948 dev_dbg(fe->dev, "ASoC: close FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001949
1950 /* now shutdown the frontend */
1951 soc_pcm_close(substream);
1952
Banajit Goswami1c7b7b42015-04-09 17:19:30 -07001953 /* shutdown the BEs */
1954 dpcm_be_dai_shutdown(fe, substream->stream);
1955
Liam Girdwood01d75842012-04-25 12:12:49 +01001956 /* run the stream event for each BE */
1957 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
1958
1959 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01001960 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01001961 return 0;
1962}
1963
Liam Girdwood23607022014-01-17 17:03:55 +00001964int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01001965{
1966 struct snd_soc_dpcm *dpcm;
1967
1968 /* only hw_params backends that are either sinks or sources
1969 * to this frontend DAI */
1970 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1971
1972 struct snd_soc_pcm_runtime *be = dpcm->be;
1973 struct snd_pcm_substream *be_substream =
1974 snd_soc_dpcm_get_substream(be, stream);
1975
1976 /* is this op for this BE ? */
1977 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
1978 continue;
1979
1980 /* only free hw when no longer used - check all FEs */
1981 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
1982 continue;
1983
Qiao Zhou36fba622014-12-03 10:13:43 +08001984 /* do not free hw if this BE is used by other FE */
1985 if (be->dpcm[stream].users > 1)
1986 continue;
1987
Liam Girdwood01d75842012-04-25 12:12:49 +01001988 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
1989 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
1990 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
Patrick Lai08b27842012-12-19 19:36:02 -08001991 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
Vinod Koul5e82d2b2016-02-01 22:26:40 +05301992 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
1993 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
Liam Girdwood01d75842012-04-25 12:12:49 +01001994 continue;
1995
Liam Girdwood103d84a2012-11-19 14:39:15 +00001996 dev_dbg(be->dev, "ASoC: hw_free BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00001997 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01001998
1999 soc_pcm_hw_free(be_substream);
2000
2001 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
2002 }
2003
2004 return 0;
2005}
2006
Mark Brown45c0a182012-05-09 21:46:27 +01002007static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002008{
2009 struct snd_soc_pcm_runtime *fe = substream->private_data;
2010 int err, stream = substream->stream;
2011
2012 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002013 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002014
Liam Girdwood103d84a2012-11-19 14:39:15 +00002015 dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002016
2017 /* call hw_free on the frontend */
2018 err = soc_pcm_hw_free(substream);
2019 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002020 dev_err(fe->dev,"ASoC: hw_free FE %s failed\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002021 fe->dai_link->name);
2022
2023 /* only hw_params backends that are either sinks or sources
2024 * to this frontend DAI */
2025 err = dpcm_be_dai_hw_free(fe, stream);
2026
2027 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002028 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002029
2030 mutex_unlock(&fe->card->mutex);
2031 return 0;
2032}
2033
Banajit Goswami8886fb02016-11-21 21:39:54 -08002034int dpcm_fe_dai_hw_params_be(struct snd_soc_pcm_runtime *fe,
2035 struct snd_soc_pcm_runtime *be,
2036 struct snd_pcm_hw_params *params, int stream)
2037{
2038 int ret;
2039 struct snd_soc_dpcm *dpcm;
2040 struct snd_pcm_substream *be_substream =
2041 snd_soc_dpcm_get_substream(be, stream);
2042
2043 /* is this op for this BE ? */
2044 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2045 return 0;
2046
2047 /* only allow hw_params() if no connected FEs are running */
2048 if (!snd_soc_dpcm_can_be_params(fe, be, stream))
2049 return 0;
2050
2051 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
2052 (be->dpcm[stream].state !=
2053 SND_SOC_DPCM_STATE_HW_PARAMS) &&
2054 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE))
2055 return 0;
2056
2057 dev_dbg(be->dev, "ASoC: hw_params BE %s\n",
2058 fe->dai_link->name);
2059
2060 /* perform any hw_params fixups */
2061 if (be->dai_link->be_hw_params_fixup) {
2062 ret = be->dai_link->be_hw_params_fixup(be,
2063 params);
2064 if (ret < 0) {
2065 dev_err(be->dev,
2066 "ASoC: hw_params BE fixup failed %d\n",
2067 ret);
2068 goto unwind;
2069 }
2070 }
2071
2072 ret = soc_pcm_hw_params(be_substream, params);
2073 if (ret < 0) {
2074 dev_err(be->dev, "ASoC: hw_params BE failed %d\n", ret);
2075 goto unwind;
2076 }
2077
2078 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2079 return 0;
2080
2081unwind:
2082 /* disable any enabled and non active backends */
2083 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
2084 struct snd_soc_pcm_runtime *be = dpcm->be;
2085 struct snd_pcm_substream *be_substream =
2086 snd_soc_dpcm_get_substream(be, stream);
2087
2088 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2089 continue;
2090
2091 /* only allow hw_free() if no connected FEs are running */
2092 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2093 continue;
2094
2095 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
2096 (be->dpcm[stream].state
2097 != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2098 (be->dpcm[stream].state
2099 != SND_SOC_DPCM_STATE_HW_FREE) &&
2100 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
2101 continue;
2102
2103 soc_pcm_hw_free(be_substream);
2104 }
2105
2106 return ret;
2107}
2108
Liam Girdwood23607022014-01-17 17:03:55 +00002109int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002110{
2111 struct snd_soc_dpcm *dpcm;
2112 int ret;
2113
2114 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
2115
2116 struct snd_soc_pcm_runtime *be = dpcm->be;
2117 struct snd_pcm_substream *be_substream =
2118 snd_soc_dpcm_get_substream(be, stream);
2119
2120 /* is this op for this BE ? */
2121 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2122 continue;
2123
Liam Girdwood01d75842012-04-25 12:12:49 +01002124 /* copy params for each dpcm */
2125 memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params,
2126 sizeof(struct snd_pcm_hw_params));
2127
2128 /* perform any hw_params fixups */
2129 if (be->dai_link->be_hw_params_fixup) {
2130 ret = be->dai_link->be_hw_params_fixup(be,
2131 &dpcm->hw_params);
2132 if (ret < 0) {
2133 dev_err(be->dev,
Liam Girdwood103d84a2012-11-19 14:39:15 +00002134 "ASoC: hw_params BE fixup failed %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002135 ret);
2136 goto unwind;
2137 }
2138 }
2139
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00002140 /* only allow hw_params() if no connected FEs are running */
2141 if (!snd_soc_dpcm_can_be_params(fe, be, stream))
2142 continue;
2143
2144 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
2145 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2146 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE))
2147 continue;
2148
2149 dev_dbg(be->dev, "ASoC: hw_params BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002150 be->dai_link->name);
Kuninori Morimotob0639bd2016-01-21 01:47:12 +00002151
Liam Girdwood01d75842012-04-25 12:12:49 +01002152 ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params);
2153 if (ret < 0) {
2154 dev_err(dpcm->be->dev,
Liam Girdwood103d84a2012-11-19 14:39:15 +00002155 "ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002156 goto unwind;
2157 }
2158
2159 be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2160 }
2161 return 0;
2162
2163unwind:
2164 /* disable any enabled and non active backends */
2165 list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) {
2166 struct snd_soc_pcm_runtime *be = dpcm->be;
2167 struct snd_pcm_substream *be_substream =
2168 snd_soc_dpcm_get_substream(be, stream);
2169
2170 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2171 continue;
2172
2173 /* only allow hw_free() if no connected FEs are running */
2174 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2175 continue;
2176
2177 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
2178 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2179 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
2180 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
2181 continue;
2182
2183 soc_pcm_hw_free(be_substream);
2184 }
2185
2186 return ret;
2187}
2188
Mark Brown45c0a182012-05-09 21:46:27 +01002189static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
2190 struct snd_pcm_hw_params *params)
Liam Girdwood01d75842012-04-25 12:12:49 +01002191{
2192 struct snd_soc_pcm_runtime *fe = substream->private_data;
2193 int ret, stream = substream->stream;
2194
2195 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002196 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002197
2198 memcpy(&fe->dpcm[substream->stream].hw_params, params,
2199 sizeof(struct snd_pcm_hw_params));
2200 ret = dpcm_be_dai_hw_params(fe, substream->stream);
2201 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002202 dev_err(fe->dev,"ASoC: hw_params BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002203 goto out;
2204 }
2205
Liam Girdwood103d84a2012-11-19 14:39:15 +00002206 dev_dbg(fe->dev, "ASoC: hw_params FE %s rate %d chan %x fmt %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002207 fe->dai_link->name, params_rate(params),
2208 params_channels(params), params_format(params));
2209
2210 /* call hw_params on the frontend */
2211 ret = soc_pcm_hw_params(substream, params);
2212 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002213 dev_err(fe->dev,"ASoC: hw_params FE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002214 dpcm_be_dai_hw_free(fe, stream);
2215 } else
2216 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
2217
2218out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002219 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002220 mutex_unlock(&fe->card->mutex);
2221 return ret;
2222}
2223
2224static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm,
2225 struct snd_pcm_substream *substream, int cmd)
2226{
2227 int ret;
2228
Liam Girdwood103d84a2012-11-19 14:39:15 +00002229 dev_dbg(dpcm->be->dev, "ASoC: trigger BE %s cmd %d\n",
彭东林94d215c2016-09-26 08:29:31 +00002230 dpcm->be->dai_link->name, cmd);
Liam Girdwood01d75842012-04-25 12:12:49 +01002231
2232 ret = soc_pcm_trigger(substream, cmd);
2233 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002234 dev_err(dpcm->be->dev,"ASoC: trigger BE failed %d\n", ret);
Liam Girdwood01d75842012-04-25 12:12:49 +01002235
2236 return ret;
2237}
2238
Liam Girdwood23607022014-01-17 17:03:55 +00002239int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
Mark Brown45c0a182012-05-09 21:46:27 +01002240 int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002241{
2242 struct snd_soc_dpcm *dpcm;
2243 int ret = 0;
2244
2245 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
2246
2247 struct snd_soc_pcm_runtime *be = dpcm->be;
2248 struct snd_pcm_substream *be_substream =
2249 snd_soc_dpcm_get_substream(be, stream);
2250
2251 /* is this op for this BE ? */
2252 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2253 continue;
2254
2255 switch (cmd) {
2256 case SNDRV_PCM_TRIGGER_START:
2257 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
2258 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
2259 continue;
2260
2261 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2262 if (ret)
2263 return ret;
2264
2265 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2266 break;
2267 case SNDRV_PCM_TRIGGER_RESUME:
2268 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
2269 continue;
2270
2271 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2272 if (ret)
2273 return ret;
2274
2275 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2276 break;
2277 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2278 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
2279 continue;
2280
2281 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2282 if (ret)
2283 return ret;
2284
2285 be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2286 break;
2287 case SNDRV_PCM_TRIGGER_STOP:
2288 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2289 continue;
2290
2291 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2292 continue;
2293
2294 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2295 if (ret)
2296 return ret;
2297
2298 be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2299 break;
2300 case SNDRV_PCM_TRIGGER_SUSPEND:
Nicolin Chen868a6ca2014-05-12 20:12:05 +08002301 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
Liam Girdwood01d75842012-04-25 12:12:49 +01002302 continue;
2303
2304 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2305 continue;
2306
2307 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2308 if (ret)
2309 return ret;
2310
2311 be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND;
2312 break;
2313 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2314 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2315 continue;
2316
2317 if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
2318 continue;
2319
2320 ret = dpcm_do_trigger(dpcm, be_substream, cmd);
2321 if (ret)
2322 return ret;
2323
2324 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2325 break;
2326 }
2327 }
2328
2329 return ret;
2330}
2331EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
2332
Ranjani Sridharan221f1412019-11-04 14:48:11 -08002333static int dpcm_dai_trigger_fe_be(struct snd_pcm_substream *substream,
2334 int cmd, bool fe_first)
2335{
2336 struct snd_soc_pcm_runtime *fe = substream->private_data;
2337 int ret;
2338
2339 /* call trigger on the frontend before the backend. */
2340 if (fe_first) {
2341 dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n",
2342 fe->dai_link->name, cmd);
2343
2344 ret = soc_pcm_trigger(substream, cmd);
2345 if (ret < 0)
2346 return ret;
2347
2348 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2349 return ret;
2350 }
2351
2352 /* call trigger on the frontend after the backend. */
2353 ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
2354 if (ret < 0)
2355 return ret;
2356
2357 dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n",
2358 fe->dai_link->name, cmd);
2359
2360 ret = soc_pcm_trigger(substream, cmd);
2361
2362 return ret;
2363}
2364
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002365static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
Liam Girdwood01d75842012-04-25 12:12:49 +01002366{
2367 struct snd_soc_pcm_runtime *fe = substream->private_data;
Ranjani Sridharan221f1412019-11-04 14:48:11 -08002368 int stream = substream->stream;
2369 int ret = 0;
Liam Girdwood01d75842012-04-25 12:12:49 +01002370 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
2371
2372 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
2373
2374 switch (trigger) {
2375 case SND_SOC_DPCM_TRIGGER_PRE:
Ranjani Sridharan221f1412019-11-04 14:48:11 -08002376 switch (cmd) {
2377 case SNDRV_PCM_TRIGGER_START:
2378 case SNDRV_PCM_TRIGGER_RESUME:
2379 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2380 ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
2381 break;
2382 case SNDRV_PCM_TRIGGER_STOP:
2383 case SNDRV_PCM_TRIGGER_SUSPEND:
2384 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2385 ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
2386 break;
2387 default:
2388 ret = -EINVAL;
2389 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002390 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002391 break;
2392 case SND_SOC_DPCM_TRIGGER_POST:
Ranjani Sridharan221f1412019-11-04 14:48:11 -08002393 switch (cmd) {
2394 case SNDRV_PCM_TRIGGER_START:
2395 case SNDRV_PCM_TRIGGER_RESUME:
2396 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2397 ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
2398 break;
2399 case SNDRV_PCM_TRIGGER_STOP:
2400 case SNDRV_PCM_TRIGGER_SUSPEND:
2401 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2402 ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
2403 break;
2404 default:
2405 ret = -EINVAL;
2406 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002407 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002408 break;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002409 case SND_SOC_DPCM_TRIGGER_BESPOKE:
2410 /* bespoke trigger() - handles both FE and BEs */
2411
Liam Girdwood103d84a2012-11-19 14:39:15 +00002412 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd %d\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002413 fe->dai_link->name, cmd);
2414
2415 ret = soc_pcm_bespoke_trigger(substream, cmd);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002416 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002417 default:
Liam Girdwood103d84a2012-11-19 14:39:15 +00002418 dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd,
Liam Girdwood01d75842012-04-25 12:12:49 +01002419 fe->dai_link->name);
2420 ret = -EINVAL;
2421 goto out;
2422 }
2423
Ranjani Sridharan221f1412019-11-04 14:48:11 -08002424 if (ret < 0) {
2425 dev_err(fe->dev, "ASoC: trigger FE cmd: %d failed: %d\n",
2426 cmd, ret);
2427 goto out;
2428 }
2429
Liam Girdwood01d75842012-04-25 12:12:49 +01002430 switch (cmd) {
2431 case SNDRV_PCM_TRIGGER_START:
2432 case SNDRV_PCM_TRIGGER_RESUME:
2433 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2434 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
2435 break;
2436 case SNDRV_PCM_TRIGGER_STOP:
2437 case SNDRV_PCM_TRIGGER_SUSPEND:
Liam Girdwood01d75842012-04-25 12:12:49 +01002438 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
2439 break;
Banajit Goswami6175bce2013-02-14 18:24:08 -08002440 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2441 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
2442 break;
Liam Girdwood01d75842012-04-25 12:12:49 +01002443 }
2444
2445out:
2446 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
2447 return ret;
2448}
2449
Banajit Goswami8886fb02016-11-21 21:39:54 -08002450int dpcm_fe_dai_prepare_be(struct snd_soc_pcm_runtime *fe,
2451 struct snd_soc_pcm_runtime *be, int stream)
2452{
2453 struct snd_pcm_substream *be_substream =
2454 snd_soc_dpcm_get_substream(be, stream);
2455 int ret = 0;
2456
2457 /* is this op for this BE ? */
2458 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2459 return 0;
2460
2461 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2462 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
2463 return 0;
2464
2465 dev_dbg(be->dev, "ASoC: prepare BE %s\n",
2466 fe->dai_link->name);
2467
2468 ret = soc_pcm_prepare(be_substream);
2469 if (ret < 0) {
2470 dev_err(be->dev, "ASoC: backend prepare failed %d\n",
2471 ret);
2472 return ret;
2473 }
2474
2475 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2476 return ret;
2477}
2478
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002479static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
2480{
2481 struct snd_soc_pcm_runtime *fe = substream->private_data;
2482 int stream = substream->stream;
2483
2484 /* if FE's runtime_update is already set, we're in race;
2485 * process this trigger later at exit
2486 */
2487 if (fe->dpcm[stream].runtime_update != SND_SOC_DPCM_UPDATE_NO) {
2488 fe->dpcm[stream].trigger_pending = cmd + 1;
2489 return 0; /* delayed, assuming it's successful */
2490 }
2491
2492 /* we're alone, let's trigger */
2493 return dpcm_fe_dai_do_trigger(substream, cmd);
2494}
2495
Liam Girdwood23607022014-01-17 17:03:55 +00002496int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002497{
2498 struct snd_soc_dpcm *dpcm;
2499 int ret = 0;
2500
2501 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
2502
2503 struct snd_soc_pcm_runtime *be = dpcm->be;
2504 struct snd_pcm_substream *be_substream =
2505 snd_soc_dpcm_get_substream(be, stream);
2506
2507 /* is this op for this BE ? */
2508 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2509 continue;
2510
2511 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
Koro Chen95f444d2015-10-28 10:15:34 +08002512 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
Libin Yang1166bec2019-05-08 10:32:41 +08002513 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND) &&
2514 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
Liam Girdwood01d75842012-04-25 12:12:49 +01002515 continue;
2516
Liam Girdwood103d84a2012-11-19 14:39:15 +00002517 dev_dbg(be->dev, "ASoC: prepare BE %s\n",
彭东林94d215c2016-09-26 08:29:31 +00002518 be->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002519
2520 ret = soc_pcm_prepare(be_substream);
2521 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002522 dev_err(be->dev, "ASoC: backend prepare failed %d\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002523 ret);
2524 break;
2525 }
2526
2527 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2528 }
2529 return ret;
2530}
2531
Banajit Goswami8886fb02016-11-21 21:39:54 -08002532static void dpcm_be_async_prepare(void *data, async_cookie_t cookie)
2533{
2534 struct snd_soc_dpcm *dpcm = data;
2535 struct snd_soc_pcm_runtime *be = dpcm->be;
2536 int stream = dpcm->stream;
2537 struct snd_pcm_substream *be_substream =
2538 snd_soc_dpcm_get_substream(be, stream);
2539 int ret;
2540
2541 dev_dbg(be->dev, "%s ASoC: prepare BE %s\n", __func__,
2542 dpcm->fe->dai_link->name);
2543 ret = soc_pcm_prepare(be_substream);
2544 if (ret < 0) {
2545 be->err_ops = ret;
2546 dev_err(be->dev, "ASoC: backend prepare failed %d\n",
2547 ret);
2548 return;
2549 }
2550 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2551}
2552
2553void dpcm_be_dai_prepare_async(struct snd_soc_pcm_runtime *fe, int stream,
2554 struct async_domain *domain)
2555{
2556 struct snd_soc_dpcm *dpcm;
2557 struct snd_soc_dpcm *dpcm_async[DPCM_MAX_BE_USERS];
2558 int i = 0, j;
2559
2560 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
2561 struct snd_soc_pcm_runtime *be = dpcm->be;
2562
2563 be->err_ops = 0;
2564 /* is this op for this BE ? */
2565 if (!snd_soc_dpcm_be_can_update(fe, be, stream))
2566 continue;
2567
2568 if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
2569 (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
2570 continue;
2571
2572 /* does this BE support async op ?*/
2573 if ((fe->dai_link->async_ops & ASYNC_DPCM_SND_SOC_PREPARE) &&
2574 (be->dai_link->async_ops & ASYNC_DPCM_SND_SOC_PREPARE)) {
2575 dpcm->stream = stream;
2576 async_schedule_domain(dpcm_be_async_prepare,
2577 dpcm, domain);
2578 } else {
2579 dpcm_async[i++] = dpcm;
Walter Yange0c24ee2017-03-02 12:13:34 +08002580 if (i == DPCM_MAX_BE_USERS) {
2581 dev_dbg(fe->dev, "ASoC: MAX backend users!\n");
2582 break;
2583 }
Banajit Goswami8886fb02016-11-21 21:39:54 -08002584 }
2585 }
2586
2587 for (j = 0; j < i; j++) {
2588 struct snd_soc_dpcm *dpcm = dpcm_async[j];
2589 struct snd_soc_pcm_runtime *be = dpcm->be;
2590 struct snd_pcm_substream *be_substream =
2591 snd_soc_dpcm_get_substream(be, stream);
2592 int ret;
2593
2594 dev_dbg(be->dev, "ASoC: prepare BE %s\n",
2595 dpcm->fe->dai_link->name);
2596
2597 ret = soc_pcm_prepare(be_substream);
2598 if (ret < 0) {
2599 dev_err(be->dev, "ASoC: backend prepare failed %d\n",
2600 ret);
2601 be->err_ops = ret;
2602 return;
2603 }
2604
2605 be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2606 }
2607}
2608
Mark Brown45c0a182012-05-09 21:46:27 +01002609static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002610{
2611 struct snd_soc_pcm_runtime *fe = substream->private_data;
Banajit Goswami8886fb02016-11-21 21:39:54 -08002612 struct snd_soc_dpcm *dpcm;
Liam Girdwood01d75842012-04-25 12:12:49 +01002613 int stream = substream->stream, ret = 0;
Banajit Goswami8886fb02016-11-21 21:39:54 -08002614 ASYNC_DOMAIN_EXCLUSIVE(async_domain);
Liam Girdwood01d75842012-04-25 12:12:49 +01002615
2616 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2617
Banajit Goswami8886fb02016-11-21 21:39:54 -08002618 fe->err_ops = 0;
2619
Liam Girdwood103d84a2012-11-19 14:39:15 +00002620 dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name);
Liam Girdwood01d75842012-04-25 12:12:49 +01002621
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002622 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
Liam Girdwood01d75842012-04-25 12:12:49 +01002623
2624 /* there is no point preparing this FE if there are no BEs */
2625 if (list_empty(&fe->dpcm[stream].be_clients)) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002626 dev_err(fe->dev, "ASoC: no backend DAIs enabled for %s\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01002627 fe->dai_link->name);
2628 ret = -EINVAL;
2629 goto out;
2630 }
2631
Banajit Goswami8886fb02016-11-21 21:39:54 -08002632 if (!(fe->dai_link->async_ops & ASYNC_DPCM_SND_SOC_PREPARE)) {
2633 ret = dpcm_be_dai_prepare(fe, substream->stream);
2634 if (ret < 0)
2635 goto out;
2636 /* call prepare on the frontend */
2637 ret = soc_pcm_prepare(substream);
2638 if (ret < 0) {
2639 dev_err(fe->dev, "ASoC: prepare FE %s failed\n",
2640 fe->dai_link->name);
2641 goto out;
2642 }
2643 } else {
2644 dpcm_be_dai_prepare_async(fe, substream->stream,
2645 &async_domain);
Liam Girdwood01d75842012-04-25 12:12:49 +01002646
Banajit Goswami8886fb02016-11-21 21:39:54 -08002647 /* call prepare on the frontend */
2648 ret = soc_pcm_prepare(substream);
2649 if (ret < 0) {
2650 fe->err_ops = ret;
2651 dev_err(fe->dev, "ASoC: prepare FE %s failed\n",
2652 fe->dai_link->name);
2653 }
2654
2655 async_synchronize_full_domain(&async_domain);
2656
2657 /* check if any BE failed */
2658 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients,
2659 list_be) {
2660 struct snd_soc_pcm_runtime *be = dpcm->be;
2661
2662 if (be->err_ops < 0) {
2663 ret = be->err_ops;
2664 goto out;
2665 }
2666 }
2667
2668 /* check if FE failed */
2669 if (fe->err_ops < 0) {
2670 ret = fe->err_ops;
2671 goto out;
2672 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002673 }
2674
2675 /* run the stream event for each BE */
2676 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
2677 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2678
2679out:
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002680 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood01d75842012-04-25 12:12:49 +01002681 mutex_unlock(&fe->card->mutex);
2682
2683 return ret;
2684}
2685
Gopikrishnaiah Anandbdc375e2014-05-30 11:29:56 -07002686static int soc_pcm_compat_ioctl(struct snd_pcm_substream *substream,
2687 unsigned int cmd, void *arg)
2688{
2689 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2690 struct snd_soc_platform *platform = rtd->platform;
2691
2692 if (platform->driver->ops->compat_ioctl)
2693 return platform->driver->ops->compat_ioctl(substream,
2694 cmd, arg);
2695 return snd_pcm_lib_ioctl(substream, cmd, arg);
2696}
2697
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01002698static int soc_pcm_ioctl(struct snd_pcm_substream *substream,
2699 unsigned int cmd, void *arg)
2700{
2701 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2702 struct snd_soc_platform *platform = rtd->platform;
2703
Mark Brownc5914b02013-10-30 17:47:39 -07002704 if (platform->driver->ops && platform->driver->ops->ioctl)
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01002705 return platform->driver->ops->ioctl(substream, cmd, arg);
2706 return snd_pcm_lib_ioctl(substream, cmd, arg);
2707}
2708
Liam Girdwood618dae12012-04-25 12:12:51 +01002709static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
2710{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002711 struct snd_pcm_substream *substream =
2712 snd_soc_dpcm_get_substream(fe, stream);
2713 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01002714 int err;
Liam Girdwood01d75842012-04-25 12:12:49 +01002715
Liam Girdwood103d84a2012-11-19 14:39:15 +00002716 dev_dbg(fe->dev, "ASoC: runtime %s close on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002717 stream ? "capture" : "playback", fe->dai_link->name);
2718
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002719 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2720 /* call bespoke trigger - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002721 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002722 fe->dai_link->name);
2723
2724 err = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
2725 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002726 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002727 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002728 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd stop\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002729 fe->dai_link->name);
2730
2731 err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
2732 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002733 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002734 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002735
2736 err = dpcm_be_dai_hw_free(fe, stream);
2737 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002738 dev_err(fe->dev,"ASoC: hw_free FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002739
2740 err = dpcm_be_dai_shutdown(fe, stream);
2741 if (err < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002742 dev_err(fe->dev,"ASoC: shutdown FE failed %d\n", err);
Liam Girdwood618dae12012-04-25 12:12:51 +01002743
2744 /* run the stream event for each BE */
2745 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2746
2747 return 0;
2748}
2749
2750static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
2751{
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002752 struct snd_pcm_substream *substream =
2753 snd_soc_dpcm_get_substream(fe, stream);
Liam Girdwood618dae12012-04-25 12:12:51 +01002754 struct snd_soc_dpcm *dpcm;
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002755 enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
Liam Girdwood618dae12012-04-25 12:12:51 +01002756 int ret;
2757
Liam Girdwood103d84a2012-11-19 14:39:15 +00002758 dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002759 stream ? "capture" : "playback", fe->dai_link->name);
2760
2761 /* Only start the BE if the FE is ready */
2762 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
2763 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE)
2764 return -EINVAL;
2765
2766 /* startup must always be called for new BEs */
2767 ret = dpcm_be_dai_startup(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002768 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002769 goto disconnect;
Liam Girdwood618dae12012-04-25 12:12:51 +01002770
2771 /* keep going if FE state is > open */
2772 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN)
2773 return 0;
2774
2775 ret = dpcm_be_dai_hw_params(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002776 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002777 goto close;
Liam Girdwood618dae12012-04-25 12:12:51 +01002778
2779 /* keep going if FE state is > hw_params */
2780 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS)
2781 return 0;
2782
2783
2784 ret = dpcm_be_dai_prepare(fe, stream);
Dan Carpenterfffc0ca2013-01-10 11:59:57 +03002785 if (ret < 0)
Liam Girdwood618dae12012-04-25 12:12:51 +01002786 goto hw_free;
Liam Girdwood618dae12012-04-25 12:12:51 +01002787
2788 /* run the stream event for each BE */
2789 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
2790
2791 /* keep going if FE state is > prepare */
2792 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE ||
2793 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP)
2794 return 0;
2795
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002796 if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
2797 /* call trigger on the frontend - FE takes care of all BE triggers */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002798 dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002799 fe->dai_link->name);
Liam Girdwood618dae12012-04-25 12:12:51 +01002800
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002801 ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
2802 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002803 dev_err(fe->dev,"ASoC: bespoke trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002804 goto hw_free;
2805 }
2806 } else {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002807 dev_dbg(fe->dev, "ASoC: trigger FE %s cmd start\n",
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002808 fe->dai_link->name);
2809
2810 ret = dpcm_be_dai_trigger(fe, stream,
2811 SNDRV_PCM_TRIGGER_START);
2812 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002813 dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
Liam Girdwood07bf84a2012-04-25 12:12:52 +01002814 goto hw_free;
2815 }
Liam Girdwood618dae12012-04-25 12:12:51 +01002816 }
2817
2818 return 0;
2819
2820hw_free:
2821 dpcm_be_dai_hw_free(fe, stream);
2822close:
2823 dpcm_be_dai_shutdown(fe, stream);
2824disconnect:
2825 /* disconnect any non started BEs */
2826 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
2827 struct snd_soc_pcm_runtime *be = dpcm->be;
2828 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
2829 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2830 }
2831
2832 return ret;
2833}
2834
2835static int dpcm_run_new_update(struct snd_soc_pcm_runtime *fe, int stream)
2836{
2837 int ret;
2838
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002839 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood618dae12012-04-25 12:12:51 +01002840 ret = dpcm_run_update_startup(fe, stream);
2841 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002842 dev_err(fe->dev, "ASoC: failed to startup some BEs\n");
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002843 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood618dae12012-04-25 12:12:51 +01002844
2845 return ret;
2846}
2847
2848static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream)
2849{
2850 int ret;
2851
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002852 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
Liam Girdwood618dae12012-04-25 12:12:51 +01002853 ret = dpcm_run_update_shutdown(fe, stream);
2854 if (ret < 0)
Liam Girdwood103d84a2012-11-19 14:39:15 +00002855 dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n");
Takashi Iwaiea9d0d72014-11-04 16:52:28 +01002856 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Liam Girdwood618dae12012-04-25 12:12:51 +01002857
2858 return ret;
2859}
2860
2861/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
2862 * any DAI links.
2863 */
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002864int soc_dpcm_runtime_update(struct snd_soc_card *card)
Liam Girdwood618dae12012-04-25 12:12:51 +01002865{
Mengdong Lin1a497982015-11-18 02:34:11 -05002866 struct snd_soc_pcm_runtime *fe;
2867 int old, new, paths;
Liam Girdwood618dae12012-04-25 12:12:51 +01002868
Liam Girdwood618dae12012-04-25 12:12:51 +01002869 mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Mengdong Lin1a497982015-11-18 02:34:11 -05002870 list_for_each_entry(fe, &card->rtd_list, list) {
Liam Girdwood618dae12012-04-25 12:12:51 +01002871 struct snd_soc_dapm_widget_list *list;
Liam Girdwood618dae12012-04-25 12:12:51 +01002872
2873 /* make sure link is FE */
2874 if (!fe->dai_link->dynamic)
2875 continue;
2876
2877 /* only check active links */
2878 if (!fe->cpu_dai->active)
2879 continue;
2880
2881 /* DAPM sync will call this to update DSP paths */
Liam Girdwood103d84a2012-11-19 14:39:15 +00002882 dev_dbg(fe->dev, "ASoC: DPCM runtime update for FE %s\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002883 fe->dai_link->name);
2884
2885 /* skip if FE doesn't have playback capability */
Qiao Zhou075207d2014-11-17 16:02:57 +08002886 if (!fe->cpu_dai->driver->playback.channels_min
2887 || !fe->codec_dai->driver->playback.channels_min)
2888 goto capture;
2889
2890 /* skip if FE isn't currently playing */
2891 if (!fe->cpu_dai->playback_active
2892 || !fe->codec_dai->playback_active)
Liam Girdwood618dae12012-04-25 12:12:51 +01002893 goto capture;
2894
2895 paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list);
2896 if (paths < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002897 dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002898 fe->dai_link->name, "playback");
2899 mutex_unlock(&card->mutex);
2900 return paths;
2901 }
2902
2903 /* update any new playback paths */
2904 new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 1);
2905 if (new) {
2906 dpcm_run_new_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
2907 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
2908 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
2909 }
2910
2911 /* update any old playback paths */
2912 old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 0);
2913 if (old) {
2914 dpcm_run_old_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
2915 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
2916 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
2917 }
2918
Qiao Zhou7ed9de72014-06-04 19:42:06 +08002919 dpcm_path_put(&list);
Liam Girdwood618dae12012-04-25 12:12:51 +01002920capture:
2921 /* skip if FE doesn't have capture capability */
Qiao Zhou075207d2014-11-17 16:02:57 +08002922 if (!fe->cpu_dai->driver->capture.channels_min
2923 || !fe->codec_dai->driver->capture.channels_min)
2924 continue;
2925
2926 /* skip if FE isn't currently capturing */
2927 if (!fe->cpu_dai->capture_active
2928 || !fe->codec_dai->capture_active)
Liam Girdwood618dae12012-04-25 12:12:51 +01002929 continue;
2930
2931 paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list);
2932 if (paths < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00002933 dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
Liam Girdwood618dae12012-04-25 12:12:51 +01002934 fe->dai_link->name, "capture");
2935 mutex_unlock(&card->mutex);
2936 return paths;
2937 }
2938
2939 /* update any new capture paths */
2940 new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 1);
2941 if (new) {
2942 dpcm_run_new_update(fe, SNDRV_PCM_STREAM_CAPTURE);
2943 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
2944 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
2945 }
2946
2947 /* update any old capture paths */
2948 old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 0);
2949 if (old) {
2950 dpcm_run_old_update(fe, SNDRV_PCM_STREAM_CAPTURE);
2951 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
2952 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
2953 }
2954
2955 dpcm_path_put(&list);
2956 }
2957
2958 mutex_unlock(&card->mutex);
2959 return 0;
2960}
Liam Girdwood01d75842012-04-25 12:12:49 +01002961int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute)
2962{
2963 struct snd_soc_dpcm *dpcm;
2964 struct list_head *clients =
2965 &fe->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients;
2966
2967 list_for_each_entry(dpcm, clients, list_be) {
2968
2969 struct snd_soc_pcm_runtime *be = dpcm->be;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002970 int i;
Liam Girdwood01d75842012-04-25 12:12:49 +01002971
2972 if (be->dai_link->ignore_suspend)
2973 continue;
2974
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002975 for (i = 0; i < be->num_codecs; i++) {
2976 struct snd_soc_dai *dai = be->codec_dais[i];
2977 struct snd_soc_dai_driver *drv = dai->driver;
Liam Girdwood01d75842012-04-25 12:12:49 +01002978
Benoit Cousson2e5894d2014-07-08 23:19:35 +02002979 dev_dbg(be->dev, "ASoC: BE digital mute %s\n",
2980 be->dai_link->name);
2981
2982 if (drv->ops && drv->ops->digital_mute &&
2983 dai->playback_active)
2984 drv->ops->digital_mute(dai, mute);
2985 }
Liam Girdwood01d75842012-04-25 12:12:49 +01002986 }
2987
2988 return 0;
2989}
2990
Mark Brown45c0a182012-05-09 21:46:27 +01002991static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01002992{
2993 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
2994 struct snd_soc_dpcm *dpcm;
2995 struct snd_soc_dapm_widget_list *list;
2996 int ret;
2997 int stream = fe_substream->stream;
2998
2999 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
3000 fe->dpcm[stream].runtime = fe_substream->runtime;
3001
Qiao Zhou8f70e512014-09-10 17:54:07 +08003002 ret = dpcm_path_get(fe, stream, &list);
3003 if (ret < 0) {
3004 mutex_unlock(&fe->card->mutex);
3005 return ret;
3006 } else if (ret == 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00003007 dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
Liam Girdwood01d75842012-04-25 12:12:49 +01003008 fe->dai_link->name, stream ? "capture" : "playback");
Liam Girdwood01d75842012-04-25 12:12:49 +01003009 }
3010
3011 /* calculate valid and active FE <-> BE dpcms */
3012 dpcm_process_paths(fe, stream, &list, 1);
3013
3014 ret = dpcm_fe_dai_startup(fe_substream);
3015 if (ret < 0) {
3016 /* clean up all links */
3017 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
3018 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
3019
3020 dpcm_be_disconnect(fe, stream);
3021 fe->dpcm[stream].runtime = NULL;
3022 }
3023
3024 dpcm_clear_pending_state(fe, stream);
3025 dpcm_path_put(&list);
3026 mutex_unlock(&fe->card->mutex);
3027 return ret;
3028}
3029
Mark Brown45c0a182012-05-09 21:46:27 +01003030static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
Liam Girdwood01d75842012-04-25 12:12:49 +01003031{
3032 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
3033 struct snd_soc_dpcm *dpcm;
3034 int stream = fe_substream->stream, ret;
3035
3036 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
3037 ret = dpcm_fe_dai_shutdown(fe_substream);
3038
3039 /* mark FE's links ready to prune */
3040 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
3041 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
3042
3043 dpcm_be_disconnect(fe, stream);
3044
3045 fe->dpcm[stream].runtime = NULL;
3046 mutex_unlock(&fe->card->mutex);
3047 return ret;
3048}
3049
Liam Girdwoodddee6272011-06-09 14:45:53 +01003050/* create a new pcm */
3051int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
3052{
Liam Girdwoodddee6272011-06-09 14:45:53 +01003053 struct snd_soc_platform *platform = rtd->platform;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02003054 struct snd_soc_dai *codec_dai;
Liam Girdwoodddee6272011-06-09 14:45:53 +01003055 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
3056 struct snd_pcm *pcm;
Banajit Goswami7ffe84e2017-01-10 17:28:14 -08003057 struct snd_pcm_str *stream;
Liam Girdwoodddee6272011-06-09 14:45:53 +01003058 char new_name[64];
3059 int ret = 0, playback = 0, capture = 0;
Benoit Cousson2e5894d2014-07-08 23:19:35 +02003060 int i;
Liam Girdwoodddee6272011-06-09 14:45:53 +01003061
Liam Girdwood01d75842012-04-25 12:12:49 +01003062 if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
Liam Girdwood1e9de422014-01-07 17:51:42 +00003063 playback = rtd->dai_link->dpcm_playback;
3064 capture = rtd->dai_link->dpcm_capture;
Liam Girdwood01d75842012-04-25 12:12:49 +01003065 } else {
Benoit Cousson2e5894d2014-07-08 23:19:35 +02003066 for (i = 0; i < rtd->num_codecs; i++) {
3067 codec_dai = rtd->codec_dais[i];
3068 if (codec_dai->driver->playback.channels_min)
3069 playback = 1;
3070 if (codec_dai->driver->capture.channels_min)
3071 capture = 1;
3072 }
3073
3074 capture = capture && cpu_dai->driver->capture.channels_min;
3075 playback = playback && cpu_dai->driver->playback.channels_min;
Liam Girdwood01d75842012-04-25 12:12:49 +01003076 }
Sangsu Parka5002312012-01-02 17:15:10 +09003077
Fabio Estevamd6bead02013-08-29 10:32:13 -03003078 if (rtd->dai_link->playback_only) {
3079 playback = 1;
3080 capture = 0;
3081 }
3082
3083 if (rtd->dai_link->capture_only) {
3084 playback = 0;
3085 capture = 1;
3086 }
3087
Liam Girdwood01d75842012-04-25 12:12:49 +01003088 /* create the PCM */
3089 if (rtd->dai_link->no_pcm) {
3090 snprintf(new_name, sizeof(new_name), "(%s)",
3091 rtd->dai_link->stream_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003092
Liam Girdwood01d75842012-04-25 12:12:49 +01003093 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
3094 playback, capture, &pcm);
3095 } else {
3096 if (rtd->dai_link->dynamic)
3097 snprintf(new_name, sizeof(new_name), "%s (*)",
3098 rtd->dai_link->stream_name);
3099 else
3100 snprintf(new_name, sizeof(new_name), "%s %s-%d",
Benoit Cousson2e5894d2014-07-08 23:19:35 +02003101 rtd->dai_link->stream_name,
3102 (rtd->num_codecs > 1) ?
3103 "multicodec" : rtd->codec_dai->name, num);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003104
Liam Girdwood01d75842012-04-25 12:12:49 +01003105 ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
3106 capture, &pcm);
3107 }
Liam Girdwoodddee6272011-06-09 14:45:53 +01003108 if (ret < 0) {
Liam Girdwood103d84a2012-11-19 14:39:15 +00003109 dev_err(rtd->card->dev, "ASoC: can't create pcm for %s\n",
Liam Girdwood5cb9b742012-07-06 16:54:52 +01003110 rtd->dai_link->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003111 return ret;
3112 }
Liam Girdwood103d84a2012-11-19 14:39:15 +00003113 dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003114
3115 /* DAPM dai link stream work */
3116 INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
3117
Vinod Koul48c76992015-02-12 09:59:53 +05303118 pcm->nonatomic = rtd->dai_link->nonatomic;
Liam Girdwoodddee6272011-06-09 14:45:53 +01003119 rtd->pcm = pcm;
3120 pcm->private_data = rtd;
Liam Girdwood01d75842012-04-25 12:12:49 +01003121
3122 if (rtd->dai_link->no_pcm) {
3123 if (playback)
3124 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
3125 if (capture)
3126 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
Banajit Goswamia19486b2016-11-21 17:54:51 -08003127 if (platform->driver->pcm_new)
3128 rtd->platform->driver->pcm_new(rtd);
Liam Girdwood01d75842012-04-25 12:12:49 +01003129 goto out;
3130 }
3131
Liam Girdwoodf5b50e72017-01-10 17:10:17 -08003132 /* setup any hostless PCMs - i.e. no host IO is performed */
3133 if (rtd->dai_link->no_host_mode) {
Banajit Goswami7ffe84e2017-01-10 17:28:14 -08003134 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
3135 stream = &pcm->streams[SNDRV_PCM_STREAM_PLAYBACK];
3136 stream->substream->hw_no_buffer = 1;
3137 snd_soc_set_runtime_hwparams(stream->substream,
3138 &no_host_hardware);
3139 }
3140 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
3141 stream = &pcm->streams[SNDRV_PCM_STREAM_CAPTURE];
3142 stream->substream->hw_no_buffer = 1;
3143 snd_soc_set_runtime_hwparams(stream->substream,
3144 &no_host_hardware);
3145 }
Liam Girdwoodf5b50e72017-01-10 17:10:17 -08003146 }
3147
Liam Girdwood01d75842012-04-25 12:12:49 +01003148 /* ASoC PCM operations */
3149 if (rtd->dai_link->dynamic) {
3150 rtd->ops.open = dpcm_fe_dai_open;
3151 rtd->ops.hw_params = dpcm_fe_dai_hw_params;
3152 rtd->ops.prepare = dpcm_fe_dai_prepare;
3153 rtd->ops.trigger = dpcm_fe_dai_trigger;
3154 rtd->ops.hw_free = dpcm_fe_dai_hw_free;
3155 rtd->ops.close = dpcm_fe_dai_close;
3156 rtd->ops.pointer = soc_pcm_pointer;
Kenneth Westfieldd6f99fa2015-05-19 12:03:55 -07003157 rtd->ops.delay_blk = soc_pcm_delay_blk;
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01003158 rtd->ops.ioctl = soc_pcm_ioctl;
Gopikrishnaiah Anandbdc375e2014-05-30 11:29:56 -07003159 rtd->ops.compat_ioctl = soc_pcm_compat_ioctl;
Liam Girdwood01d75842012-04-25 12:12:49 +01003160 } else {
3161 rtd->ops.open = soc_pcm_open;
3162 rtd->ops.hw_params = soc_pcm_hw_params;
3163 rtd->ops.prepare = soc_pcm_prepare;
3164 rtd->ops.trigger = soc_pcm_trigger;
3165 rtd->ops.hw_free = soc_pcm_hw_free;
3166 rtd->ops.close = soc_pcm_close;
3167 rtd->ops.pointer = soc_pcm_pointer;
Kenneth Westfieldd6f99fa2015-05-19 12:03:55 -07003168 rtd->ops.delay_blk = soc_pcm_delay_blk;
Liam Girdwoodbe3f3f22012-04-26 16:16:10 +01003169 rtd->ops.ioctl = soc_pcm_ioctl;
Gopikrishnaiah Anandbdc375e2014-05-30 11:29:56 -07003170 rtd->ops.compat_ioctl = soc_pcm_compat_ioctl;
Liam Girdwood01d75842012-04-25 12:12:49 +01003171 }
3172
Liam Girdwoodddee6272011-06-09 14:45:53 +01003173 if (platform->driver->ops) {
Liam Girdwood01d75842012-04-25 12:12:49 +01003174 rtd->ops.ack = platform->driver->ops->ack;
3175 rtd->ops.copy = platform->driver->ops->copy;
3176 rtd->ops.silence = platform->driver->ops->silence;
3177 rtd->ops.page = platform->driver->ops->page;
3178 rtd->ops.mmap = platform->driver->ops->mmap;
Liam Girdwoodddee6272011-06-09 14:45:53 +01003179 }
3180
3181 if (playback)
Liam Girdwood01d75842012-04-25 12:12:49 +01003182 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003183
3184 if (capture)
Liam Girdwood01d75842012-04-25 12:12:49 +01003185 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003186
3187 if (platform->driver->pcm_new) {
3188 ret = platform->driver->pcm_new(rtd);
3189 if (ret < 0) {
Mark Brownb1bc7b32012-09-26 14:25:17 +01003190 dev_err(platform->dev,
3191 "ASoC: pcm constructor failed: %d\n",
3192 ret);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003193 return ret;
3194 }
3195 }
3196
3197 pcm->private_free = platform->driver->pcm_free;
Liam Girdwood01d75842012-04-25 12:12:49 +01003198out:
Siena Richard45cbe862016-11-04 13:21:16 -07003199 dev_dbg(rtd->card->dev, "%s <-> %s mapping ok\n",
Benoit Cousson2e5894d2014-07-08 23:19:35 +02003200 (rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name,
3201 cpu_dai->name);
Liam Girdwoodddee6272011-06-09 14:45:53 +01003202 return ret;
3203}
Liam Girdwood01d75842012-04-25 12:12:49 +01003204
3205/* is the current PCM operation for this FE ? */
3206int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream)
3207{
3208 if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE)
3209 return 1;
3210 return 0;
3211}
3212EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update);
3213
3214/* is the current PCM operation for this BE ? */
3215int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
3216 struct snd_soc_pcm_runtime *be, int stream)
3217{
3218 if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) ||
3219 ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) &&
3220 be->dpcm[stream].runtime_update))
3221 return 1;
3222 return 0;
3223}
3224EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update);
3225
3226/* get the substream for this BE */
3227struct snd_pcm_substream *
3228 snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream)
3229{
3230 return be->pcm->streams[stream].substream;
3231}
3232EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream);
3233
3234/* get the BE runtime state */
3235enum snd_soc_dpcm_state
3236 snd_soc_dpcm_be_get_state(struct snd_soc_pcm_runtime *be, int stream)
3237{
3238 return be->dpcm[stream].state;
3239}
3240EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_get_state);
3241
3242/* set the BE runtime state */
3243void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be,
3244 int stream, enum snd_soc_dpcm_state state)
3245{
3246 be->dpcm[stream].state = state;
3247}
3248EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_set_state);
3249
3250/*
3251 * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE
3252 * are not running, paused or suspended for the specified stream direction.
3253 */
3254int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
3255 struct snd_soc_pcm_runtime *be, int stream)
3256{
3257 struct snd_soc_dpcm *dpcm;
3258 int state;
3259
3260 list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {
3261
3262 if (dpcm->fe == fe)
3263 continue;
3264
3265 state = dpcm->fe->dpcm[stream].state;
3266 if (state == SND_SOC_DPCM_STATE_START ||
3267 state == SND_SOC_DPCM_STATE_PAUSED ||
3268 state == SND_SOC_DPCM_STATE_SUSPEND)
3269 return 0;
3270 }
3271
3272 /* it's safe to free/stop this BE DAI */
3273 return 1;
3274}
3275EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop);
3276
3277/*
3278 * We can only change hw params a BE DAI if any of it's FE are not prepared,
3279 * running, paused or suspended for the specified stream direction.
3280 */
3281int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
3282 struct snd_soc_pcm_runtime *be, int stream)
3283{
3284 struct snd_soc_dpcm *dpcm;
3285 int state;
3286
3287 list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {
3288
3289 if (dpcm->fe == fe)
3290 continue;
3291
3292 state = dpcm->fe->dpcm[stream].state;
3293 if (state == SND_SOC_DPCM_STATE_START ||
3294 state == SND_SOC_DPCM_STATE_PAUSED ||
3295 state == SND_SOC_DPCM_STATE_SUSPEND ||
3296 state == SND_SOC_DPCM_STATE_PREPARE)
3297 return 0;
3298 }
3299
3300 /* it's safe to change hw_params */
3301 return 1;
3302}
3303EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003304
Liam Girdwood07bf84a2012-04-25 12:12:52 +01003305int snd_soc_platform_trigger(struct snd_pcm_substream *substream,
3306 int cmd, struct snd_soc_platform *platform)
3307{
Mark Brownc5914b02013-10-30 17:47:39 -07003308 if (platform->driver->ops && platform->driver->ops->trigger)
Liam Girdwood07bf84a2012-04-25 12:12:52 +01003309 return platform->driver->ops->trigger(substream, cmd);
3310 return 0;
3311}
3312EXPORT_SYMBOL_GPL(snd_soc_platform_trigger);
3313
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003314#ifdef CONFIG_DEBUG_FS
3315static char *dpcm_state_string(enum snd_soc_dpcm_state state)
3316{
3317 switch (state) {
3318 case SND_SOC_DPCM_STATE_NEW:
3319 return "new";
3320 case SND_SOC_DPCM_STATE_OPEN:
3321 return "open";
3322 case SND_SOC_DPCM_STATE_HW_PARAMS:
3323 return "hw_params";
3324 case SND_SOC_DPCM_STATE_PREPARE:
3325 return "prepare";
3326 case SND_SOC_DPCM_STATE_START:
3327 return "start";
3328 case SND_SOC_DPCM_STATE_STOP:
3329 return "stop";
3330 case SND_SOC_DPCM_STATE_SUSPEND:
3331 return "suspend";
3332 case SND_SOC_DPCM_STATE_PAUSED:
3333 return "paused";
3334 case SND_SOC_DPCM_STATE_HW_FREE:
3335 return "hw_free";
3336 case SND_SOC_DPCM_STATE_CLOSE:
3337 return "close";
3338 }
3339
3340 return "unknown";
3341}
3342
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003343static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
3344 int stream, char *buf, size_t size)
3345{
3346 struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params;
3347 struct snd_soc_dpcm *dpcm;
3348 ssize_t offset = 0;
3349
3350 /* FE state */
Takashi Iwai4ba52d02020-02-18 12:17:37 +01003351 offset += scnprintf(buf + offset, size - offset,
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003352 "[%s - %s]\n", fe->dai_link->name,
3353 stream ? "Capture" : "Playback");
3354
Takashi Iwai4ba52d02020-02-18 12:17:37 +01003355 offset += scnprintf(buf + offset, size - offset, "State: %s\n",
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003356 dpcm_state_string(fe->dpcm[stream].state));
3357
3358 if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
3359 (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
Takashi Iwai4ba52d02020-02-18 12:17:37 +01003360 offset += scnprintf(buf + offset, size - offset,
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003361 "Hardware Params: "
3362 "Format = %s, Channels = %d, Rate = %d\n",
3363 snd_pcm_format_name(params_format(params)),
3364 params_channels(params),
3365 params_rate(params));
3366
3367 /* BEs state */
Takashi Iwai4ba52d02020-02-18 12:17:37 +01003368 offset += scnprintf(buf + offset, size - offset, "Backends:\n");
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003369
3370 if (list_empty(&fe->dpcm[stream].be_clients)) {
Takashi Iwai4ba52d02020-02-18 12:17:37 +01003371 offset += scnprintf(buf + offset, size - offset,
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003372 " No active DSP links\n");
3373 goto out;
3374 }
3375
3376 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
3377 struct snd_soc_pcm_runtime *be = dpcm->be;
3378 params = &dpcm->hw_params;
3379
Takashi Iwai4ba52d02020-02-18 12:17:37 +01003380 offset += scnprintf(buf + offset, size - offset,
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003381 "- %s\n", be->dai_link->name);
3382
Takashi Iwai4ba52d02020-02-18 12:17:37 +01003383 offset += scnprintf(buf + offset, size - offset,
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003384 " State: %s\n",
3385 dpcm_state_string(be->dpcm[stream].state));
3386
3387 if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
3388 (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
Takashi Iwai4ba52d02020-02-18 12:17:37 +01003389 offset += scnprintf(buf + offset, size - offset,
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003390 " Hardware Params: "
3391 "Format = %s, Channels = %d, Rate = %d\n",
3392 snd_pcm_format_name(params_format(params)),
3393 params_channels(params),
3394 params_rate(params));
3395 }
3396
3397out:
3398 return offset;
3399}
3400
3401static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf,
3402 size_t count, loff_t *ppos)
3403{
3404 struct snd_soc_pcm_runtime *fe = file->private_data;
3405 ssize_t out_count = PAGE_SIZE, offset = 0, ret = 0;
3406 char *buf;
3407
3408 buf = kmalloc(out_count, GFP_KERNEL);
3409 if (!buf)
3410 return -ENOMEM;
3411
3412 if (fe->cpu_dai->driver->playback.channels_min)
3413 offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_PLAYBACK,
3414 buf + offset, out_count - offset);
3415
3416 if (fe->cpu_dai->driver->capture.channels_min)
3417 offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_CAPTURE,
3418 buf + offset, out_count - offset);
3419
Liam Girdwoodf57b8482012-04-27 11:33:46 +01003420 ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003421
Liam Girdwoodf57b8482012-04-27 11:33:46 +01003422 kfree(buf);
3423 return ret;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003424}
3425
3426static const struct file_operations dpcm_state_fops = {
Liam Girdwoodf57b8482012-04-27 11:33:46 +01003427 .open = simple_open,
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003428 .read = dpcm_state_read_file,
3429 .llseek = default_llseek,
3430};
3431
Lars-Peter Clausen2e55b902015-04-09 10:52:37 +02003432void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003433{
Mark Brownb3bba9a2012-05-08 10:33:47 +01003434 if (!rtd->dai_link)
Lars-Peter Clausen2e55b902015-04-09 10:52:37 +02003435 return;
Mark Brownb3bba9a2012-05-08 10:33:47 +01003436
Lars-Peter Clausen6553bf062015-04-09 10:52:38 +02003437 if (!rtd->card->debugfs_card_root)
3438 return;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003439
3440 rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name,
3441 rtd->card->debugfs_card_root);
3442 if (!rtd->debugfs_dpcm_root) {
3443 dev_dbg(rtd->dev,
3444 "ASoC: Failed to create dpcm debugfs directory %s\n",
3445 rtd->dai_link->name);
Lars-Peter Clausen2e55b902015-04-09 10:52:37 +02003446 return;
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003447 }
3448
Liam Girdwoodf57b8482012-04-27 11:33:46 +01003449 rtd->debugfs_dpcm_state = debugfs_create_file("state", 0444,
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003450 rtd->debugfs_dpcm_root,
3451 rtd, &dpcm_state_fops);
Liam Girdwoodf86dcef2012-04-25 12:12:50 +01003452}
3453#endif