blob: 16fe08690cf572419ddfc94587efd85987d33c70 [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>
Cezary Rojewski4137f4b2019-12-17 10:58:50 +010022#include <linux/pm_runtime.h>
Namarta Kohli1245b702012-08-16 17:10:41 +053023
Charles Keepax1e57b822018-04-24 16:39:03 +010024static int soc_compr_components_open(struct snd_compr_stream *cstream,
25 struct snd_soc_component **last)
Namarta Kohli1245b702012-08-16 17:10:41 +053026{
27 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +000028 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +090029 int i, ret;
Charles Keepax1e57b822018-04-24 16:39:03 +010030
Kuninori Morimoto613fb502020-01-10 11:35:21 +090031 for_each_rtd_components(rtd, i, component) {
Charles Keepax1e57b822018-04-24 16:39:03 +010032 if (!component->driver->compr_ops ||
33 !component->driver->compr_ops->open)
34 continue;
35
36 ret = component->driver->compr_ops->open(cstream);
37 if (ret < 0) {
38 dev_err(component->dev,
39 "Compress ASoC: can't open platform %s: %d\n",
40 component->name, ret);
41
42 *last = component;
43 return ret;
44 }
45 }
46
47 *last = NULL;
48 return 0;
49}
50
51static int soc_compr_components_free(struct snd_compr_stream *cstream,
52 struct snd_soc_component *last)
53{
54 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
55 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +090056 int i;
Charles Keepax1e57b822018-04-24 16:39:03 +010057
Kuninori Morimoto613fb502020-01-10 11:35:21 +090058 for_each_rtd_components(rtd, i, component) {
Charles Keepax1e57b822018-04-24 16:39:03 +010059 if (component == last)
60 break;
61
62 if (!component->driver->compr_ops ||
63 !component->driver->compr_ops->free)
64 continue;
65
66 component->driver->compr_ops->free(cstream);
67 }
68
69 return 0;
70}
71
72static int soc_compr_open(struct snd_compr_stream *cstream)
73{
74 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Cezary Rojewski4137f4b2019-12-17 10:58:50 +010075 struct snd_soc_component *component, *save = NULL;
Vinod Koul2e622ae2016-11-13 12:10:02 +053076 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto613fb502020-01-10 11:35:21 +090077 int ret, i;
Namarta Kohli1245b702012-08-16 17:10:41 +053078
Kuninori Morimoto613fb502020-01-10 11:35:21 +090079 for_each_rtd_components(rtd, i, component) {
Cezary Rojewski4137f4b2019-12-17 10:58:50 +010080 ret = pm_runtime_get_sync(component->dev);
81 if (ret < 0 && ret != -EACCES) {
82 pm_runtime_put_noidle(component->dev);
83 save = component;
84 goto pm_err;
85 }
86 }
87
Peter Ujfalusi72b745e2019-08-13 13:45:32 +030088 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax15e2e612013-01-24 09:44:29 +000089
Vinod Koul2e622ae2016-11-13 12:10:02 +053090 if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) {
91 ret = cpu_dai->driver->cops->startup(cstream, cpu_dai);
92 if (ret < 0) {
Charles Keepax141dfc92018-01-26 13:08:45 +000093 dev_err(cpu_dai->dev,
94 "Compress ASoC: can't open interface %s: %d\n",
Vinod Koul2e622ae2016-11-13 12:10:02 +053095 cpu_dai->name, ret);
96 goto out;
97 }
98 }
99
Charles Keepax1e57b822018-04-24 16:39:03 +0100100 ret = soc_compr_components_open(cstream, &component);
101 if (ret < 0)
102 goto machine_err;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000103
Namarta Kohli1245b702012-08-16 17:10:41 +0530104 if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->startup) {
105 ret = rtd->dai_link->compr_ops->startup(cstream);
106 if (ret < 0) {
Charles Keepax141dfc92018-01-26 13:08:45 +0000107 dev_err(rtd->dev,
108 "Compress ASoC: %s startup failed: %d\n",
109 rtd->dai_link->name, ret);
Namarta Kohli1245b702012-08-16 17:10:41 +0530110 goto machine_err;
111 }
112 }
113
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100114 snd_soc_runtime_activate(rtd, cstream->direction);
Namarta Kohli1245b702012-08-16 17:10:41 +0530115
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300116 mutex_unlock(&rtd->card->pcm_mutex);
Charles Keepax15e2e612013-01-24 09:44:29 +0000117
Namarta Kohli1245b702012-08-16 17:10:41 +0530118 return 0;
119
120machine_err:
Charles Keepax1e57b822018-04-24 16:39:03 +0100121 soc_compr_components_free(cstream, component);
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000122
Vinod Koul2e622ae2016-11-13 12:10:02 +0530123 if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
124 cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
Namarta Kohli1245b702012-08-16 17:10:41 +0530125out:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300126 mutex_unlock(&rtd->card->pcm_mutex);
Cezary Rojewski4137f4b2019-12-17 10:58:50 +0100127pm_err:
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900128 for_each_rtd_components(rtd, i, component) {
Cezary Rojewski4137f4b2019-12-17 10:58:50 +0100129 if (component == save)
130 break;
131 pm_runtime_mark_last_busy(component->dev);
132 pm_runtime_put_autosuspend(component->dev);
133 }
134
Namarta Kohli1245b702012-08-16 17:10:41 +0530135 return ret;
136}
137
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000138static int soc_compr_open_fe(struct snd_compr_stream *cstream)
139{
140 struct snd_soc_pcm_runtime *fe = cstream->private_data;
Satish Babu Patakokila01b8ced2017-06-16 17:33:40 -0700141 struct snd_pcm_substream *fe_substream =
142 fe->pcm->streams[cstream->direction].substream;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000143 struct snd_soc_component *component;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530144 struct snd_soc_dai *cpu_dai = fe->cpu_dai;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000145 struct snd_soc_dpcm *dpcm;
146 struct snd_soc_dapm_widget_list *list;
147 int stream;
Charles Keepax572e6c82018-04-24 16:39:01 +0100148 int ret;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000149
150 if (cstream->direction == SND_COMPRESS_PLAYBACK)
151 stream = SNDRV_PCM_STREAM_PLAYBACK;
152 else
153 stream = SNDRV_PCM_STREAM_CAPTURE;
154
155 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
Srinivas Kandagatla0b0722e2018-08-03 13:30:03 +0100156 fe->dpcm[stream].runtime = fe_substream->runtime;
157
158 ret = dpcm_path_get(fe, stream, &list);
159 if (ret < 0)
160 goto be_err;
161 else if (ret == 0)
162 dev_dbg(fe->dev, "Compress ASoC: %s no valid %s route\n",
163 fe->dai_link->name, stream ? "capture" : "playback");
164 /* calculate valid and active FE <-> BE dpcms */
165 dpcm_process_paths(fe, stream, &list, 1);
166 fe->dpcm[stream].runtime = fe_substream->runtime;
167
168 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
169
170 ret = dpcm_be_dai_startup(fe, stream);
171 if (ret < 0) {
172 /* clean up all links */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +0000173 for_each_dpcm_be(fe, stream, dpcm)
Srinivas Kandagatla0b0722e2018-08-03 13:30:03 +0100174 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
175
176 dpcm_be_disconnect(fe, stream);
177 fe->dpcm[stream].runtime = NULL;
178 goto out;
179 }
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000180
Vinod Koul2e622ae2016-11-13 12:10:02 +0530181 if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) {
182 ret = cpu_dai->driver->cops->startup(cstream, cpu_dai);
183 if (ret < 0) {
Charles Keepax141dfc92018-01-26 13:08:45 +0000184 dev_err(cpu_dai->dev,
185 "Compress ASoC: can't open interface %s: %d\n",
Vinod Koul2e622ae2016-11-13 12:10:02 +0530186 cpu_dai->name, ret);
187 goto out;
188 }
189 }
190
Charles Keepax1e57b822018-04-24 16:39:03 +0100191 ret = soc_compr_components_open(cstream, &component);
192 if (ret < 0)
Srinivas Kandagatla0b0722e2018-08-03 13:30:03 +0100193 goto open_err;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000194
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000195 if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->startup) {
196 ret = fe->dai_link->compr_ops->startup(cstream);
197 if (ret < 0) {
Charles Keepax141dfc92018-01-26 13:08:45 +0000198 pr_err("Compress ASoC: %s startup failed: %d\n",
199 fe->dai_link->name, ret);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000200 goto machine_err;
201 }
202 }
203
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000204 dpcm_clear_pending_state(fe, stream);
205 dpcm_path_put(&list);
206
207 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
208 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
209
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100210 snd_soc_runtime_activate(fe, stream);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000211
212 mutex_unlock(&fe->card->mutex);
213
214 return 0;
215
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000216machine_err:
Charles Keepax1e57b822018-04-24 16:39:03 +0100217 soc_compr_components_free(cstream, component);
Srinivas Kandagatla0b0722e2018-08-03 13:30:03 +0100218open_err:
Vinod Koul2e622ae2016-11-13 12:10:02 +0530219 if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
220 cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000221out:
Srinivas Kandagatla0b0722e2018-08-03 13:30:03 +0100222 dpcm_path_put(&list);
223be_err:
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000224 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
225 mutex_unlock(&fe->card->mutex);
226 return ret;
227}
228
Charles Keepax202c8f72013-01-24 09:44:30 +0000229/*
230 * Power down the audio subsystem pmdown_time msecs after close is called.
231 * This is to ensure there are no pops or clicks in between any music tracks
232 * due to DAPM power cycling.
233 */
Curtis Malainey4bf2e382019-12-03 09:30:07 -0800234static void close_delayed_work(struct snd_soc_pcm_runtime *rtd)
Charles Keepax202c8f72013-01-24 09:44:30 +0000235{
Charles Keepax202c8f72013-01-24 09:44:30 +0000236 struct snd_soc_dai *codec_dai = rtd->codec_dai;
237
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300238 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax202c8f72013-01-24 09:44:30 +0000239
Charles Keepax141dfc92018-01-26 13:08:45 +0000240 dev_dbg(rtd->dev,
241 "Compress ASoC: pop wq checking: %s status: %s waiting: %s\n",
242 codec_dai->driver->playback.stream_name,
243 codec_dai->playback_active ? "active" : "inactive",
244 rtd->pop_wait ? "yes" : "no");
Charles Keepax202c8f72013-01-24 09:44:30 +0000245
246 /* are we waiting on this codec DAI stream */
247 if (rtd->pop_wait == 1) {
248 rtd->pop_wait = 0;
249 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
250 SND_SOC_DAPM_STREAM_STOP);
251 }
252
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300253 mutex_unlock(&rtd->card->pcm_mutex);
Charles Keepax202c8f72013-01-24 09:44:30 +0000254}
255
Namarta Kohli1245b702012-08-16 17:10:41 +0530256static int soc_compr_free(struct snd_compr_stream *cstream)
257{
258 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Cezary Rojewski4137f4b2019-12-17 10:58:50 +0100259 struct snd_soc_component *component;
Namarta Kohli1245b702012-08-16 17:10:41 +0530260 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
261 struct snd_soc_dai *codec_dai = rtd->codec_dai;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900262 int stream, i;
Namarta Kohli1245b702012-08-16 17:10:41 +0530263
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300264 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax15e2e612013-01-24 09:44:29 +0000265
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100266 if (cstream->direction == SND_COMPRESS_PLAYBACK)
267 stream = SNDRV_PCM_STREAM_PLAYBACK;
268 else
269 stream = SNDRV_PCM_STREAM_CAPTURE;
270
271 snd_soc_runtime_deactivate(rtd, stream);
Namarta Kohli1245b702012-08-16 17:10:41 +0530272
Mark Brownda183962013-02-06 15:44:07 +0000273 snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
274
Namarta Kohli1245b702012-08-16 17:10:41 +0530275 if (!cpu_dai->active)
276 cpu_dai->rate = 0;
277
278 if (!codec_dai->active)
279 codec_dai->rate = 0;
280
Namarta Kohli1245b702012-08-16 17:10:41 +0530281 if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown)
282 rtd->dai_link->compr_ops->shutdown(cstream);
283
Charles Keepax1e57b822018-04-24 16:39:03 +0100284 soc_compr_components_free(cstream, NULL);
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000285
Vinod Koul2e622ae2016-11-13 12:10:02 +0530286 if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
287 cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
288
Namarta Kohli1245b702012-08-16 17:10:41 +0530289 if (cstream->direction == SND_COMPRESS_PLAYBACK) {
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100290 if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
Namarta Kohli1245b702012-08-16 17:10:41 +0530291 snd_soc_dapm_stream_event(rtd,
Charles Keepax89027d92018-04-26 17:30:07 +0100292 SNDRV_PCM_STREAM_PLAYBACK,
293 SND_SOC_DAPM_STREAM_STOP);
Charles Keepax8c3d2aa2013-01-24 09:44:28 +0000294 } else {
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600295 rtd->pop_wait = 1;
Mark Brown3d24cfe2013-08-09 18:12:29 +0100296 queue_delayed_work(system_power_efficient_wq,
297 &rtd->delayed_work,
298 msecs_to_jiffies(rtd->pmdown_time));
Charles Keepax8c3d2aa2013-01-24 09:44:28 +0000299 }
Namarta Kohli1245b702012-08-16 17:10:41 +0530300 } else {
301 /* capture streams can be powered down now */
302 snd_soc_dapm_stream_event(rtd,
Charles Keepax89027d92018-04-26 17:30:07 +0100303 SNDRV_PCM_STREAM_CAPTURE,
304 SND_SOC_DAPM_STREAM_STOP);
Namarta Kohli1245b702012-08-16 17:10:41 +0530305 }
306
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300307 mutex_unlock(&rtd->card->pcm_mutex);
Cezary Rojewski4137f4b2019-12-17 10:58:50 +0100308
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900309 for_each_rtd_components(rtd, i, component) {
Cezary Rojewski4137f4b2019-12-17 10:58:50 +0100310 pm_runtime_mark_last_busy(component->dev);
311 pm_runtime_put_autosuspend(component->dev);
312 }
313
Namarta Kohli1245b702012-08-16 17:10:41 +0530314 return 0;
315}
316
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000317static int soc_compr_free_fe(struct snd_compr_stream *cstream)
318{
319 struct snd_soc_pcm_runtime *fe = cstream->private_data;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530320 struct snd_soc_dai *cpu_dai = fe->cpu_dai;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000321 struct snd_soc_dpcm *dpcm;
322 int stream, ret;
323
324 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
325
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100326 if (cstream->direction == SND_COMPRESS_PLAYBACK)
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000327 stream = SNDRV_PCM_STREAM_PLAYBACK;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100328 else
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000329 stream = SNDRV_PCM_STREAM_CAPTURE;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000330
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100331 snd_soc_runtime_deactivate(fe, stream);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000332
333 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
334
335 ret = dpcm_be_dai_hw_free(fe, stream);
336 if (ret < 0)
Charles Keepax141dfc92018-01-26 13:08:45 +0000337 dev_err(fe->dev, "Compressed ASoC: hw_free failed: %d\n", ret);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000338
339 ret = dpcm_be_dai_shutdown(fe, stream);
340
341 /* mark FE's links ready to prune */
Kuninori Morimoto8d6258a2018-09-18 01:31:09 +0000342 for_each_dpcm_be(fe, stream, dpcm)
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000343 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
344
Daniel Mack15f6b092014-10-19 09:07:35 +0200345 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000346
347 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
348 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
349
350 dpcm_be_disconnect(fe, stream);
351
352 fe->dpcm[stream].runtime = NULL;
353
354 if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
355 fe->dai_link->compr_ops->shutdown(cstream);
356
Charles Keepax1e57b822018-04-24 16:39:03 +0100357 soc_compr_components_free(cstream, NULL);
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000358
Vinod Koul2e622ae2016-11-13 12:10:02 +0530359 if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
360 cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
361
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000362 mutex_unlock(&fe->card->mutex);
363 return 0;
364}
365
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000366static int soc_compr_components_trigger(struct snd_compr_stream *cstream,
367 int cmd)
Namarta Kohli1245b702012-08-16 17:10:41 +0530368{
Namarta Kohli1245b702012-08-16 17:10:41 +0530369 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000370 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900371 int i, ret;
Charles Keepax15e2e612013-01-24 09:44:29 +0000372
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900373 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000374 if (!component->driver->compr_ops ||
375 !component->driver->compr_ops->trigger)
376 continue;
377
Charles Keepax52cadf12019-02-05 11:18:12 +0000378 ret = component->driver->compr_ops->trigger(cstream, cmd);
379 if (ret < 0)
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000380 return ret;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000381 }
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000382
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000383 return 0;
384}
385
386static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
387{
388 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
389 struct snd_soc_dai *codec_dai = rtd->codec_dai;
390 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
391 int ret;
392
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300393 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000394
395 ret = soc_compr_components_trigger(cstream, cmd);
396 if (ret < 0)
397 goto out;
398
Vinod Koul2e622ae2016-11-13 12:10:02 +0530399 if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger)
400 cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai);
401
Mark Brownda183962013-02-06 15:44:07 +0000402 switch (cmd) {
403 case SNDRV_PCM_TRIGGER_START:
404 snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction);
405 break;
406 case SNDRV_PCM_TRIGGER_STOP:
407 snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
408 break;
Mark Browne38b9b72013-02-06 13:52:42 +0000409 }
Namarta Kohli1245b702012-08-16 17:10:41 +0530410
Charles Keepax15e2e612013-01-24 09:44:29 +0000411out:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300412 mutex_unlock(&rtd->card->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530413 return ret;
414}
415
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000416static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
417{
418 struct snd_soc_pcm_runtime *fe = cstream->private_data;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530419 struct snd_soc_dai *cpu_dai = fe->cpu_dai;
Charles Keepax52cadf12019-02-05 11:18:12 +0000420 int ret, stream;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000421
422 if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN ||
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000423 cmd == SND_COMPR_TRIGGER_DRAIN)
424 return soc_compr_components_trigger(cstream, cmd);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000425
426 if (cstream->direction == SND_COMPRESS_PLAYBACK)
427 stream = SNDRV_PCM_STREAM_PLAYBACK;
428 else
429 stream = SNDRV_PCM_STREAM_CAPTURE;
430
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000431 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
432
Vinod Koul2e622ae2016-11-13 12:10:02 +0530433 if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) {
434 ret = cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai);
435 if (ret < 0)
436 goto out;
437 }
438
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000439 ret = soc_compr_components_trigger(cstream, cmd);
440 if (ret < 0)
441 goto out;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000442
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000443 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
444
445 ret = dpcm_be_dai_trigger(fe, stream, cmd);
446
447 switch (cmd) {
448 case SNDRV_PCM_TRIGGER_START:
449 case SNDRV_PCM_TRIGGER_RESUME:
450 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
451 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
452 break;
453 case SNDRV_PCM_TRIGGER_STOP:
454 case SNDRV_PCM_TRIGGER_SUSPEND:
455 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
456 break;
457 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
458 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
459 break;
460 }
461
462out:
463 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
464 mutex_unlock(&fe->card->mutex);
465 return ret;
466}
467
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000468static int soc_compr_components_set_params(struct snd_compr_stream *cstream,
469 struct snd_compr_params *params)
Namarta Kohli1245b702012-08-16 17:10:41 +0530470{
471 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000472 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900473 int i, ret;
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000474
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900475 for_each_rtd_components(rtd, i, component) {
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000476 if (!component->driver->compr_ops ||
477 !component->driver->compr_ops->set_params)
478 continue;
479
480 ret = component->driver->compr_ops->set_params(cstream, params);
481 if (ret < 0)
482 return ret;
483 }
484
485 return 0;
486}
487
488static int soc_compr_set_params(struct snd_compr_stream *cstream,
489 struct snd_compr_params *params)
490{
491 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530492 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Charles Keepax52cadf12019-02-05 11:18:12 +0000493 int ret;
Namarta Kohli1245b702012-08-16 17:10:41 +0530494
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300495 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax15e2e612013-01-24 09:44:29 +0000496
Charles Keepaxef050be2018-04-24 16:39:02 +0100497 /*
498 * First we call set_params for the CPU DAI, then the component
499 * driver this should configure the SoC side. If the machine has
500 * compressed ops then we call that as well. The expectation is
501 * that these callbacks will configure everything for this compress
502 * path, like configuring a PCM port for a CODEC.
Namarta Kohli1245b702012-08-16 17:10:41 +0530503 */
Vinod Koul2e622ae2016-11-13 12:10:02 +0530504 if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) {
505 ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai);
506 if (ret < 0)
507 goto err;
508 }
509
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000510 ret = soc_compr_components_set_params(cstream, params);
511 if (ret < 0)
512 goto err;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000513
Namarta Kohli1245b702012-08-16 17:10:41 +0530514 if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) {
515 ret = rtd->dai_link->compr_ops->set_params(cstream);
516 if (ret < 0)
Charles Keepaxfa40ef22013-03-27 16:39:01 +0000517 goto err;
Namarta Kohli1245b702012-08-16 17:10:41 +0530518 }
519
Charles Keepax2c071ed2013-05-20 08:33:54 +0100520 if (cstream->direction == SND_COMPRESS_PLAYBACK)
521 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
Charles Keepax89027d92018-04-26 17:30:07 +0100522 SND_SOC_DAPM_STREAM_START);
Charles Keepax2c071ed2013-05-20 08:33:54 +0100523 else
524 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
Charles Keepax89027d92018-04-26 17:30:07 +0100525 SND_SOC_DAPM_STREAM_START);
Namarta Kohli1245b702012-08-16 17:10:41 +0530526
Charles Keepaxfa40ef22013-03-27 16:39:01 +0000527 /* cancel any delayed stream shutdown that is pending */
528 rtd->pop_wait = 0;
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300529 mutex_unlock(&rtd->card->pcm_mutex);
Charles Keepaxfa40ef22013-03-27 16:39:01 +0000530
531 cancel_delayed_work_sync(&rtd->delayed_work);
532
Charles Keepax52cadf12019-02-05 11:18:12 +0000533 return 0;
Charles Keepaxfa40ef22013-03-27 16:39:01 +0000534
535err:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300536 mutex_unlock(&rtd->card->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530537 return ret;
538}
539
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000540static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
Charles Keepax89027d92018-04-26 17:30:07 +0100541 struct snd_compr_params *params)
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000542{
543 struct snd_soc_pcm_runtime *fe = cstream->private_data;
Satish Babu Patakokila01b8ced2017-06-16 17:33:40 -0700544 struct snd_pcm_substream *fe_substream =
545 fe->pcm->streams[cstream->direction].substream;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530546 struct snd_soc_dai *cpu_dai = fe->cpu_dai;
Charles Keepax52cadf12019-02-05 11:18:12 +0000547 int ret, stream;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000548
549 if (cstream->direction == SND_COMPRESS_PLAYBACK)
550 stream = SNDRV_PCM_STREAM_PLAYBACK;
551 else
552 stream = SNDRV_PCM_STREAM_CAPTURE;
553
554 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
555
Srinivas Kandagatla0b0722e2018-08-03 13:30:03 +0100556 /*
557 * Create an empty hw_params for the BE as the machine driver must
558 * fix this up to match DSP decoder and ASRC configuration.
559 * I.e. machine driver fixup for compressed BE is mandatory.
560 */
561 memset(&fe->dpcm[fe_substream->stream].hw_params, 0,
562 sizeof(struct snd_pcm_hw_params));
563
564 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
565
566 ret = dpcm_be_dai_hw_params(fe, stream);
567 if (ret < 0)
568 goto out;
569
570 ret = dpcm_be_dai_prepare(fe, stream);
571 if (ret < 0)
572 goto out;
573
Vinod Koul2e622ae2016-11-13 12:10:02 +0530574 if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) {
575 ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai);
576 if (ret < 0)
577 goto out;
578 }
579
Charles Keepax4ef0ecb2019-02-05 11:18:13 +0000580 ret = soc_compr_components_set_params(cstream, params);
581 if (ret < 0)
582 goto out;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000583
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000584 if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) {
585 ret = fe->dai_link->compr_ops->set_params(cstream);
586 if (ret < 0)
587 goto out;
588 }
589
Daniel Mack15f6b092014-10-19 09:07:35 +0200590 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000591 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
592
593out:
594 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
595 mutex_unlock(&fe->card->mutex);
596 return ret;
597}
598
Namarta Kohli1245b702012-08-16 17:10:41 +0530599static int soc_compr_get_params(struct snd_compr_stream *cstream,
Charles Keepax89027d92018-04-26 17:30:07 +0100600 struct snd_codec *params)
Namarta Kohli1245b702012-08-16 17:10:41 +0530601{
602 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000603 struct snd_soc_component *component;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530604 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900605 int i, ret = 0;
Namarta Kohli1245b702012-08-16 17:10:41 +0530606
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300607 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax15e2e612013-01-24 09:44:29 +0000608
Vinod Koul2e622ae2016-11-13 12:10:02 +0530609 if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_params) {
610 ret = cpu_dai->driver->cops->get_params(cstream, params, cpu_dai);
611 if (ret < 0)
612 goto err;
613 }
614
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900615 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000616 if (!component->driver->compr_ops ||
617 !component->driver->compr_ops->get_params)
618 continue;
619
Charles Keepax52cadf12019-02-05 11:18:12 +0000620 ret = component->driver->compr_ops->get_params(cstream, params);
621 break;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000622 }
Namarta Kohli1245b702012-08-16 17:10:41 +0530623
Vinod Koul2e622ae2016-11-13 12:10:02 +0530624err:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300625 mutex_unlock(&rtd->card->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530626 return ret;
627}
628
629static int soc_compr_get_caps(struct snd_compr_stream *cstream,
Charles Keepax89027d92018-04-26 17:30:07 +0100630 struct snd_compr_caps *caps)
Namarta Kohli1245b702012-08-16 17:10:41 +0530631{
632 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000633 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900634 int i, ret = 0;
Namarta Kohli1245b702012-08-16 17:10:41 +0530635
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300636 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax15e2e612013-01-24 09:44:29 +0000637
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900638 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000639 if (!component->driver->compr_ops ||
640 !component->driver->compr_ops->get_caps)
641 continue;
642
Charles Keepax52cadf12019-02-05 11:18:12 +0000643 ret = component->driver->compr_ops->get_caps(cstream, caps);
644 break;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000645 }
646
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300647 mutex_unlock(&rtd->card->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530648 return ret;
649}
650
651static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream,
Charles Keepax89027d92018-04-26 17:30:07 +0100652 struct snd_compr_codec_caps *codec)
Namarta Kohli1245b702012-08-16 17:10:41 +0530653{
654 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000655 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900656 int i, ret = 0;
Namarta Kohli1245b702012-08-16 17:10:41 +0530657
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300658 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax15e2e612013-01-24 09:44:29 +0000659
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900660 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000661 if (!component->driver->compr_ops ||
662 !component->driver->compr_ops->get_codec_caps)
663 continue;
664
Charles Keepax52cadf12019-02-05 11:18:12 +0000665 ret = component->driver->compr_ops->get_codec_caps(cstream,
666 codec);
667 break;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000668 }
669
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300670 mutex_unlock(&rtd->card->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530671 return ret;
672}
673
674static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
675{
676 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000677 struct snd_soc_component *component;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530678 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900679 int i, ret = 0;
Namarta Kohli1245b702012-08-16 17:10:41 +0530680
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300681 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax15e2e612013-01-24 09:44:29 +0000682
Vinod Koul2e622ae2016-11-13 12:10:02 +0530683 if (cpu_dai->driver->cops && cpu_dai->driver->cops->ack) {
684 ret = cpu_dai->driver->cops->ack(cstream, bytes, cpu_dai);
685 if (ret < 0)
686 goto err;
687 }
688
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900689 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000690 if (!component->driver->compr_ops ||
691 !component->driver->compr_ops->ack)
692 continue;
693
Charles Keepax52cadf12019-02-05 11:18:12 +0000694 ret = component->driver->compr_ops->ack(cstream, bytes);
695 if (ret < 0)
696 goto err;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000697 }
Namarta Kohli1245b702012-08-16 17:10:41 +0530698
Vinod Koul2e622ae2016-11-13 12:10:02 +0530699err:
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300700 mutex_unlock(&rtd->card->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530701 return ret;
702}
703
704static int soc_compr_pointer(struct snd_compr_stream *cstream,
Charles Keepax89027d92018-04-26 17:30:07 +0100705 struct snd_compr_tstamp *tstamp)
Namarta Kohli1245b702012-08-16 17:10:41 +0530706{
707 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000708 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900709 int i, ret = 0;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530710 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Namarta Kohli1245b702012-08-16 17:10:41 +0530711
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300712 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax15e2e612013-01-24 09:44:29 +0000713
Vinod Koul2e622ae2016-11-13 12:10:02 +0530714 if (cpu_dai->driver->cops && cpu_dai->driver->cops->pointer)
715 cpu_dai->driver->cops->pointer(cstream, tstamp, cpu_dai);
716
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900717 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000718 if (!component->driver->compr_ops ||
719 !component->driver->compr_ops->pointer)
720 continue;
721
Charles Keepax52cadf12019-02-05 11:18:12 +0000722 ret = component->driver->compr_ops->pointer(cstream, tstamp);
723 break;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000724 }
725
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300726 mutex_unlock(&rtd->card->pcm_mutex);
Charles Keepax7c9190f2016-06-20 09:51:32 +0100727 return ret;
Namarta Kohli1245b702012-08-16 17:10:41 +0530728}
729
Charles Keepax1f88eb02013-02-05 10:41:47 +0000730static int soc_compr_copy(struct snd_compr_stream *cstream,
Charles Keepax4daf8912013-04-18 11:01:38 +0100731 char __user *buf, size_t count)
Charles Keepax1f88eb02013-02-05 10:41:47 +0000732{
733 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000734 struct snd_soc_component *component;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900735 int i, ret = 0;
Charles Keepax1f88eb02013-02-05 10:41:47 +0000736
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300737 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
Charles Keepax1f88eb02013-02-05 10:41:47 +0000738
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900739 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000740 if (!component->driver->compr_ops ||
741 !component->driver->compr_ops->copy)
742 continue;
743
Charles Keepax290df4d32018-01-26 13:08:43 +0000744 ret = component->driver->compr_ops->copy(cstream, buf, count);
745 break;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000746 }
Charles Keepax290df4d32018-01-26 13:08:43 +0000747
Peter Ujfalusi72b745e2019-08-13 13:45:32 +0300748 mutex_unlock(&rtd->card->pcm_mutex);
Charles Keepax1f88eb02013-02-05 10:41:47 +0000749 return ret;
750}
751
Vinod Koul02bd90e2013-07-28 20:06:15 +0530752static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
Charles Keepax89027d92018-04-26 17:30:07 +0100753 struct snd_compr_metadata *metadata)
Jeeja KP36953d92013-03-26 21:22:28 +0530754{
755 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000756 struct snd_soc_component *component;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530757 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900758 int i, ret;
Jeeja KP36953d92013-03-26 21:22:28 +0530759
Vinod Koul2e622ae2016-11-13 12:10:02 +0530760 if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_metadata) {
761 ret = cpu_dai->driver->cops->set_metadata(cstream, metadata, cpu_dai);
762 if (ret < 0)
763 return ret;
764 }
765
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900766 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000767 if (!component->driver->compr_ops ||
768 !component->driver->compr_ops->set_metadata)
769 continue;
770
Charles Keepax52cadf12019-02-05 11:18:12 +0000771 ret = component->driver->compr_ops->set_metadata(cstream,
772 metadata);
773 if (ret < 0)
774 return ret;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000775 }
Jeeja KP36953d92013-03-26 21:22:28 +0530776
Charles Keepax52cadf12019-02-05 11:18:12 +0000777 return 0;
Jeeja KP36953d92013-03-26 21:22:28 +0530778}
779
Vinod Koul02bd90e2013-07-28 20:06:15 +0530780static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
Charles Keepax89027d92018-04-26 17:30:07 +0100781 struct snd_compr_metadata *metadata)
Jeeja KP36953d92013-03-26 21:22:28 +0530782{
783 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000784 struct snd_soc_component *component;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530785 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900786 int i, ret;
Jeeja KP36953d92013-03-26 21:22:28 +0530787
Vinod Koul2e622ae2016-11-13 12:10:02 +0530788 if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_metadata) {
789 ret = cpu_dai->driver->cops->get_metadata(cstream, metadata, cpu_dai);
790 if (ret < 0)
791 return ret;
792 }
793
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900794 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000795 if (!component->driver->compr_ops ||
796 !component->driver->compr_ops->get_metadata)
797 continue;
798
Charles Keepax52cadf12019-02-05 11:18:12 +0000799 return component->driver->compr_ops->get_metadata(cstream,
800 metadata);
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000801 }
Jeeja KP36953d92013-03-26 21:22:28 +0530802
Charles Keepax52cadf12019-02-05 11:18:12 +0000803 return 0;
Jeeja KP36953d92013-03-26 21:22:28 +0530804}
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000805
Namarta Kohli1245b702012-08-16 17:10:41 +0530806/* ASoC Compress operations */
807static struct snd_compr_ops soc_compr_ops = {
808 .open = soc_compr_open,
809 .free = soc_compr_free,
810 .set_params = soc_compr_set_params,
Vinod Koul02bd90e2013-07-28 20:06:15 +0530811 .set_metadata = soc_compr_set_metadata,
812 .get_metadata = soc_compr_get_metadata,
Namarta Kohli1245b702012-08-16 17:10:41 +0530813 .get_params = soc_compr_get_params,
814 .trigger = soc_compr_trigger,
815 .pointer = soc_compr_pointer,
816 .ack = soc_compr_ack,
817 .get_caps = soc_compr_get_caps,
818 .get_codec_caps = soc_compr_get_codec_caps
819};
820
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000821/* ASoC Dynamic Compress operations */
822static struct snd_compr_ops soc_compr_dyn_ops = {
823 .open = soc_compr_open_fe,
824 .free = soc_compr_free_fe,
825 .set_params = soc_compr_set_params_fe,
826 .get_params = soc_compr_get_params,
827 .set_metadata = soc_compr_set_metadata,
828 .get_metadata = soc_compr_get_metadata,
829 .trigger = soc_compr_trigger_fe,
830 .pointer = soc_compr_pointer,
831 .ack = soc_compr_ack,
832 .get_caps = soc_compr_get_caps,
833 .get_codec_caps = soc_compr_get_codec_caps
834};
835
Jie Yang6f0c4222015-10-13 23:41:00 +0800836/**
837 * snd_soc_new_compress - create a new compress.
838 *
839 * @rtd: The runtime for which we will create compress
840 * @num: the device index number (zero based - shared with normal PCMs)
841 *
842 * Return: 0 for success, else error.
843 */
844int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
Namarta Kohli1245b702012-08-16 17:10:41 +0530845{
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000846 struct snd_soc_component *component;
Namarta Kohli1245b702012-08-16 17:10:41 +0530847 struct snd_soc_dai *codec_dai = rtd->codec_dai;
848 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
849 struct snd_compr *compr;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000850 struct snd_pcm *be_pcm;
Namarta Kohli1245b702012-08-16 17:10:41 +0530851 char new_name[64];
852 int ret = 0, direction = 0;
Vinod Koula1068042016-01-07 21:48:14 +0530853 int playback = 0, capture = 0;
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900854 int i;
Namarta Kohli1245b702012-08-16 17:10:41 +0530855
Benoit Cousson8151d5e2014-07-08 23:19:37 +0200856 if (rtd->num_codecs > 1) {
Charles Keepax141dfc92018-01-26 13:08:45 +0000857 dev_err(rtd->card->dev,
858 "Compress ASoC: Multicodec not supported\n");
Benoit Cousson8151d5e2014-07-08 23:19:37 +0200859 return -EINVAL;
860 }
861
Namarta Kohli1245b702012-08-16 17:10:41 +0530862 /* check client and interface hw capabilities */
Kuninori Morimoto467fece2019-07-22 10:36:16 +0900863 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
864 snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_PLAYBACK))
Vinod Koula1068042016-01-07 21:48:14 +0530865 playback = 1;
Kuninori Morimoto467fece2019-07-22 10:36:16 +0900866 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
867 snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_CAPTURE))
Vinod Koula1068042016-01-07 21:48:14 +0530868 capture = 1;
869
Vinod Koula1068042016-01-07 21:48:14 +0530870 /*
871 * Compress devices are unidirectional so only one of the directions
872 * should be set, check for that (xor)
873 */
874 if (playback + capture != 1) {
Charles Keepax141dfc92018-01-26 13:08:45 +0000875 dev_err(rtd->card->dev,
876 "Compress ASoC: Invalid direction for P %d, C %d\n",
877 playback, capture);
Charles Keepaxdaa2db52013-04-18 11:02:38 +0100878 return -EINVAL;
Vinod Koula1068042016-01-07 21:48:14 +0530879 }
880
Peng Donglinaeb6fa02017-08-16 22:47:53 +0800881 if (playback)
Vinod Koula1068042016-01-07 21:48:14 +0530882 direction = SND_COMPRESS_PLAYBACK;
883 else
884 direction = SND_COMPRESS_CAPTURE;
Charles Keepaxdaa2db52013-04-18 11:02:38 +0100885
Amadeusz Sławiński09f448a2019-06-17 13:36:36 +0200886 compr = devm_kzalloc(rtd->card->dev, sizeof(*compr), GFP_KERNEL);
Markus Elfring7a0cf422017-08-10 16:21:34 +0200887 if (!compr)
Namarta Kohli1245b702012-08-16 17:10:41 +0530888 return -ENOMEM;
Namarta Kohli1245b702012-08-16 17:10:41 +0530889
Charles Keepax1f88eb02013-02-05 10:41:47 +0000890 compr->ops = devm_kzalloc(rtd->card->dev, sizeof(soc_compr_ops),
891 GFP_KERNEL);
Amadeusz Sławiński09f448a2019-06-17 13:36:36 +0200892 if (!compr->ops)
893 return -ENOMEM;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000894
895 if (rtd->dai_link->dynamic) {
896 snprintf(new_name, sizeof(new_name), "(%s)",
897 rtd->dai_link->stream_name);
898
899 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
Qais Yousefd3268a42015-01-14 08:47:29 +0000900 rtd->dai_link->dpcm_playback,
901 rtd->dai_link->dpcm_capture, &be_pcm);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000902 if (ret < 0) {
Charles Keepax141dfc92018-01-26 13:08:45 +0000903 dev_err(rtd->card->dev,
904 "Compress ASoC: can't create compressed for %s: %d\n",
905 rtd->dai_link->name, ret);
Amadeusz Sławiński09f448a2019-06-17 13:36:36 +0200906 return ret;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000907 }
908
909 rtd->pcm = be_pcm;
910 rtd->fe_compr = 1;
Qais Yousefd3268a42015-01-14 08:47:29 +0000911 if (rtd->dai_link->dpcm_playback)
912 be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
913 else if (rtd->dai_link->dpcm_capture)
914 be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000915 memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops));
Peng Donglinaeb6fa02017-08-16 22:47:53 +0800916 } else {
917 snprintf(new_name, sizeof(new_name), "%s %s-%d",
918 rtd->dai_link->stream_name, codec_dai->name, num);
919
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000920 memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));
Peng Donglinaeb6fa02017-08-16 22:47:53 +0800921 }
Charles Keepax1f88eb02013-02-05 10:41:47 +0000922
Kuninori Morimoto613fb502020-01-10 11:35:21 +0900923 for_each_rtd_components(rtd, i, component) {
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000924 if (!component->driver->compr_ops ||
925 !component->driver->compr_ops->copy)
926 continue;
927
928 compr->ops->copy = soc_compr_copy;
Charles Keepaxca76db62018-04-26 17:30:04 +0100929 break;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000930 }
931
Namarta Kohli1245b702012-08-16 17:10:41 +0530932 mutex_init(&compr->lock);
Richard Fitzgeralde5241a82015-11-25 13:00:24 +0000933 ret = snd_compress_new(rtd->card->snd_card, num, direction,
934 new_name, compr);
Namarta Kohli1245b702012-08-16 17:10:41 +0530935 if (ret < 0) {
Kuninori Morimotoe5acfc72017-12-05 04:23:05 +0000936 component = rtd->codec_dai->component;
Charles Keepax141dfc92018-01-26 13:08:45 +0000937 dev_err(component->dev,
938 "Compress ASoC: can't create compress for codec %s: %d\n",
939 component->name, ret);
Amadeusz Sławiński09f448a2019-06-17 13:36:36 +0200940 return ret;
Namarta Kohli1245b702012-08-16 17:10:41 +0530941 }
942
Charles Keepax202c8f72013-01-24 09:44:30 +0000943 /* DAPM dai link stream work */
Curtis Malainey4bf2e382019-12-03 09:30:07 -0800944 rtd->close_delayed_work_func = close_delayed_work;
Charles Keepax202c8f72013-01-24 09:44:30 +0000945
Namarta Kohli1245b702012-08-16 17:10:41 +0530946 rtd->compr = compr;
947 compr->private_data = rtd;
948
Charles Keepax141dfc92018-01-26 13:08:45 +0000949 dev_info(rtd->card->dev, "Compress ASoC: %s <-> %s mapping ok\n",
950 codec_dai->name, cpu_dai->name);
Charles Keepax1f88eb02013-02-05 10:41:47 +0000951
Amadeusz Sławiński09f448a2019-06-17 13:36:36 +0200952 return 0;
Namarta Kohli1245b702012-08-16 17:10:41 +0530953}
Jie Yang6f0c4222015-10-13 23:41:00 +0800954EXPORT_SYMBOL_GPL(snd_soc_new_compress);