blob: 4984b6a2c3708789b0646bf3f6cd77b270ced1b7 [file] [log] [blame]
Kuninori Morimotob3ed4c82018-07-02 06:24:57 +00001// SPDX-License-Identifier: GPL-2.0+
2//
3// soc-compress.c -- ALSA SoC Compress
4//
5// Copyright (C) 2012 Intel Corp.
6//
7// Authors: Namarta Kohli <namartax.kohli@intel.com>
8// Ramesh Babu K V <ramesh.babu@linux.intel.com>
9// Vinod Koul <vinod.koul@linux.intel.com>
Namarta Kohli1245b702012-08-16 17:10:41 +053010
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/delay.h>
14#include <linux/slab.h>
15#include <linux/workqueue.h>
16#include <sound/core.h>
17#include <sound/compress_params.h>
18#include <sound/compress_driver.h>
19#include <sound/soc.h>
20#include <sound/initval.h>
Liam Girdwood2a99ef02014-01-17 17:03:56 +000021#include <sound/soc-dpcm.h>
Kuninori Morimoto9ab711c2020-05-25 09:57:41 +090022#include <sound/soc-link.h>
Cezary Rojewski4137f4b2019-12-17 10:58:50 +010023#include <linux/pm_runtime.h>
Namarta Kohli1245b702012-08-16 17:10:41 +053024
Charles Keepax1e57b822018-04-24 16:39:03 +010025static int soc_compr_components_open(struct snd_compr_stream *cstream,
26 struct snd_soc_component **last)
Namarta Kohli1245b702012-08-16 17:10:41 +053027{
28 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +000029 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +090030 int i, ret;
Charles Keepax1e57b822018-04-24 16:39:03 +010031
Kuninori Morimoto613fb502020-01-10 11:35:21 +090032 for_each_rtd_components(rtd, i, component) {
Kuninori Morimotoc6cb5222020-04-20 16:07:50 +090033 if (!component->driver->compress_ops ||
34 !component->driver->compress_ops->open)
35 continue;
36
37 ret = component->driver->compress_ops->open(component, cstream);
38 if (ret < 0) {
39 dev_err(component->dev,
40 "Compress ASoC: can't open platform %s: %d\n",
41 component->name, ret);
42
43 *last = component;
44 return ret;
45 }
46 }
47
Charles Keepax1e57b822018-04-24 16:39:03 +010048 *last = NULL;
49 return 0;
50}
51
52static int soc_compr_components_free(struct snd_compr_stream *cstream,
53 struct snd_soc_component *last)
54{
55 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
56 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +090057 int i;
Charles Keepax1e57b822018-04-24 16:39:03 +010058
Kuninori Morimoto613fb502020-01-10 11:35:21 +090059 for_each_rtd_components(rtd, i, component) {
Charles Keepax1e57b822018-04-24 16:39:03 +010060 if (component == last)
61 break;
62
Kuninori Morimotoc6cb5222020-04-20 16:07:50 +090063 if (!component->driver->compress_ops ||
64 !component->driver->compress_ops->free)
65 continue;
66
67 component->driver->compress_ops->free(component, cstream);
68 }
69
Charles Keepax1e57b822018-04-24 16:39:03 +010070 return 0;
71}
72
73static int soc_compr_open(struct snd_compr_stream *cstream)
74{
75 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Rong Chen3e645a42020-04-24 08:54:37 +080076 struct snd_soc_component *component = NULL, *save = NULL;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +090077 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Kuninori Morimoto613fb502020-01-10 11:35:21 +090078 int ret, i;
Namarta Kohli1245b702012-08-16 17:10:41 +053079
Kuninori Morimoto613fb502020-01-10 11:35:21 +090080 for_each_rtd_components(rtd, i, component) {
Cezary Rojewski4137f4b2019-12-17 10:58:50 +010081 ret = pm_runtime_get_sync(component->dev);
82 if (ret < 0 && ret != -EACCES) {
83 pm_runtime_put_noidle(component->dev);
84 save = component;
85 goto pm_err;
86 }
87 }
88
Peter Ujfalusi72b745e2019-08-13 13:45:32 +030089 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax15e2e612013-01-24 09:44:29 +000090
Kuninori Morimotob5ae4cc2020-04-24 08:15:24 +090091 ret = snd_soc_dai_compr_startup(cpu_dai, cstream);
92 if (ret < 0)
93 goto out;
Vinod Koul2e622ae2016-11-13 12:10:02 +053094
Charles Keepax1e57b822018-04-24 16:39:03 +010095 ret = soc_compr_components_open(cstream, &component);
96 if (ret < 0)
97 goto machine_err;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +000098
Kuninori Morimoto9ab711c2020-05-25 09:57:41 +090099 ret = snd_soc_link_compr_startup(cstream);
100 if (ret < 0)
101 goto machine_err;
Namarta Kohli1245b702012-08-16 17:10:41 +0530102
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100103 snd_soc_runtime_activate(rtd, cstream->direction);
Namarta Kohli1245b702012-08-16 17:10:41 +0530104
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300105 mutex_unlock(&rtd->card->pcm_mutex);
Charles Keepax15e2e612013-01-24 09:44:29 +0000106
Namarta Kohli1245b702012-08-16 17:10:41 +0530107 return 0;
108
109machine_err:
Charles Keepax1e57b822018-04-24 16:39:03 +0100110 soc_compr_components_free(cstream, component);
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000111
Kuninori Morimoto2b25f812020-04-24 08:15:28 +0900112 snd_soc_dai_compr_shutdown(cpu_dai, cstream);
Namarta Kohli1245b702012-08-16 17:10:41 +0530113out:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300114 mutex_unlock(&rtd->card->pcm_mutex);
Cezary Rojewski4137f4b2019-12-17 10:58:50 +0100115pm_err:
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900116 for_each_rtd_components(rtd, i, component) {
Cezary Rojewski4137f4b2019-12-17 10:58:50 +0100117 if (component == save)
118 break;
119 pm_runtime_mark_last_busy(component->dev);
120 pm_runtime_put_autosuspend(component->dev);
121 }
122
Namarta Kohli1245b702012-08-16 17:10:41 +0530123 return ret;
124}
125
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000126static int soc_compr_open_fe(struct snd_compr_stream *cstream)
127{
128 struct snd_soc_pcm_runtime *fe = cstream->private_data;
Satish Babu Patakokila01b8ced2017-06-16 17:33:40 -0700129 struct snd_pcm_substream *fe_substream =
130 fe->pcm->streams[cstream->direction].substream;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000131 struct snd_soc_component *component;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900132 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000133 struct snd_soc_dpcm *dpcm;
134 struct snd_soc_dapm_widget_list *list;
135 int stream;
Charles Keepax572e6c82018-04-24 16:39:01 +0100136 int ret;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000137
138 if (cstream->direction == SND_COMPRESS_PLAYBACK)
139 stream = SNDRV_PCM_STREAM_PLAYBACK;
140 else
141 stream = SNDRV_PCM_STREAM_CAPTURE;
142
143 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Srinivas Kandagatla0b0722e2018-08-03 13:30:03 +0100144 fe->dpcm[stream].runtime = fe_substream->runtime;
145
146 ret = dpcm_path_get(fe, stream, &list);
147 if (ret < 0)
148 goto be_err;
149 else if (ret == 0)
150 dev_dbg(fe->dev, "Compress ASoC: %s no valid %s route\n",
151 fe->dai_link->name, stream ? "capture" : "playback");
152 /* calculate valid and active FE <-> BE dpcms */
153 dpcm_process_paths(fe, stream, &list, 1);
154 fe->dpcm[stream].runtime = fe_substream->runtime;
155
156 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
157
158 ret = dpcm_be_dai_startup(fe, stream);
159 if (ret < 0) {
160 /* clean up all links */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +0000161 for_each_dpcm_be(fe, stream, dpcm)
Srinivas Kandagatla0b0722e2018-08-03 13:30:03 +0100162 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
163
164 dpcm_be_disconnect(fe, stream);
165 fe->dpcm[stream].runtime = NULL;
166 goto out;
167 }
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000168
Kuninori Morimotob5ae4cc2020-04-24 08:15:24 +0900169 ret = snd_soc_dai_compr_startup(cpu_dai, cstream);
170 if (ret < 0)
171 goto out;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530172
Charles Keepax1e57b822018-04-24 16:39:03 +0100173 ret = soc_compr_components_open(cstream, &component);
174 if (ret < 0)
Srinivas Kandagatla0b0722e2018-08-03 13:30:03 +0100175 goto open_err;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000176
Kuninori Morimoto9ab711c2020-05-25 09:57:41 +0900177 ret = snd_soc_link_compr_startup(cstream);
178 if (ret < 0)
179 goto machine_err;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000180
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000181 dpcm_clear_pending_state(fe, stream);
182 dpcm_path_put(&list);
183
184 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
185 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
186
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100187 snd_soc_runtime_activate(fe, stream);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000188
189 mutex_unlock(&fe->card->mutex);
190
191 return 0;
192
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000193machine_err:
Charles Keepax1e57b822018-04-24 16:39:03 +0100194 soc_compr_components_free(cstream, component);
Srinivas Kandagatla0b0722e2018-08-03 13:30:03 +0100195open_err:
Kuninori Morimoto2b25f812020-04-24 08:15:28 +0900196 snd_soc_dai_compr_shutdown(cpu_dai, cstream);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000197out:
Srinivas Kandagatla0b0722e2018-08-03 13:30:03 +0100198 dpcm_path_put(&list);
199be_err:
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000200 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
201 mutex_unlock(&fe->card->mutex);
202 return ret;
203}
204
Namarta Kohli1245b702012-08-16 17:10:41 +0530205static int soc_compr_free(struct snd_compr_stream *cstream)
206{
207 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Cezary Rojewski4137f4b2019-12-17 10:58:50 +0100208 struct snd_soc_component *component;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900209 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
210 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900211 int stream, i;
Namarta Kohli1245b702012-08-16 17:10:41 +0530212
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300213 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax15e2e612013-01-24 09:44:29 +0000214
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100215 if (cstream->direction == SND_COMPRESS_PLAYBACK)
216 stream = SNDRV_PCM_STREAM_PLAYBACK;
217 else
218 stream = SNDRV_PCM_STREAM_CAPTURE;
219
220 snd_soc_runtime_deactivate(rtd, stream);
Namarta Kohli1245b702012-08-16 17:10:41 +0530221
Mark Brownda183962013-02-06 15:44:07 +0000222 snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
223
Kuninori Morimotob3dea622020-05-15 09:46:51 +0900224 if (!snd_soc_dai_active(cpu_dai))
Namarta Kohli1245b702012-08-16 17:10:41 +0530225 cpu_dai->rate = 0;
226
Kuninori Morimotob3dea622020-05-15 09:46:51 +0900227 if (!snd_soc_dai_active(codec_dai))
Namarta Kohli1245b702012-08-16 17:10:41 +0530228 codec_dai->rate = 0;
229
Kuninori Morimoto0e532c92020-05-25 09:57:45 +0900230 snd_soc_link_compr_shutdown(cstream);
Namarta Kohli1245b702012-08-16 17:10:41 +0530231
Charles Keepax1e57b822018-04-24 16:39:03 +0100232 soc_compr_components_free(cstream, NULL);
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000233
Kuninori Morimoto2b25f812020-04-24 08:15:28 +0900234 snd_soc_dai_compr_shutdown(cpu_dai, cstream);
Vinod Koul2e622ae2016-11-13 12:10:02 +0530235
Kuninori Morimoto3f4cf792020-01-10 11:36:23 +0900236 snd_soc_dapm_stream_stop(rtd, stream);
Namarta Kohli1245b702012-08-16 17:10:41 +0530237
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300238 mutex_unlock(&rtd->card->pcm_mutex);
Cezary Rojewski4137f4b2019-12-17 10:58:50 +0100239
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900240 for_each_rtd_components(rtd, i, component) {
Cezary Rojewski4137f4b2019-12-17 10:58:50 +0100241 pm_runtime_mark_last_busy(component->dev);
242 pm_runtime_put_autosuspend(component->dev);
243 }
244
Namarta Kohli1245b702012-08-16 17:10:41 +0530245 return 0;
246}
247
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000248static int soc_compr_free_fe(struct snd_compr_stream *cstream)
249{
250 struct snd_soc_pcm_runtime *fe = cstream->private_data;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900251 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000252 struct snd_soc_dpcm *dpcm;
253 int stream, ret;
254
255 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
256
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100257 if (cstream->direction == SND_COMPRESS_PLAYBACK)
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000258 stream = SNDRV_PCM_STREAM_PLAYBACK;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100259 else
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000260 stream = SNDRV_PCM_STREAM_CAPTURE;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000261
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100262 snd_soc_runtime_deactivate(fe, stream);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000263
264 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
265
266 ret = dpcm_be_dai_hw_free(fe, stream);
267 if (ret < 0)
Charles Keepax141dfc92018-01-26 13:08:45 +0000268 dev_err(fe->dev, "Compressed ASoC: hw_free failed: %d\n", ret);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000269
270 ret = dpcm_be_dai_shutdown(fe, stream);
271
272 /* mark FE's links ready to prune */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +0000273 for_each_dpcm_be(fe, stream, dpcm)
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000274 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
275
Kuninori Morimoto1c531232020-02-21 10:25:18 +0900276 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000277
278 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
279 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
280
281 dpcm_be_disconnect(fe, stream);
282
283 fe->dpcm[stream].runtime = NULL;
284
Kuninori Morimoto0e532c92020-05-25 09:57:45 +0900285 snd_soc_link_compr_shutdown(cstream);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000286
Charles Keepax1e57b822018-04-24 16:39:03 +0100287 soc_compr_components_free(cstream, NULL);
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000288
Kuninori Morimoto2b25f812020-04-24 08:15:28 +0900289 snd_soc_dai_compr_shutdown(cpu_dai, cstream);
Vinod Koul2e622ae2016-11-13 12:10:02 +0530290
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000291 mutex_unlock(&fe->card->mutex);
292 return 0;
293}
294
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000295static int soc_compr_components_trigger(struct snd_compr_stream *cstream,
296 int cmd)
Namarta Kohli1245b702012-08-16 17:10:41 +0530297{
Namarta Kohli1245b702012-08-16 17:10:41 +0530298 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000299 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900300 int i, ret;
Charles Keepax15e2e612013-01-24 09:44:29 +0000301
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900302 for_each_rtd_components(rtd, i, component) {
Kuninori Morimotoc6cb5222020-04-20 16:07:50 +0900303 if (!component->driver->compress_ops ||
304 !component->driver->compress_ops->trigger)
305 continue;
306
307 ret = component->driver->compress_ops->trigger(
308 component, cstream, cmd);
309 if (ret < 0)
310 return ret;
311 }
312
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000313 return 0;
314}
315
316static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
317{
318 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900319 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
320 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000321 int ret;
322
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300323 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000324
325 ret = soc_compr_components_trigger(cstream, cmd);
326 if (ret < 0)
327 goto out;
328
Kuninori Morimotoeb084112020-04-24 08:15:32 +0900329 ret = snd_soc_dai_compr_trigger(cpu_dai, cstream, cmd);
330 if (ret < 0)
331 goto out;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530332
Mark Brownda183962013-02-06 15:44:07 +0000333 switch (cmd) {
334 case SNDRV_PCM_TRIGGER_START:
335 snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction);
336 break;
337 case SNDRV_PCM_TRIGGER_STOP:
338 snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
339 break;
Mark Browne38b9b72013-02-06 13:52:42 +0000340 }
Namarta Kohli1245b702012-08-16 17:10:41 +0530341
Charles Keepax15e2e612013-01-24 09:44:29 +0000342out:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300343 mutex_unlock(&rtd->card->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530344 return ret;
345}
346
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000347static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
348{
349 struct snd_soc_pcm_runtime *fe = cstream->private_data;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900350 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
Charles Keepax52cadf12019-02-05 11:18:12 +0000351 int ret, stream;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000352
353 if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN ||
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000354 cmd == SND_COMPR_TRIGGER_DRAIN)
355 return soc_compr_components_trigger(cstream, cmd);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000356
357 if (cstream->direction == SND_COMPRESS_PLAYBACK)
358 stream = SNDRV_PCM_STREAM_PLAYBACK;
359 else
360 stream = SNDRV_PCM_STREAM_CAPTURE;
361
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000362 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
363
Kuninori Morimotoeb084112020-04-24 08:15:32 +0900364 ret = snd_soc_dai_compr_trigger(cpu_dai, cstream, cmd);
365 if (ret < 0)
366 goto out;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530367
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000368 ret = soc_compr_components_trigger(cstream, cmd);
369 if (ret < 0)
370 goto out;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000371
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000372 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
373
374 ret = dpcm_be_dai_trigger(fe, stream, cmd);
375
376 switch (cmd) {
377 case SNDRV_PCM_TRIGGER_START:
378 case SNDRV_PCM_TRIGGER_RESUME:
379 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
380 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
381 break;
382 case SNDRV_PCM_TRIGGER_STOP:
383 case SNDRV_PCM_TRIGGER_SUSPEND:
384 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
385 break;
386 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
387 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
388 break;
389 }
390
391out:
392 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
393 mutex_unlock(&fe->card->mutex);
394 return ret;
395}
396
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000397static int soc_compr_components_set_params(struct snd_compr_stream *cstream,
398 struct snd_compr_params *params)
Namarta Kohli1245b702012-08-16 17:10:41 +0530399{
400 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000401 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900402 int i, ret;
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000403
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900404 for_each_rtd_components(rtd, i, component) {
Kuninori Morimotoc6cb5222020-04-20 16:07:50 +0900405 if (!component->driver->compress_ops ||
406 !component->driver->compress_ops->set_params)
407 continue;
408
409 ret = component->driver->compress_ops->set_params(
410 component, cstream, params);
411 if (ret < 0)
412 return ret;
413 }
414
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000415 return 0;
416}
417
418static int soc_compr_set_params(struct snd_compr_stream *cstream,
419 struct snd_compr_params *params)
420{
421 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900422 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Charles Keepax52cadf12019-02-05 11:18:12 +0000423 int ret;
Namarta Kohli1245b702012-08-16 17:10:41 +0530424
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300425 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax15e2e612013-01-24 09:44:29 +0000426
Charles Keepaxef050be2018-04-24 16:39:02 +0100427 /*
428 * First we call set_params for the CPU DAI, then the component
429 * driver this should configure the SoC side. If the machine has
430 * compressed ops then we call that as well. The expectation is
431 * that these callbacks will configure everything for this compress
432 * path, like configuring a PCM port for a CODEC.
Namarta Kohli1245b702012-08-16 17:10:41 +0530433 */
Kuninori Morimoto8dfedaf2020-04-24 08:15:36 +0900434 ret = snd_soc_dai_compr_set_params(cpu_dai, cstream, params);
435 if (ret < 0)
436 goto err;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530437
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000438 ret = soc_compr_components_set_params(cstream, params);
439 if (ret < 0)
440 goto err;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000441
Kuninori Morimotoeab810f2020-05-25 09:57:50 +0900442 ret = snd_soc_link_compr_set_params(cstream);
443 if (ret < 0)
444 goto err;
Namarta Kohli1245b702012-08-16 17:10:41 +0530445
Charles Keepax2c071ed2013-05-20 08:33:54 +0100446 if (cstream->direction == SND_COMPRESS_PLAYBACK)
447 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
Charles Keepax89027d92018-04-26 17:30:07 +0100448 SND_SOC_DAPM_STREAM_START);
Charles Keepax2c071ed2013-05-20 08:33:54 +0100449 else
450 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
Charles Keepax89027d92018-04-26 17:30:07 +0100451 SND_SOC_DAPM_STREAM_START);
Namarta Kohli1245b702012-08-16 17:10:41 +0530452
Charles Keepaxfa40ef22013-03-27 16:39:01 +0000453 /* cancel any delayed stream shutdown that is pending */
454 rtd->pop_wait = 0;
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300455 mutex_unlock(&rtd->card->pcm_mutex);
Charles Keepaxfa40ef22013-03-27 16:39:01 +0000456
457 cancel_delayed_work_sync(&rtd->delayed_work);
458
Charles Keepax52cadf12019-02-05 11:18:12 +0000459 return 0;
Charles Keepaxfa40ef22013-03-27 16:39:01 +0000460
461err:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300462 mutex_unlock(&rtd->card->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530463 return ret;
464}
465
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000466static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
Charles Keepax89027d92018-04-26 17:30:07 +0100467 struct snd_compr_params *params)
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000468{
469 struct snd_soc_pcm_runtime *fe = cstream->private_data;
Satish Babu Patakokila01b8ced2017-06-16 17:33:40 -0700470 struct snd_pcm_substream *fe_substream =
471 fe->pcm->streams[cstream->direction].substream;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900472 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
Charles Keepax52cadf12019-02-05 11:18:12 +0000473 int ret, stream;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000474
475 if (cstream->direction == SND_COMPRESS_PLAYBACK)
476 stream = SNDRV_PCM_STREAM_PLAYBACK;
477 else
478 stream = SNDRV_PCM_STREAM_CAPTURE;
479
480 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
481
Srinivas Kandagatla0b0722e2018-08-03 13:30:03 +0100482 /*
483 * Create an empty hw_params for the BE as the machine driver must
484 * fix this up to match DSP decoder and ASRC configuration.
485 * I.e. machine driver fixup for compressed BE is mandatory.
486 */
487 memset(&fe->dpcm[fe_substream->stream].hw_params, 0,
488 sizeof(struct snd_pcm_hw_params));
489
490 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
491
492 ret = dpcm_be_dai_hw_params(fe, stream);
493 if (ret < 0)
494 goto out;
495
496 ret = dpcm_be_dai_prepare(fe, stream);
497 if (ret < 0)
498 goto out;
499
Kuninori Morimoto8dfedaf2020-04-24 08:15:36 +0900500 ret = snd_soc_dai_compr_set_params(cpu_dai, cstream, params);
501 if (ret < 0)
502 goto out;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530503
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000504 ret = soc_compr_components_set_params(cstream, params);
505 if (ret < 0)
506 goto out;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000507
Kuninori Morimotoeab810f2020-05-25 09:57:50 +0900508 ret = snd_soc_link_compr_set_params(cstream);
509 if (ret < 0)
510 goto out;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000511
Daniel Mack15f6b092014-10-19 09:07:35 +0200512 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000513 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
514
515out:
516 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
517 mutex_unlock(&fe->card->mutex);
518 return ret;
519}
520
Namarta Kohli1245b702012-08-16 17:10:41 +0530521static int soc_compr_get_params(struct snd_compr_stream *cstream,
Charles Keepax89027d92018-04-26 17:30:07 +0100522 struct snd_codec *params)
Namarta Kohli1245b702012-08-16 17:10:41 +0530523{
524 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000525 struct snd_soc_component *component;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900526 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900527 int i, ret = 0;
Namarta Kohli1245b702012-08-16 17:10:41 +0530528
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300529 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax15e2e612013-01-24 09:44:29 +0000530
Kuninori Morimotoadbef5432020-04-24 08:15:40 +0900531 ret = snd_soc_dai_compr_get_params(cpu_dai, cstream, params);
532 if (ret < 0)
533 goto err;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530534
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900535 for_each_rtd_components(rtd, i, component) {
Kuninori Morimotoc6cb5222020-04-20 16:07:50 +0900536 if (!component->driver->compress_ops ||
537 !component->driver->compress_ops->get_params)
538 continue;
539
540 ret = component->driver->compress_ops->get_params(
541 component, cstream, params);
542 break;
543 }
544
Vinod Koul2e622ae2016-11-13 12:10:02 +0530545err:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300546 mutex_unlock(&rtd->card->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530547 return ret;
548}
549
550static int soc_compr_get_caps(struct snd_compr_stream *cstream,
Charles Keepax89027d92018-04-26 17:30:07 +0100551 struct snd_compr_caps *caps)
Namarta Kohli1245b702012-08-16 17:10:41 +0530552{
553 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000554 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900555 int i, ret = 0;
Namarta Kohli1245b702012-08-16 17:10:41 +0530556
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300557 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax15e2e612013-01-24 09:44:29 +0000558
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900559 for_each_rtd_components(rtd, i, component) {
Kuninori Morimotoc6cb5222020-04-20 16:07:50 +0900560 if (!component->driver->compress_ops ||
561 !component->driver->compress_ops->get_caps)
562 continue;
563
564 ret = component->driver->compress_ops->get_caps(
565 component, cstream, caps);
566 break;
567 }
568
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300569 mutex_unlock(&rtd->card->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530570 return ret;
571}
572
573static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream,
Charles Keepax89027d92018-04-26 17:30:07 +0100574 struct snd_compr_codec_caps *codec)
Namarta Kohli1245b702012-08-16 17:10:41 +0530575{
576 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000577 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900578 int i, ret = 0;
Namarta Kohli1245b702012-08-16 17:10:41 +0530579
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300580 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax15e2e612013-01-24 09:44:29 +0000581
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900582 for_each_rtd_components(rtd, i, component) {
Kuninori Morimotoc6cb5222020-04-20 16:07:50 +0900583 if (!component->driver->compress_ops ||
584 !component->driver->compress_ops->get_codec_caps)
585 continue;
586
587 ret = component->driver->compress_ops->get_codec_caps(
588 component, cstream, codec);
589 break;
590 }
591
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300592 mutex_unlock(&rtd->card->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530593 return ret;
594}
595
596static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
597{
598 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000599 struct snd_soc_component *component;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900600 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900601 int i, ret = 0;
Namarta Kohli1245b702012-08-16 17:10:41 +0530602
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300603 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax15e2e612013-01-24 09:44:29 +0000604
Kuninori Morimoto53294352020-04-24 08:15:45 +0900605 ret = snd_soc_dai_compr_ack(cpu_dai, cstream, bytes);
606 if (ret < 0)
607 goto err;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530608
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900609 for_each_rtd_components(rtd, i, component) {
Kuninori Morimotoc6cb5222020-04-20 16:07:50 +0900610 if (!component->driver->compress_ops ||
611 !component->driver->compress_ops->ack)
612 continue;
613
614 ret = component->driver->compress_ops->ack(
615 component, cstream, bytes);
616 if (ret < 0)
617 goto err;
618 }
619
Vinod Koul2e622ae2016-11-13 12:10:02 +0530620err:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300621 mutex_unlock(&rtd->card->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530622 return ret;
623}
624
625static int soc_compr_pointer(struct snd_compr_stream *cstream,
Charles Keepax89027d92018-04-26 17:30:07 +0100626 struct snd_compr_tstamp *tstamp)
Namarta Kohli1245b702012-08-16 17:10:41 +0530627{
628 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000629 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900630 int i, ret = 0;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900631 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Namarta Kohli1245b702012-08-16 17:10:41 +0530632
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300633 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax15e2e612013-01-24 09:44:29 +0000634
Kuninori Morimotoed38cc52020-04-24 08:15:49 +0900635 ret = snd_soc_dai_compr_pointer(cpu_dai, cstream, tstamp);
636 if (ret < 0)
637 goto out;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530638
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900639 for_each_rtd_components(rtd, i, component) {
Kuninori Morimotoc6cb5222020-04-20 16:07:50 +0900640 if (!component->driver->compress_ops ||
641 !component->driver->compress_ops->pointer)
642 continue;
643
644 ret = component->driver->compress_ops->pointer(
645 component, cstream, tstamp);
646 break;
647 }
Kuninori Morimotoed38cc52020-04-24 08:15:49 +0900648out:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300649 mutex_unlock(&rtd->card->pcm_mutex);
Charles Keepax7c9190f2016-06-20 09:51:32 +0100650 return ret;
Namarta Kohli1245b702012-08-16 17:10:41 +0530651}
652
Charles Keepax1f88eb02013-02-05 10:41:47 +0000653static int soc_compr_copy(struct snd_compr_stream *cstream,
Charles Keepax4daf8912013-04-18 11:01:38 +0100654 char __user *buf, size_t count)
Charles Keepax1f88eb02013-02-05 10:41:47 +0000655{
656 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000657 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900658 int i, ret = 0;
Charles Keepax1f88eb02013-02-05 10:41:47 +0000659
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300660 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax1f88eb02013-02-05 10:41:47 +0000661
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900662 for_each_rtd_components(rtd, i, component) {
Kuninori Morimotoc6cb5222020-04-20 16:07:50 +0900663 if (!component->driver->compress_ops ||
664 !component->driver->compress_ops->copy)
665 continue;
666
667 ret = component->driver->compress_ops->copy(
668 component, cstream, buf, count);
669 break;
670 }
671
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300672 mutex_unlock(&rtd->card->pcm_mutex);
Charles Keepax1f88eb02013-02-05 10:41:47 +0000673 return ret;
674}
675
Vinod Koul02bd90e2013-07-28 20:06:15 +0530676static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
Charles Keepax89027d92018-04-26 17:30:07 +0100677 struct snd_compr_metadata *metadata)
Jeeja KP36953d92013-03-26 21:22:28 +0530678{
679 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000680 struct snd_soc_component *component;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900681 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900682 int i, ret;
Jeeja KP36953d92013-03-26 21:22:28 +0530683
Kuninori Morimoto88b3a7d2020-04-24 08:15:54 +0900684 ret = snd_soc_dai_compr_set_metadata(cpu_dai, cstream, metadata);
685 if (ret < 0)
686 return ret;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530687
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900688 for_each_rtd_components(rtd, i, component) {
Kuninori Morimotoc6cb5222020-04-20 16:07:50 +0900689 if (!component->driver->compress_ops ||
690 !component->driver->compress_ops->set_metadata)
691 continue;
692
693 ret = component->driver->compress_ops->set_metadata(
694 component, cstream, metadata);
695 if (ret < 0)
696 return ret;
697 }
698
Charles Keepax52cadf12019-02-05 11:18:12 +0000699 return 0;
Jeeja KP36953d92013-03-26 21:22:28 +0530700}
701
Vinod Koul02bd90e2013-07-28 20:06:15 +0530702static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
Charles Keepax89027d92018-04-26 17:30:07 +0100703 struct snd_compr_metadata *metadata)
Jeeja KP36953d92013-03-26 21:22:28 +0530704{
705 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000706 struct snd_soc_component *component;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900707 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900708 int i, ret;
Jeeja KP36953d92013-03-26 21:22:28 +0530709
Kuninori Morimoto94d72812020-04-24 08:15:59 +0900710 ret = snd_soc_dai_compr_get_metadata(cpu_dai, cstream, metadata);
711 if (ret < 0)
712 return ret;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530713
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900714 for_each_rtd_components(rtd, i, component) {
Kuninori Morimotoc6cb5222020-04-20 16:07:50 +0900715 if (!component->driver->compress_ops ||
716 !component->driver->compress_ops->get_metadata)
717 continue;
718
719 return component->driver->compress_ops->get_metadata(
720 component, cstream, metadata);
721 }
722
Charles Keepax52cadf12019-02-05 11:18:12 +0000723 return 0;
Jeeja KP36953d92013-03-26 21:22:28 +0530724}
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000725
Namarta Kohli1245b702012-08-16 17:10:41 +0530726/* ASoC Compress operations */
727static struct snd_compr_ops soc_compr_ops = {
728 .open = soc_compr_open,
729 .free = soc_compr_free,
730 .set_params = soc_compr_set_params,
Vinod Koul02bd90e2013-07-28 20:06:15 +0530731 .set_metadata = soc_compr_set_metadata,
732 .get_metadata = soc_compr_get_metadata,
Namarta Kohli1245b702012-08-16 17:10:41 +0530733 .get_params = soc_compr_get_params,
734 .trigger = soc_compr_trigger,
735 .pointer = soc_compr_pointer,
736 .ack = soc_compr_ack,
737 .get_caps = soc_compr_get_caps,
738 .get_codec_caps = soc_compr_get_codec_caps
739};
740
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000741/* ASoC Dynamic Compress operations */
742static struct snd_compr_ops soc_compr_dyn_ops = {
743 .open = soc_compr_open_fe,
744 .free = soc_compr_free_fe,
745 .set_params = soc_compr_set_params_fe,
746 .get_params = soc_compr_get_params,
747 .set_metadata = soc_compr_set_metadata,
748 .get_metadata = soc_compr_get_metadata,
749 .trigger = soc_compr_trigger_fe,
750 .pointer = soc_compr_pointer,
751 .ack = soc_compr_ack,
752 .get_caps = soc_compr_get_caps,
753 .get_codec_caps = soc_compr_get_codec_caps
754};
755
Jie Yang6f0c4222015-10-13 23:41:00 +0800756/**
757 * snd_soc_new_compress - create a new compress.
758 *
759 * @rtd: The runtime for which we will create compress
760 * @num: the device index number (zero based - shared with normal PCMs)
761 *
762 * Return: 0 for success, else error.
763 */
764int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
Namarta Kohli1245b702012-08-16 17:10:41 +0530765{
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000766 struct snd_soc_component *component;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900767 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
768 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Namarta Kohli1245b702012-08-16 17:10:41 +0530769 struct snd_compr *compr;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000770 struct snd_pcm *be_pcm;
Namarta Kohli1245b702012-08-16 17:10:41 +0530771 char new_name[64];
772 int ret = 0, direction = 0;
Vinod Koula1068042016-01-07 21:48:14 +0530773 int playback = 0, capture = 0;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900774 int i;
Namarta Kohli1245b702012-08-16 17:10:41 +0530775
Bard Liao6e1276a2020-02-25 21:39:16 +0800776 if (rtd->num_cpus > 1 ||
777 rtd->num_codecs > 1) {
Charles Keepax141dfc92018-01-26 13:08:45 +0000778 dev_err(rtd->card->dev,
Bard Liao6e1276a2020-02-25 21:39:16 +0800779 "Compress ASoC: Multi CPU/Codec not supported\n");
Benoit Cousson8151d5e2014-07-08 23:19:37 +0200780 return -EINVAL;
781 }
782
Namarta Kohli1245b702012-08-16 17:10:41 +0530783 /* check client and interface hw capabilities */
Kuninori Morimoto467fece2019-07-22 10:36:16 +0900784 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
785 snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_PLAYBACK))
Vinod Koula1068042016-01-07 21:48:14 +0530786 playback = 1;
Kuninori Morimoto467fece2019-07-22 10:36:16 +0900787 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
788 snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_CAPTURE))
Vinod Koula1068042016-01-07 21:48:14 +0530789 capture = 1;
790
Vinod Koula1068042016-01-07 21:48:14 +0530791 /*
792 * Compress devices are unidirectional so only one of the directions
793 * should be set, check for that (xor)
794 */
795 if (playback + capture != 1) {
Charles Keepax141dfc92018-01-26 13:08:45 +0000796 dev_err(rtd->card->dev,
797 "Compress ASoC: Invalid direction for P %d, C %d\n",
798 playback, capture);
Charles Keepaxdaa2db52013-04-18 11:02:38 +0100799 return -EINVAL;
Vinod Koula1068042016-01-07 21:48:14 +0530800 }
801
Peng Donglinaeb6fa02017-08-16 22:47:53 +0800802 if (playback)
Vinod Koula1068042016-01-07 21:48:14 +0530803 direction = SND_COMPRESS_PLAYBACK;
804 else
805 direction = SND_COMPRESS_CAPTURE;
Charles Keepaxdaa2db52013-04-18 11:02:38 +0100806
Amadeusz Sławiński09f448a2019-06-17 13:36:36 +0200807 compr = devm_kzalloc(rtd->card->dev, sizeof(*compr), GFP_KERNEL);
Markus Elfring7a0cf422017-08-10 16:21:34 +0200808 if (!compr)
Namarta Kohli1245b702012-08-16 17:10:41 +0530809 return -ENOMEM;
Namarta Kohli1245b702012-08-16 17:10:41 +0530810
Charles Keepax1f88eb02013-02-05 10:41:47 +0000811 compr->ops = devm_kzalloc(rtd->card->dev, sizeof(soc_compr_ops),
812 GFP_KERNEL);
Amadeusz Sławiński09f448a2019-06-17 13:36:36 +0200813 if (!compr->ops)
814 return -ENOMEM;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000815
816 if (rtd->dai_link->dynamic) {
817 snprintf(new_name, sizeof(new_name), "(%s)",
818 rtd->dai_link->stream_name);
819
820 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
Qais Yousefd3268a42015-01-14 08:47:29 +0000821 rtd->dai_link->dpcm_playback,
822 rtd->dai_link->dpcm_capture, &be_pcm);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000823 if (ret < 0) {
Charles Keepax141dfc92018-01-26 13:08:45 +0000824 dev_err(rtd->card->dev,
825 "Compress ASoC: can't create compressed for %s: %d\n",
826 rtd->dai_link->name, ret);
Amadeusz Sławiński09f448a2019-06-17 13:36:36 +0200827 return ret;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000828 }
829
830 rtd->pcm = be_pcm;
831 rtd->fe_compr = 1;
Qais Yousefd3268a42015-01-14 08:47:29 +0000832 if (rtd->dai_link->dpcm_playback)
833 be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
834 else if (rtd->dai_link->dpcm_capture)
835 be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000836 memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops));
Peng Donglinaeb6fa02017-08-16 22:47:53 +0800837 } else {
838 snprintf(new_name, sizeof(new_name), "%s %s-%d",
839 rtd->dai_link->stream_name, codec_dai->name, num);
840
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000841 memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));
Peng Donglinaeb6fa02017-08-16 22:47:53 +0800842 }
Charles Keepax1f88eb02013-02-05 10:41:47 +0000843
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900844 for_each_rtd_components(rtd, i, component) {
Kuninori Morimotoc6cb5222020-04-20 16:07:50 +0900845 if (!component->driver->compress_ops ||
846 !component->driver->compress_ops->copy)
847 continue;
848
849 compr->ops->copy = soc_compr_copy;
850 break;
851 }
852
Namarta Kohli1245b702012-08-16 17:10:41 +0530853 mutex_init(&compr->lock);
Richard Fitzgeralde5241a82015-11-25 13:00:24 +0000854 ret = snd_compress_new(rtd->card->snd_card, num, direction,
855 new_name, compr);
Namarta Kohli1245b702012-08-16 17:10:41 +0530856 if (ret < 0) {
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900857 component = asoc_rtd_to_codec(rtd, 0)->component;
Charles Keepax141dfc92018-01-26 13:08:45 +0000858 dev_err(component->dev,
859 "Compress ASoC: can't create compress for codec %s: %d\n",
860 component->name, ret);
Amadeusz Sławiński09f448a2019-06-17 13:36:36 +0200861 return ret;
Namarta Kohli1245b702012-08-16 17:10:41 +0530862 }
863
Charles Keepax202c8f72013-01-24 09:44:30 +0000864 /* DAPM dai link stream work */
Kuninori Morimoto83f94a22020-01-10 11:36:17 +0900865 rtd->close_delayed_work_func = snd_soc_close_delayed_work;
Charles Keepax202c8f72013-01-24 09:44:30 +0000866
Namarta Kohli1245b702012-08-16 17:10:41 +0530867 rtd->compr = compr;
868 compr->private_data = rtd;
869
Charles Keepax141dfc92018-01-26 13:08:45 +0000870 dev_info(rtd->card->dev, "Compress ASoC: %s <-> %s mapping ok\n",
871 codec_dai->name, cpu_dai->name);
Charles Keepax1f88eb02013-02-05 10:41:47 +0000872
Amadeusz Sławiński09f448a2019-06-17 13:36:36 +0200873 return 0;
Namarta Kohli1245b702012-08-16 17:10:41 +0530874}
Jie Yang6f0c4222015-10-13 23:41:00 +0800875EXPORT_SYMBOL_GPL(snd_soc_new_compress);