blob: 8e2494a9f3a7f02afd3866c464feccb920357422 [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
Peter Ujfalusicd46f382021-09-01 12:52:55 +030025static int snd_soc_compr_components_open(struct snd_compr_stream *cstream)
26{
27 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
28 struct snd_soc_component *component;
29 int ret = 0;
30 int i;
31
32 for_each_rtd_components(rtd, i, component) {
33 ret = snd_soc_component_module_get_when_open(component, cstream);
34 if (ret < 0)
35 break;
36
37 ret = snd_soc_component_compr_open(component, cstream);
38 if (ret < 0)
39 break;
40 }
41
42 return ret;
43}
44
45static void snd_soc_compr_components_free(struct snd_compr_stream *cstream,
46 int rollback)
47{
48 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
49 struct snd_soc_component *component;
50 int i;
51
52 for_each_rtd_components(rtd, i, component) {
53 snd_soc_component_compr_free(component, cstream, rollback);
54 snd_soc_component_module_put_when_close(component, cstream, rollback);
55 }
56}
57
Kuninori Morimoto453d32c2020-11-19 08:50:19 +090058static int soc_compr_clean(struct snd_compr_stream *cstream, int rollback)
Kuninori Morimoto15a7b8c2020-11-19 08:49:57 +090059{
60 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
61 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
62 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
63 int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
64
65 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
66
Kuninori Morimoto453d32c2020-11-19 08:50:19 +090067 if (!rollback)
68 snd_soc_runtime_deactivate(rtd, stream);
Kuninori Morimoto15a7b8c2020-11-19 08:49:57 +090069
70 snd_soc_dai_digital_mute(codec_dai, 1, stream);
71
72 if (!snd_soc_dai_active(cpu_dai))
73 cpu_dai->rate = 0;
74
75 if (!snd_soc_dai_active(codec_dai))
76 codec_dai->rate = 0;
77
Kuninori Morimoto453d32c2020-11-19 08:50:19 +090078 snd_soc_link_compr_shutdown(cstream, rollback);
Kuninori Morimoto15a7b8c2020-11-19 08:49:57 +090079
Peter Ujfalusicd46f382021-09-01 12:52:55 +030080 snd_soc_compr_components_free(cstream, rollback);
Kuninori Morimoto15a7b8c2020-11-19 08:49:57 +090081
Kuninori Morimoto453d32c2020-11-19 08:50:19 +090082 snd_soc_dai_compr_shutdown(cpu_dai, cstream, rollback);
Kuninori Morimoto15a7b8c2020-11-19 08:49:57 +090083
Kuninori Morimoto453d32c2020-11-19 08:50:19 +090084 if (!rollback)
85 snd_soc_dapm_stream_stop(rtd, stream);
Kuninori Morimoto15a7b8c2020-11-19 08:49:57 +090086
87 mutex_unlock(&rtd->card->pcm_mutex);
88
Kuninori Morimoto453d32c2020-11-19 08:50:19 +090089 snd_soc_pcm_component_pm_runtime_put(rtd, cstream, rollback);
Kuninori Morimoto15a7b8c2020-11-19 08:49:57 +090090
91 return 0;
92}
93
Kuninori Morimoto453d32c2020-11-19 08:50:19 +090094static int soc_compr_free(struct snd_compr_stream *cstream)
95{
96 return soc_compr_clean(cstream, 0);
97}
98
Charles Keepax1e57b822018-04-24 16:39:03 +010099static int soc_compr_open(struct snd_compr_stream *cstream)
100{
101 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900102 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Kuninori Morimoto7428d8c2020-10-30 10:01:22 +0900103 int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
Kuninori Morimoto939a5cf2020-09-28 09:01:17 +0900104 int ret;
Namarta Kohli1245b702012-08-16 17:10:41 +0530105
Kuninori Morimoto939a5cf2020-09-28 09:01:17 +0900106 ret = snd_soc_pcm_component_pm_runtime_get(rtd, cstream);
107 if (ret < 0)
Kuninori Morimoto453d32c2020-11-19 08:50:19 +0900108 goto err_no_lock;
Cezary Rojewski4137f4b2019-12-17 10:58:50 +0100109
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300110 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax15e2e612013-01-24 09:44:29 +0000111
Kuninori Morimotob5ae4cc2020-04-24 08:15:24 +0900112 ret = snd_soc_dai_compr_startup(cpu_dai, cstream);
113 if (ret < 0)
Kuninori Morimoto453d32c2020-11-19 08:50:19 +0900114 goto err;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530115
Peter Ujfalusicd46f382021-09-01 12:52:55 +0300116 ret = snd_soc_compr_components_open(cstream);
Charles Keepax1e57b822018-04-24 16:39:03 +0100117 if (ret < 0)
Kuninori Morimoto453d32c2020-11-19 08:50:19 +0900118 goto err;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000119
Kuninori Morimoto9ab711c2020-05-25 09:57:41 +0900120 ret = snd_soc_link_compr_startup(cstream);
121 if (ret < 0)
Kuninori Morimoto453d32c2020-11-19 08:50:19 +0900122 goto err;
Namarta Kohli1245b702012-08-16 17:10:41 +0530123
Kuninori Morimotoeb849592020-10-30 10:01:15 +0900124 snd_soc_runtime_activate(rtd, stream);
Kuninori Morimoto453d32c2020-11-19 08:50:19 +0900125err:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300126 mutex_unlock(&rtd->card->pcm_mutex);
Kuninori Morimoto453d32c2020-11-19 08:50:19 +0900127err_no_lock:
128 if (ret < 0)
129 soc_compr_clean(cstream, 1);
Cezary Rojewski4137f4b2019-12-17 10:58:50 +0100130
Namarta Kohli1245b702012-08-16 17:10:41 +0530131 return ret;
132}
133
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000134static int soc_compr_open_fe(struct snd_compr_stream *cstream)
135{
136 struct snd_soc_pcm_runtime *fe = cstream->private_data;
Satish Babu Patakokila01b8ced2017-06-16 17:33:40 -0700137 struct snd_pcm_substream *fe_substream =
138 fe->pcm->streams[cstream->direction].substream;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900139 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000140 struct snd_soc_dpcm *dpcm;
141 struct snd_soc_dapm_widget_list *list;
Kuninori Morimoto7428d8c2020-10-30 10:01:22 +0900142 int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
Charles Keepax572e6c82018-04-24 16:39:01 +0100143 int ret;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000144
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000145 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Srinivas Kandagatla0b0722e2018-08-03 13:30:03 +0100146 fe->dpcm[stream].runtime = fe_substream->runtime;
147
148 ret = dpcm_path_get(fe, stream, &list);
149 if (ret < 0)
150 goto be_err;
Kuninori Morimotod479f002021-03-15 09:57:52 +0900151
Srinivas Kandagatla0b0722e2018-08-03 13:30:03 +0100152 /* 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
Peter Ujfalusicd46f382021-09-01 12:52:55 +0300173 ret = snd_soc_compr_components_open(cstream);
Charles Keepax1e57b822018-04-24 16:39:03 +0100174 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
Gyeongtaek Lee45475bf2021-04-07 13:14:04 +0900187 mutex_lock_nested(&fe->card->pcm_mutex, fe->card->pcm_subclass);
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100188 snd_soc_runtime_activate(fe, stream);
Gyeongtaek Lee45475bf2021-04-07 13:14:04 +0900189 mutex_unlock(&fe->card->pcm_mutex);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000190
191 mutex_unlock(&fe->card->mutex);
192
193 return 0;
194
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000195machine_err:
Peter Ujfalusicd46f382021-09-01 12:52:55 +0300196 snd_soc_compr_components_free(cstream, 1);
Srinivas Kandagatla0b0722e2018-08-03 13:30:03 +0100197open_err:
Kuninori Morimoto1e6a93c2020-11-19 08:50:04 +0900198 snd_soc_dai_compr_shutdown(cpu_dai, cstream, 1);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000199out:
Srinivas Kandagatla0b0722e2018-08-03 13:30:03 +0100200 dpcm_path_put(&list);
201be_err:
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000202 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
203 mutex_unlock(&fe->card->mutex);
204 return ret;
205}
206
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000207static int soc_compr_free_fe(struct snd_compr_stream *cstream)
208{
209 struct snd_soc_pcm_runtime *fe = cstream->private_data;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900210 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000211 struct snd_soc_dpcm *dpcm;
Kuninori Morimoto7428d8c2020-10-30 10:01:22 +0900212 int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000213
214 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
215
Gyeongtaek Lee45475bf2021-04-07 13:14:04 +0900216 mutex_lock_nested(&fe->card->pcm_mutex, fe->card->pcm_subclass);
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100217 snd_soc_runtime_deactivate(fe, stream);
Gyeongtaek Lee45475bf2021-04-07 13:14:04 +0900218 mutex_unlock(&fe->card->pcm_mutex);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000219
220 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
221
Kuninori Morimotof52366e2021-03-15 09:58:32 +0900222 dpcm_be_dai_hw_free(fe, stream);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000223
Kuninori Morimoto531590b2021-03-09 10:08:17 +0900224 dpcm_be_dai_shutdown(fe, stream);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000225
226 /* mark FE's links ready to prune */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +0000227 for_each_dpcm_be(fe, stream, dpcm)
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000228 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
229
Kuninori Morimoto1c531232020-02-21 10:25:18 +0900230 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000231
232 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
233 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
234
235 dpcm_be_disconnect(fe, stream);
236
237 fe->dpcm[stream].runtime = NULL;
238
Kuninori Morimotocd7c7d12020-11-19 08:50:14 +0900239 snd_soc_link_compr_shutdown(cstream, 0);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000240
Peter Ujfalusicd46f382021-09-01 12:52:55 +0300241 snd_soc_compr_components_free(cstream, 0);
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000242
Kuninori Morimoto1e6a93c2020-11-19 08:50:04 +0900243 snd_soc_dai_compr_shutdown(cpu_dai, cstream, 0);
Vinod Koul2e622ae2016-11-13 12:10:02 +0530244
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000245 mutex_unlock(&fe->card->mutex);
246 return 0;
247}
248
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000249static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
250{
251 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900252 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
253 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Kuninori Morimoto7428d8c2020-10-30 10:01:22 +0900254 int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000255 int ret;
256
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300257 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000258
Kuninori Morimoto08aee252020-11-13 13:15:33 +0900259 ret = snd_soc_component_compr_trigger(cstream, cmd);
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000260 if (ret < 0)
261 goto out;
262
Kuninori Morimotoeb084112020-04-24 08:15:32 +0900263 ret = snd_soc_dai_compr_trigger(cpu_dai, cstream, cmd);
264 if (ret < 0)
265 goto out;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530266
Mark Brownda183962013-02-06 15:44:07 +0000267 switch (cmd) {
268 case SNDRV_PCM_TRIGGER_START:
Kuninori Morimotoeb849592020-10-30 10:01:15 +0900269 snd_soc_dai_digital_mute(codec_dai, 0, stream);
Mark Brownda183962013-02-06 15:44:07 +0000270 break;
271 case SNDRV_PCM_TRIGGER_STOP:
Kuninori Morimotoeb849592020-10-30 10:01:15 +0900272 snd_soc_dai_digital_mute(codec_dai, 1, stream);
Mark Brownda183962013-02-06 15:44:07 +0000273 break;
Mark Browne38b9b72013-02-06 13:52:42 +0000274 }
Namarta Kohli1245b702012-08-16 17:10:41 +0530275
Charles Keepax15e2e612013-01-24 09:44:29 +0000276out:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300277 mutex_unlock(&rtd->card->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530278 return ret;
279}
280
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000281static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
282{
283 struct snd_soc_pcm_runtime *fe = cstream->private_data;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900284 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
Kuninori Morimoto7428d8c2020-10-30 10:01:22 +0900285 int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
286 int ret;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000287
288 if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN ||
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000289 cmd == SND_COMPR_TRIGGER_DRAIN)
Kuninori Morimoto08aee252020-11-13 13:15:33 +0900290 return snd_soc_component_compr_trigger(cstream, cmd);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000291
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000292 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
293
Kuninori Morimotoeb084112020-04-24 08:15:32 +0900294 ret = snd_soc_dai_compr_trigger(cpu_dai, cstream, cmd);
295 if (ret < 0)
296 goto out;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530297
Kuninori Morimoto08aee252020-11-13 13:15:33 +0900298 ret = snd_soc_component_compr_trigger(cstream, cmd);
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000299 if (ret < 0)
300 goto out;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000301
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000302 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
303
304 ret = dpcm_be_dai_trigger(fe, stream, cmd);
305
306 switch (cmd) {
307 case SNDRV_PCM_TRIGGER_START:
308 case SNDRV_PCM_TRIGGER_RESUME:
309 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
310 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
311 break;
312 case SNDRV_PCM_TRIGGER_STOP:
313 case SNDRV_PCM_TRIGGER_SUSPEND:
314 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
315 break;
316 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
317 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
318 break;
319 }
320
321out:
322 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
323 mutex_unlock(&fe->card->mutex);
324 return ret;
325}
326
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000327static int soc_compr_set_params(struct snd_compr_stream *cstream,
328 struct snd_compr_params *params)
329{
330 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900331 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Kuninori Morimoto7428d8c2020-10-30 10:01:22 +0900332 int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
Charles Keepax52cadf12019-02-05 11:18:12 +0000333 int ret;
Namarta Kohli1245b702012-08-16 17:10:41 +0530334
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300335 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax15e2e612013-01-24 09:44:29 +0000336
Charles Keepaxef050be2018-04-24 16:39:02 +0100337 /*
338 * First we call set_params for the CPU DAI, then the component
339 * driver this should configure the SoC side. If the machine has
340 * compressed ops then we call that as well. The expectation is
341 * that these callbacks will configure everything for this compress
342 * path, like configuring a PCM port for a CODEC.
Namarta Kohli1245b702012-08-16 17:10:41 +0530343 */
Kuninori Morimoto8dfedaf2020-04-24 08:15:36 +0900344 ret = snd_soc_dai_compr_set_params(cpu_dai, cstream, params);
345 if (ret < 0)
346 goto err;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530347
Kuninori Morimotoff08cf82020-11-13 13:15:49 +0900348 ret = snd_soc_component_compr_set_params(cstream, params);
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000349 if (ret < 0)
350 goto err;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000351
Kuninori Morimotoeab810f2020-05-25 09:57:50 +0900352 ret = snd_soc_link_compr_set_params(cstream);
353 if (ret < 0)
354 goto err;
Namarta Kohli1245b702012-08-16 17:10:41 +0530355
Kuninori Morimoto7428d8c2020-10-30 10:01:22 +0900356 snd_soc_dapm_stream_event(rtd, stream, SND_SOC_DAPM_STREAM_START);
Namarta Kohli1245b702012-08-16 17:10:41 +0530357
Charles Keepaxfa40ef22013-03-27 16:39:01 +0000358 /* cancel any delayed stream shutdown that is pending */
359 rtd->pop_wait = 0;
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300360 mutex_unlock(&rtd->card->pcm_mutex);
Charles Keepaxfa40ef22013-03-27 16:39:01 +0000361
362 cancel_delayed_work_sync(&rtd->delayed_work);
363
Charles Keepax52cadf12019-02-05 11:18:12 +0000364 return 0;
Charles Keepaxfa40ef22013-03-27 16:39:01 +0000365
366err:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300367 mutex_unlock(&rtd->card->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530368 return ret;
369}
370
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000371static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
Charles Keepax89027d92018-04-26 17:30:07 +0100372 struct snd_compr_params *params)
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000373{
374 struct snd_soc_pcm_runtime *fe = cstream->private_data;
Satish Babu Patakokila01b8ced2017-06-16 17:33:40 -0700375 struct snd_pcm_substream *fe_substream =
376 fe->pcm->streams[cstream->direction].substream;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900377 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
Kuninori Morimoto7428d8c2020-10-30 10:01:22 +0900378 int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
379 int ret;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000380
381 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
382
Srinivas Kandagatla0b0722e2018-08-03 13:30:03 +0100383 /*
384 * Create an empty hw_params for the BE as the machine driver must
385 * fix this up to match DSP decoder and ASRC configuration.
386 * I.e. machine driver fixup for compressed BE is mandatory.
387 */
388 memset(&fe->dpcm[fe_substream->stream].hw_params, 0,
389 sizeof(struct snd_pcm_hw_params));
390
391 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
392
393 ret = dpcm_be_dai_hw_params(fe, stream);
394 if (ret < 0)
395 goto out;
396
397 ret = dpcm_be_dai_prepare(fe, stream);
398 if (ret < 0)
399 goto out;
400
Kuninori Morimoto8dfedaf2020-04-24 08:15:36 +0900401 ret = snd_soc_dai_compr_set_params(cpu_dai, cstream, params);
402 if (ret < 0)
403 goto out;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530404
Kuninori Morimotoff08cf82020-11-13 13:15:49 +0900405 ret = snd_soc_component_compr_set_params(cstream, params);
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000406 if (ret < 0)
407 goto out;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000408
Kuninori Morimotoeab810f2020-05-25 09:57:50 +0900409 ret = snd_soc_link_compr_set_params(cstream);
410 if (ret < 0)
411 goto out;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000412
Daniel Mack15f6b092014-10-19 09:07:35 +0200413 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000414 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
415
416out:
417 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
418 mutex_unlock(&fe->card->mutex);
419 return ret;
420}
421
Namarta Kohli1245b702012-08-16 17:10:41 +0530422static int soc_compr_get_params(struct snd_compr_stream *cstream,
Charles Keepax89027d92018-04-26 17:30:07 +0100423 struct snd_codec *params)
Namarta Kohli1245b702012-08-16 17:10:41 +0530424{
425 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900426 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Kuninori Morimoto77c221e2020-11-13 13:15:56 +0900427 int ret = 0;
Namarta Kohli1245b702012-08-16 17:10:41 +0530428
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300429 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax15e2e612013-01-24 09:44:29 +0000430
Kuninori Morimotoadbef5432020-04-24 08:15:40 +0900431 ret = snd_soc_dai_compr_get_params(cpu_dai, cstream, params);
432 if (ret < 0)
433 goto err;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530434
Kuninori Morimoto77c221e2020-11-13 13:15:56 +0900435 ret = snd_soc_component_compr_get_params(cstream, params);
Vinod Koul2e622ae2016-11-13 12:10:02 +0530436err:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300437 mutex_unlock(&rtd->card->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530438 return ret;
439}
440
Namarta Kohli1245b702012-08-16 17:10:41 +0530441static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
442{
443 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900444 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Kuninori Morimoto0506b882020-11-13 13:16:17 +0900445 int ret;
Namarta Kohli1245b702012-08-16 17:10:41 +0530446
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300447 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax15e2e612013-01-24 09:44:29 +0000448
Kuninori Morimoto53294352020-04-24 08:15:45 +0900449 ret = snd_soc_dai_compr_ack(cpu_dai, cstream, bytes);
450 if (ret < 0)
451 goto err;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530452
Kuninori Morimoto0506b882020-11-13 13:16:17 +0900453 ret = snd_soc_component_compr_ack(cstream, bytes);
Vinod Koul2e622ae2016-11-13 12:10:02 +0530454err:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300455 mutex_unlock(&rtd->card->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530456 return ret;
457}
458
459static int soc_compr_pointer(struct snd_compr_stream *cstream,
Charles Keepax89027d92018-04-26 17:30:07 +0100460 struct snd_compr_tstamp *tstamp)
Namarta Kohli1245b702012-08-16 17:10:41 +0530461{
462 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimoto03ecea62020-11-13 13:16:24 +0900463 int ret;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900464 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Namarta Kohli1245b702012-08-16 17:10:41 +0530465
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300466 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax15e2e612013-01-24 09:44:29 +0000467
Kuninori Morimotoed38cc52020-04-24 08:15:49 +0900468 ret = snd_soc_dai_compr_pointer(cpu_dai, cstream, tstamp);
469 if (ret < 0)
470 goto out;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530471
Kuninori Morimoto03ecea62020-11-13 13:16:24 +0900472 ret = snd_soc_component_compr_pointer(cstream, tstamp);
Kuninori Morimotoed38cc52020-04-24 08:15:49 +0900473out:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300474 mutex_unlock(&rtd->card->pcm_mutex);
Charles Keepax7c9190f2016-06-20 09:51:32 +0100475 return ret;
Namarta Kohli1245b702012-08-16 17:10:41 +0530476}
477
Vinod Koul02bd90e2013-07-28 20:06:15 +0530478static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
Charles Keepax89027d92018-04-26 17:30:07 +0100479 struct snd_compr_metadata *metadata)
Jeeja KP36953d92013-03-26 21:22:28 +0530480{
481 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900482 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Kuninori Morimoto1b308fb2020-11-13 13:16:36 +0900483 int ret;
Jeeja KP36953d92013-03-26 21:22:28 +0530484
Kuninori Morimoto88b3a7d2020-04-24 08:15:54 +0900485 ret = snd_soc_dai_compr_set_metadata(cpu_dai, cstream, metadata);
486 if (ret < 0)
487 return ret;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530488
Kuninori Morimoto1b308fb2020-11-13 13:16:36 +0900489 return snd_soc_component_compr_set_metadata(cstream, metadata);
Jeeja KP36953d92013-03-26 21:22:28 +0530490}
491
Vinod Koul02bd90e2013-07-28 20:06:15 +0530492static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
Charles Keepax89027d92018-04-26 17:30:07 +0100493 struct snd_compr_metadata *metadata)
Jeeja KP36953d92013-03-26 21:22:28 +0530494{
495 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900496 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Kuninori Morimotobab78c22020-11-13 13:16:41 +0900497 int ret;
Jeeja KP36953d92013-03-26 21:22:28 +0530498
Kuninori Morimoto94d72812020-04-24 08:15:59 +0900499 ret = snd_soc_dai_compr_get_metadata(cpu_dai, cstream, metadata);
500 if (ret < 0)
501 return ret;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530502
Kuninori Morimotobab78c22020-11-13 13:16:41 +0900503 return snd_soc_component_compr_get_metadata(cstream, metadata);
Jeeja KP36953d92013-03-26 21:22:28 +0530504}
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000505
Namarta Kohli1245b702012-08-16 17:10:41 +0530506/* ASoC Compress operations */
507static struct snd_compr_ops soc_compr_ops = {
508 .open = soc_compr_open,
509 .free = soc_compr_free,
510 .set_params = soc_compr_set_params,
Vinod Koul02bd90e2013-07-28 20:06:15 +0530511 .set_metadata = soc_compr_set_metadata,
512 .get_metadata = soc_compr_get_metadata,
Namarta Kohli1245b702012-08-16 17:10:41 +0530513 .get_params = soc_compr_get_params,
514 .trigger = soc_compr_trigger,
515 .pointer = soc_compr_pointer,
516 .ack = soc_compr_ack,
Kuninori Morimotod67fcb22020-11-13 13:16:03 +0900517 .get_caps = snd_soc_component_compr_get_caps,
Kuninori Morimoto0f6fe092020-11-13 13:16:11 +0900518 .get_codec_caps = snd_soc_component_compr_get_codec_caps,
Namarta Kohli1245b702012-08-16 17:10:41 +0530519};
520
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000521/* ASoC Dynamic Compress operations */
522static struct snd_compr_ops soc_compr_dyn_ops = {
523 .open = soc_compr_open_fe,
524 .free = soc_compr_free_fe,
525 .set_params = soc_compr_set_params_fe,
526 .get_params = soc_compr_get_params,
527 .set_metadata = soc_compr_set_metadata,
528 .get_metadata = soc_compr_get_metadata,
529 .trigger = soc_compr_trigger_fe,
530 .pointer = soc_compr_pointer,
531 .ack = soc_compr_ack,
Kuninori Morimotod67fcb22020-11-13 13:16:03 +0900532 .get_caps = snd_soc_component_compr_get_caps,
Kuninori Morimoto0f6fe092020-11-13 13:16:11 +0900533 .get_codec_caps = snd_soc_component_compr_get_codec_caps,
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000534};
535
Jie Yang6f0c4222015-10-13 23:41:00 +0800536/**
537 * snd_soc_new_compress - create a new compress.
538 *
539 * @rtd: The runtime for which we will create compress
540 * @num: the device index number (zero based - shared with normal PCMs)
541 *
542 * Return: 0 for success, else error.
543 */
544int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
Namarta Kohli1245b702012-08-16 17:10:41 +0530545{
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000546 struct snd_soc_component *component;
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900547 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
548 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
Namarta Kohli1245b702012-08-16 17:10:41 +0530549 struct snd_compr *compr;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000550 struct snd_pcm *be_pcm;
Namarta Kohli1245b702012-08-16 17:10:41 +0530551 char new_name[64];
552 int ret = 0, direction = 0;
Vinod Koula1068042016-01-07 21:48:14 +0530553 int playback = 0, capture = 0;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900554 int i;
Namarta Kohli1245b702012-08-16 17:10:41 +0530555
Kuninori Morimoto7428d8c2020-10-30 10:01:22 +0900556 /*
557 * make sure these are same value,
558 * and then use these as equally
559 */
560 BUILD_BUG_ON((int)SNDRV_PCM_STREAM_PLAYBACK != (int)SND_COMPRESS_PLAYBACK);
561 BUILD_BUG_ON((int)SNDRV_PCM_STREAM_CAPTURE != (int)SND_COMPRESS_CAPTURE);
562
Bard Liao6e1276a2020-02-25 21:39:16 +0800563 if (rtd->num_cpus > 1 ||
564 rtd->num_codecs > 1) {
Charles Keepax141dfc92018-01-26 13:08:45 +0000565 dev_err(rtd->card->dev,
Bard Liao6e1276a2020-02-25 21:39:16 +0800566 "Compress ASoC: Multi CPU/Codec not supported\n");
Benoit Cousson8151d5e2014-07-08 23:19:37 +0200567 return -EINVAL;
568 }
569
Namarta Kohli1245b702012-08-16 17:10:41 +0530570 /* check client and interface hw capabilities */
Kuninori Morimoto467fece2019-07-22 10:36:16 +0900571 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
572 snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_PLAYBACK))
Vinod Koula1068042016-01-07 21:48:14 +0530573 playback = 1;
Kuninori Morimoto467fece2019-07-22 10:36:16 +0900574 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
575 snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_CAPTURE))
Vinod Koula1068042016-01-07 21:48:14 +0530576 capture = 1;
577
Vinod Koula1068042016-01-07 21:48:14 +0530578 /*
579 * Compress devices are unidirectional so only one of the directions
580 * should be set, check for that (xor)
581 */
582 if (playback + capture != 1) {
Charles Keepax141dfc92018-01-26 13:08:45 +0000583 dev_err(rtd->card->dev,
584 "Compress ASoC: Invalid direction for P %d, C %d\n",
585 playback, capture);
Charles Keepaxdaa2db52013-04-18 11:02:38 +0100586 return -EINVAL;
Vinod Koula1068042016-01-07 21:48:14 +0530587 }
588
Peng Donglinaeb6fa02017-08-16 22:47:53 +0800589 if (playback)
Vinod Koula1068042016-01-07 21:48:14 +0530590 direction = SND_COMPRESS_PLAYBACK;
591 else
592 direction = SND_COMPRESS_CAPTURE;
Charles Keepaxdaa2db52013-04-18 11:02:38 +0100593
Amadeusz Sławiński09f448a2019-06-17 13:36:36 +0200594 compr = devm_kzalloc(rtd->card->dev, sizeof(*compr), GFP_KERNEL);
Markus Elfring7a0cf422017-08-10 16:21:34 +0200595 if (!compr)
Namarta Kohli1245b702012-08-16 17:10:41 +0530596 return -ENOMEM;
Namarta Kohli1245b702012-08-16 17:10:41 +0530597
Charles Keepax1f88eb02013-02-05 10:41:47 +0000598 compr->ops = devm_kzalloc(rtd->card->dev, sizeof(soc_compr_ops),
599 GFP_KERNEL);
Amadeusz Sławiński09f448a2019-06-17 13:36:36 +0200600 if (!compr->ops)
601 return -ENOMEM;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000602
603 if (rtd->dai_link->dynamic) {
604 snprintf(new_name, sizeof(new_name), "(%s)",
605 rtd->dai_link->stream_name);
606
607 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
Qais Yousefd3268a42015-01-14 08:47:29 +0000608 rtd->dai_link->dpcm_playback,
609 rtd->dai_link->dpcm_capture, &be_pcm);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000610 if (ret < 0) {
Charles Keepax141dfc92018-01-26 13:08:45 +0000611 dev_err(rtd->card->dev,
612 "Compress ASoC: can't create compressed for %s: %d\n",
613 rtd->dai_link->name, ret);
Amadeusz Sławiński09f448a2019-06-17 13:36:36 +0200614 return ret;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000615 }
616
617 rtd->pcm = be_pcm;
618 rtd->fe_compr = 1;
Qais Yousefd3268a42015-01-14 08:47:29 +0000619 if (rtd->dai_link->dpcm_playback)
620 be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
621 else if (rtd->dai_link->dpcm_capture)
622 be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000623 memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops));
Peng Donglinaeb6fa02017-08-16 22:47:53 +0800624 } else {
625 snprintf(new_name, sizeof(new_name), "%s %s-%d",
626 rtd->dai_link->stream_name, codec_dai->name, num);
627
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000628 memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));
Peng Donglinaeb6fa02017-08-16 22:47:53 +0800629 }
Charles Keepax1f88eb02013-02-05 10:41:47 +0000630
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900631 for_each_rtd_components(rtd, i, component) {
Kuninori Morimotoc6cb5222020-04-20 16:07:50 +0900632 if (!component->driver->compress_ops ||
633 !component->driver->compress_ops->copy)
634 continue;
635
Kuninori Morimotob5852e62020-11-13 13:16:30 +0900636 compr->ops->copy = snd_soc_component_compr_copy;
Kuninori Morimotoc6cb5222020-04-20 16:07:50 +0900637 break;
638 }
639
Richard Fitzgeralde5241a82015-11-25 13:00:24 +0000640 ret = snd_compress_new(rtd->card->snd_card, num, direction,
641 new_name, compr);
Namarta Kohli1245b702012-08-16 17:10:41 +0530642 if (ret < 0) {
Kuninori Morimotoc2233a22020-03-30 10:47:37 +0900643 component = asoc_rtd_to_codec(rtd, 0)->component;
Charles Keepax141dfc92018-01-26 13:08:45 +0000644 dev_err(component->dev,
645 "Compress ASoC: can't create compress for codec %s: %d\n",
646 component->name, ret);
Amadeusz Sławiński09f448a2019-06-17 13:36:36 +0200647 return ret;
Namarta Kohli1245b702012-08-16 17:10:41 +0530648 }
649
Charles Keepax202c8f72013-01-24 09:44:30 +0000650 /* DAPM dai link stream work */
Kuninori Morimoto83f94a22020-01-10 11:36:17 +0900651 rtd->close_delayed_work_func = snd_soc_close_delayed_work;
Charles Keepax202c8f72013-01-24 09:44:30 +0000652
Namarta Kohli1245b702012-08-16 17:10:41 +0530653 rtd->compr = compr;
654 compr->private_data = rtd;
655
Pierre-Louis Bossart1d5cd522020-06-12 15:40:50 -0500656 dev_dbg(rtd->card->dev, "Compress ASoC: %s <-> %s mapping ok\n",
657 codec_dai->name, cpu_dai->name);
Charles Keepax1f88eb02013-02-05 10:41:47 +0000658
Amadeusz Sławiński09f448a2019-06-17 13:36:36 +0200659 return 0;
Namarta Kohli1245b702012-08-16 17:10:41 +0530660}
Jie Yang6f0c4222015-10-13 23:41:00 +0800661EXPORT_SYMBOL_GPL(snd_soc_new_compress);