blob: 948505f7422927a67ed8abc38f4438470dd34bea [file] [log] [blame]
Namarta Kohli1245b702012-08-16 17:10:41 +05301/*
2 * soc-compress.c -- ALSA SoC Compress
3 *
4 * Copyright (C) 2012 Intel Corp.
5 *
6 * Authors: Namarta Kohli <namartax.kohli@intel.com>
7 * Ramesh Babu K V <ramesh.babu@linux.intel.com>
8 * Vinod Koul <vinod.koul@linux.intel.com>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
16
17#include <linux/kernel.h>
18#include <linux/init.h>
19#include <linux/delay.h>
20#include <linux/slab.h>
21#include <linux/workqueue.h>
22#include <sound/core.h>
23#include <sound/compress_params.h>
24#include <sound/compress_driver.h>
25#include <sound/soc.h>
26#include <sound/initval.h>
Liam Girdwood2a99ef02014-01-17 17:03:56 +000027#include <sound/soc-dpcm.h>
Namarta Kohli1245b702012-08-16 17:10:41 +053028
29static int soc_compr_open(struct snd_compr_stream *cstream)
30{
31 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
32 struct snd_soc_platform *platform = rtd->platform;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +000033 struct snd_soc_component *component;
34 struct snd_soc_rtdcom_list *rtdcom;
Vinod Koul2e622ae2016-11-13 12:10:02 +053035 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Charles Keepax572e6c82018-04-24 16:39:01 +010036 int ret;
Namarta Kohli1245b702012-08-16 17:10:41 +053037
Charles Keepax15e2e612013-01-24 09:44:29 +000038 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
39
Vinod Koul2e622ae2016-11-13 12:10:02 +053040 if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) {
41 ret = cpu_dai->driver->cops->startup(cstream, cpu_dai);
42 if (ret < 0) {
Charles Keepax141dfc92018-01-26 13:08:45 +000043 dev_err(cpu_dai->dev,
44 "Compress ASoC: can't open interface %s: %d\n",
Vinod Koul2e622ae2016-11-13 12:10:02 +053045 cpu_dai->name, ret);
46 goto out;
47 }
48 }
49
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +000050 if (platform && platform->driver->compr_ops && platform->driver->compr_ops->open) {
Namarta Kohli1245b702012-08-16 17:10:41 +053051 ret = platform->driver->compr_ops->open(cstream);
52 if (ret < 0) {
Charles Keepax141dfc92018-01-26 13:08:45 +000053 dev_err(platform->dev,
54 "Compress ASoC: can't open platform %s: %d\n",
55 platform->component.name, ret);
Vinod Koul2e622ae2016-11-13 12:10:02 +053056 goto plat_err;
Namarta Kohli1245b702012-08-16 17:10:41 +053057 }
58 }
59
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +000060 for_each_rtdcom(rtd, rtdcom) {
61 component = rtdcom->component;
62
63 /* ignore duplication for now */
64 if (platform && (component == &platform->component))
65 continue;
66
67 if (!component->driver->compr_ops ||
68 !component->driver->compr_ops->open)
69 continue;
70
Charles Keepax572e6c82018-04-24 16:39:01 +010071 ret = component->driver->compr_ops->open(cstream);
72 if (ret < 0) {
Charles Keepax141dfc92018-01-26 13:08:45 +000073 dev_err(component->dev,
74 "Compress ASoC: can't open platform %s: %d\n",
Charles Keepax572e6c82018-04-24 16:39:01 +010075 component->name, ret);
76 goto machine_err;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +000077 }
78 }
Charles Keepax572e6c82018-04-24 16:39:01 +010079 component = NULL;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +000080
Namarta Kohli1245b702012-08-16 17:10:41 +053081 if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->startup) {
82 ret = rtd->dai_link->compr_ops->startup(cstream);
83 if (ret < 0) {
Charles Keepax141dfc92018-01-26 13:08:45 +000084 dev_err(rtd->dev,
85 "Compress ASoC: %s startup failed: %d\n",
86 rtd->dai_link->name, ret);
Namarta Kohli1245b702012-08-16 17:10:41 +053087 goto machine_err;
88 }
89 }
90
Lars-Peter Clausen24894b72014-03-05 13:17:43 +010091 snd_soc_runtime_activate(rtd, cstream->direction);
Namarta Kohli1245b702012-08-16 17:10:41 +053092
Charles Keepax15e2e612013-01-24 09:44:29 +000093 mutex_unlock(&rtd->pcm_mutex);
94
Namarta Kohli1245b702012-08-16 17:10:41 +053095 return 0;
96
97machine_err:
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +000098 for_each_rtdcom(rtd, rtdcom) {
Charles Keepax572e6c82018-04-24 16:39:01 +010099 struct snd_soc_component *err_comp = rtdcom->component;
100
101 if (err_comp == component)
102 break;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000103
104 /* ignore duplication for now */
Charles Keepax572e6c82018-04-24 16:39:01 +0100105 if (platform && (err_comp == &platform->component))
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000106 continue;
107
Charles Keepax572e6c82018-04-24 16:39:01 +0100108 if (!err_comp->driver->compr_ops ||
109 !err_comp->driver->compr_ops->free)
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000110 continue;
111
Charles Keepax572e6c82018-04-24 16:39:01 +0100112 err_comp->driver->compr_ops->free(cstream);
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000113 }
114
115 if (platform && platform->driver->compr_ops && platform->driver->compr_ops->free)
Namarta Kohli1245b702012-08-16 17:10:41 +0530116 platform->driver->compr_ops->free(cstream);
Vinod Koul2e622ae2016-11-13 12:10:02 +0530117plat_err:
118 if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
119 cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
Namarta Kohli1245b702012-08-16 17:10:41 +0530120out:
Charles Keepax15e2e612013-01-24 09:44:29 +0000121 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530122 return ret;
123}
124
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000125static int soc_compr_open_fe(struct snd_compr_stream *cstream)
126{
127 struct snd_soc_pcm_runtime *fe = cstream->private_data;
Satish Babu Patakokila01b8ced2017-06-16 17:33:40 -0700128 struct snd_pcm_substream *fe_substream =
129 fe->pcm->streams[cstream->direction].substream;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000130 struct snd_soc_platform *platform = fe->platform;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000131 struct snd_soc_component *component;
132 struct snd_soc_rtdcom_list *rtdcom;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530133 struct snd_soc_dai *cpu_dai = fe->cpu_dai;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000134 struct snd_soc_dpcm *dpcm;
135 struct snd_soc_dapm_widget_list *list;
136 int stream;
Charles Keepax572e6c82018-04-24 16:39:01 +0100137 int ret;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000138
139 if (cstream->direction == SND_COMPRESS_PLAYBACK)
140 stream = SNDRV_PCM_STREAM_PLAYBACK;
141 else
142 stream = SNDRV_PCM_STREAM_CAPTURE;
143
144 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
145
Vinod Koul2e622ae2016-11-13 12:10:02 +0530146 if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) {
147 ret = cpu_dai->driver->cops->startup(cstream, cpu_dai);
148 if (ret < 0) {
Charles Keepax141dfc92018-01-26 13:08:45 +0000149 dev_err(cpu_dai->dev,
150 "Compress ASoC: can't open interface %s: %d\n",
Vinod Koul2e622ae2016-11-13 12:10:02 +0530151 cpu_dai->name, ret);
152 goto out;
153 }
154 }
155
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000156 if (platform && platform->driver->compr_ops && platform->driver->compr_ops->open) {
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000157 ret = platform->driver->compr_ops->open(cstream);
158 if (ret < 0) {
Charles Keepax141dfc92018-01-26 13:08:45 +0000159 dev_err(platform->dev,
160 "Compress ASoC: can't open platform %s: %d\n",
161 platform->component.name, ret);
Vinod Koul2e622ae2016-11-13 12:10:02 +0530162 goto plat_err;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000163 }
164 }
165
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000166 for_each_rtdcom(fe, rtdcom) {
167 component = rtdcom->component;
168
169 /* ignore duplication for now */
170 if (platform && (component == &platform->component))
171 continue;
172
173 if (!component->driver->compr_ops ||
174 !component->driver->compr_ops->open)
175 continue;
176
Charles Keepax572e6c82018-04-24 16:39:01 +0100177 ret = component->driver->compr_ops->open(cstream);
178 if (ret < 0) {
Charles Keepax141dfc92018-01-26 13:08:45 +0000179 dev_err(component->dev,
180 "Compress ASoC: can't open platform %s: %d\n",
Charles Keepax572e6c82018-04-24 16:39:01 +0100181 component->name, ret);
182 goto machine_err;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000183 }
184 }
Charles Keepax572e6c82018-04-24 16:39:01 +0100185 component = NULL;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000186
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000187 if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->startup) {
188 ret = fe->dai_link->compr_ops->startup(cstream);
189 if (ret < 0) {
Charles Keepax141dfc92018-01-26 13:08:45 +0000190 pr_err("Compress ASoC: %s startup failed: %d\n",
191 fe->dai_link->name, ret);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000192 goto machine_err;
193 }
194 }
195
196 fe->dpcm[stream].runtime = fe_substream->runtime;
197
Qiao Zhou8f70e512014-09-10 17:54:07 +0800198 ret = dpcm_path_get(fe, stream, &list);
Qiao Zhou2e4ec1c2014-09-12 09:41:31 +0800199 if (ret < 0)
Qiao Zhou8f70e512014-09-10 17:54:07 +0800200 goto fe_err;
Qiao Zhou2e4ec1c2014-09-12 09:41:31 +0800201 else if (ret == 0)
Charles Keepax141dfc92018-01-26 13:08:45 +0000202 dev_dbg(fe->dev, "Compress ASoC: %s no valid %s route\n",
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000203 fe->dai_link->name, stream ? "capture" : "playback");
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000204
205 /* calculate valid and active FE <-> BE dpcms */
206 dpcm_process_paths(fe, stream, &list, 1);
207
208 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
209
210 ret = dpcm_be_dai_startup(fe, stream);
211 if (ret < 0) {
212 /* clean up all links */
213 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
214 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
215
216 dpcm_be_disconnect(fe, stream);
217 fe->dpcm[stream].runtime = NULL;
Charles Keepaxb0f12c62016-08-16 11:24:46 +0100218 goto path_err;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000219 }
220
221 dpcm_clear_pending_state(fe, stream);
222 dpcm_path_put(&list);
223
224 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
225 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
226
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100227 snd_soc_runtime_activate(fe, stream);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000228
229 mutex_unlock(&fe->card->mutex);
230
231 return 0;
232
Charles Keepaxb0f12c62016-08-16 11:24:46 +0100233path_err:
234 dpcm_path_put(&list);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000235fe_err:
236 if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
237 fe->dai_link->compr_ops->shutdown(cstream);
238machine_err:
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000239 for_each_rtdcom(fe, rtdcom) {
Charles Keepax572e6c82018-04-24 16:39:01 +0100240 struct snd_soc_component *err_comp = rtdcom->component;
241
242 if (err_comp == component)
243 break;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000244
245 /* ignore duplication for now */
Charles Keepax572e6c82018-04-24 16:39:01 +0100246 if (platform && (err_comp == &platform->component))
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000247 continue;
248
Charles Keepax572e6c82018-04-24 16:39:01 +0100249 if (!err_comp->driver->compr_ops ||
250 !err_comp->driver->compr_ops->free)
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000251 continue;
252
Charles Keepax572e6c82018-04-24 16:39:01 +0100253 err_comp->driver->compr_ops->free(cstream);
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000254 }
255
256 if (platform && platform->driver->compr_ops && platform->driver->compr_ops->free)
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000257 platform->driver->compr_ops->free(cstream);
Vinod Koul2e622ae2016-11-13 12:10:02 +0530258plat_err:
259 if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
260 cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000261out:
262 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
263 mutex_unlock(&fe->card->mutex);
264 return ret;
265}
266
Charles Keepax202c8f72013-01-24 09:44:30 +0000267/*
268 * Power down the audio subsystem pmdown_time msecs after close is called.
269 * This is to ensure there are no pops or clicks in between any music tracks
270 * due to DAPM power cycling.
271 */
272static void close_delayed_work(struct work_struct *work)
273{
274 struct snd_soc_pcm_runtime *rtd =
275 container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
276 struct snd_soc_dai *codec_dai = rtd->codec_dai;
277
278 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
279
Charles Keepax141dfc92018-01-26 13:08:45 +0000280 dev_dbg(rtd->dev,
281 "Compress ASoC: pop wq checking: %s status: %s waiting: %s\n",
282 codec_dai->driver->playback.stream_name,
283 codec_dai->playback_active ? "active" : "inactive",
284 rtd->pop_wait ? "yes" : "no");
Charles Keepax202c8f72013-01-24 09:44:30 +0000285
286 /* are we waiting on this codec DAI stream */
287 if (rtd->pop_wait == 1) {
288 rtd->pop_wait = 0;
289 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
290 SND_SOC_DAPM_STREAM_STOP);
291 }
292
293 mutex_unlock(&rtd->pcm_mutex);
294}
295
Namarta Kohli1245b702012-08-16 17:10:41 +0530296static int soc_compr_free(struct snd_compr_stream *cstream)
297{
298 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
299 struct snd_soc_platform *platform = rtd->platform;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000300 struct snd_soc_component *component;
301 struct snd_soc_rtdcom_list *rtdcom;
Namarta Kohli1245b702012-08-16 17:10:41 +0530302 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
303 struct snd_soc_dai *codec_dai = rtd->codec_dai;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100304 int stream;
Namarta Kohli1245b702012-08-16 17:10:41 +0530305
Charles Keepax15e2e612013-01-24 09:44:29 +0000306 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
307
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100308 if (cstream->direction == SND_COMPRESS_PLAYBACK)
309 stream = SNDRV_PCM_STREAM_PLAYBACK;
310 else
311 stream = SNDRV_PCM_STREAM_CAPTURE;
312
313 snd_soc_runtime_deactivate(rtd, stream);
Namarta Kohli1245b702012-08-16 17:10:41 +0530314
Mark Brownda183962013-02-06 15:44:07 +0000315 snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
316
Namarta Kohli1245b702012-08-16 17:10:41 +0530317 if (!cpu_dai->active)
318 cpu_dai->rate = 0;
319
320 if (!codec_dai->active)
321 codec_dai->rate = 0;
322
Namarta Kohli1245b702012-08-16 17:10:41 +0530323 if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown)
324 rtd->dai_link->compr_ops->shutdown(cstream);
325
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000326 for_each_rtdcom(rtd, rtdcom) {
327 component = rtdcom->component;
328
329 /* ignore duplication for now */
330 if (platform && (component == &platform->component))
331 continue;
332
333 if (!component->driver->compr_ops ||
334 !component->driver->compr_ops->free)
335 continue;
336
337 component->driver->compr_ops->free(cstream);
338 }
339
340 if (platform && platform->driver->compr_ops && platform->driver->compr_ops->free)
Namarta Kohli1245b702012-08-16 17:10:41 +0530341 platform->driver->compr_ops->free(cstream);
Namarta Kohli1245b702012-08-16 17:10:41 +0530342
Vinod Koul2e622ae2016-11-13 12:10:02 +0530343 if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
344 cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
345
Namarta Kohli1245b702012-08-16 17:10:41 +0530346 if (cstream->direction == SND_COMPRESS_PLAYBACK) {
Lars-Peter Clausen208a1582014-03-05 13:17:42 +0100347 if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
Namarta Kohli1245b702012-08-16 17:10:41 +0530348 snd_soc_dapm_stream_event(rtd,
349 SNDRV_PCM_STREAM_PLAYBACK,
350 SND_SOC_DAPM_STREAM_STOP);
Charles Keepax8c3d2aa2013-01-24 09:44:28 +0000351 } else {
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600352 rtd->pop_wait = 1;
Mark Brown3d24cfe2013-08-09 18:12:29 +0100353 queue_delayed_work(system_power_efficient_wq,
354 &rtd->delayed_work,
355 msecs_to_jiffies(rtd->pmdown_time));
Charles Keepax8c3d2aa2013-01-24 09:44:28 +0000356 }
Namarta Kohli1245b702012-08-16 17:10:41 +0530357 } else {
358 /* capture streams can be powered down now */
359 snd_soc_dapm_stream_event(rtd,
360 SNDRV_PCM_STREAM_CAPTURE,
361 SND_SOC_DAPM_STREAM_STOP);
362 }
363
Charles Keepax15e2e612013-01-24 09:44:29 +0000364 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530365 return 0;
366}
367
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000368static int soc_compr_free_fe(struct snd_compr_stream *cstream)
369{
370 struct snd_soc_pcm_runtime *fe = cstream->private_data;
371 struct snd_soc_platform *platform = fe->platform;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000372 struct snd_soc_component *component;
373 struct snd_soc_rtdcom_list *rtdcom;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530374 struct snd_soc_dai *cpu_dai = fe->cpu_dai;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000375 struct snd_soc_dpcm *dpcm;
376 int stream, ret;
377
378 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
379
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100380 if (cstream->direction == SND_COMPRESS_PLAYBACK)
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000381 stream = SNDRV_PCM_STREAM_PLAYBACK;
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100382 else
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000383 stream = SNDRV_PCM_STREAM_CAPTURE;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000384
Lars-Peter Clausen24894b72014-03-05 13:17:43 +0100385 snd_soc_runtime_deactivate(fe, stream);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000386
387 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
388
389 ret = dpcm_be_dai_hw_free(fe, stream);
390 if (ret < 0)
Charles Keepax141dfc92018-01-26 13:08:45 +0000391 dev_err(fe->dev, "Compressed ASoC: hw_free failed: %d\n", ret);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000392
393 ret = dpcm_be_dai_shutdown(fe, stream);
394
395 /* mark FE's links ready to prune */
396 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
397 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
398
Daniel Mack15f6b092014-10-19 09:07:35 +0200399 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000400
401 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
402 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
403
404 dpcm_be_disconnect(fe, stream);
405
406 fe->dpcm[stream].runtime = NULL;
407
408 if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
409 fe->dai_link->compr_ops->shutdown(cstream);
410
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000411 if (platform && platform->driver->compr_ops && platform->driver->compr_ops->free)
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000412 platform->driver->compr_ops->free(cstream);
413
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000414 for_each_rtdcom(fe, rtdcom) {
415 component = rtdcom->component;
416
417 /* ignore duplication for now */
418 if (platform && (component == &platform->component))
419 continue;
420
421 if (!component->driver->compr_ops ||
422 !component->driver->compr_ops->free)
423 continue;
424
425 component->driver->compr_ops->free(cstream);
426 }
427
Vinod Koul2e622ae2016-11-13 12:10:02 +0530428 if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
429 cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
430
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000431 mutex_unlock(&fe->card->mutex);
432 return 0;
433}
434
Namarta Kohli1245b702012-08-16 17:10:41 +0530435static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
436{
437
438 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
439 struct snd_soc_platform *platform = rtd->platform;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000440 struct snd_soc_component *component;
441 struct snd_soc_rtdcom_list *rtdcom;
Namarta Kohli1245b702012-08-16 17:10:41 +0530442 struct snd_soc_dai *codec_dai = rtd->codec_dai;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530443 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000444 int ret = 0, __ret;
Namarta Kohli1245b702012-08-16 17:10:41 +0530445
Charles Keepax15e2e612013-01-24 09:44:29 +0000446 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
447
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000448 if (platform && platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
Namarta Kohli1245b702012-08-16 17:10:41 +0530449 ret = platform->driver->compr_ops->trigger(cstream, cmd);
450 if (ret < 0)
Charles Keepax15e2e612013-01-24 09:44:29 +0000451 goto out;
Namarta Kohli1245b702012-08-16 17:10:41 +0530452 }
453
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000454 for_each_rtdcom(rtd, rtdcom) {
455 component = rtdcom->component;
456
457 /* ignore duplication for now */
458 if (platform && (component == &platform->component))
459 continue;
460
461 if (!component->driver->compr_ops ||
462 !component->driver->compr_ops->trigger)
463 continue;
464
465 __ret = component->driver->compr_ops->trigger(cstream, cmd);
466 if (__ret < 0)
467 ret = __ret;
468 }
469 if (ret < 0)
470 goto out;
471
Vinod Koul2e622ae2016-11-13 12:10:02 +0530472 if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger)
473 cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai);
474
Mark Brownda183962013-02-06 15:44:07 +0000475 switch (cmd) {
476 case SNDRV_PCM_TRIGGER_START:
477 snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction);
478 break;
479 case SNDRV_PCM_TRIGGER_STOP:
480 snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
481 break;
Mark Browne38b9b72013-02-06 13:52:42 +0000482 }
Namarta Kohli1245b702012-08-16 17:10:41 +0530483
Charles Keepax15e2e612013-01-24 09:44:29 +0000484out:
485 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530486 return ret;
487}
488
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000489static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
490{
491 struct snd_soc_pcm_runtime *fe = cstream->private_data;
492 struct snd_soc_platform *platform = fe->platform;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000493 struct snd_soc_component *component;
494 struct snd_soc_rtdcom_list *rtdcom;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530495 struct snd_soc_dai *cpu_dai = fe->cpu_dai;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000496 int ret = 0, __ret, stream;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000497
498 if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN ||
499 cmd == SND_COMPR_TRIGGER_DRAIN) {
500
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000501 if (platform &&
502 platform->driver->compr_ops &&
Dan Carpenter15b8e942014-05-14 17:23:08 +0300503 platform->driver->compr_ops->trigger)
504 return platform->driver->compr_ops->trigger(cstream,
505 cmd);
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000506
507 for_each_rtdcom(fe, rtdcom) {
508 component = rtdcom->component;
509
510 /* ignore duplication for now */
511 if (platform && (component == &platform->component))
512 continue;
513
514 if (!component->driver->compr_ops ||
515 !component->driver->compr_ops->trigger)
516 continue;
517
518 __ret = component->driver->compr_ops->trigger(cstream, cmd);
519 if (__ret < 0)
520 ret = __ret;
521 }
522 return ret;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000523 }
524
525 if (cstream->direction == SND_COMPRESS_PLAYBACK)
526 stream = SNDRV_PCM_STREAM_PLAYBACK;
527 else
528 stream = SNDRV_PCM_STREAM_CAPTURE;
529
530
531 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
532
Vinod Koul2e622ae2016-11-13 12:10:02 +0530533 if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) {
534 ret = cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai);
535 if (ret < 0)
536 goto out;
537 }
538
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000539 if (platform && platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000540 ret = platform->driver->compr_ops->trigger(cstream, cmd);
541 if (ret < 0)
542 goto out;
543 }
544
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000545 for_each_rtdcom(fe, rtdcom) {
546 component = rtdcom->component;
547
548 /* ignore duplication for now */
549 if (platform && (component == &platform->component))
550 continue;
551
552 if (!component->driver->compr_ops ||
553 !component->driver->compr_ops->trigger)
554 continue;
555
556 __ret = component->driver->compr_ops->trigger(cstream, cmd);
557 if (__ret < 0)
558 ret = __ret;
559 }
560 if (ret < 0)
561 goto out;
562
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000563 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
564
565 ret = dpcm_be_dai_trigger(fe, stream, cmd);
566
567 switch (cmd) {
568 case SNDRV_PCM_TRIGGER_START:
569 case SNDRV_PCM_TRIGGER_RESUME:
570 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
571 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
572 break;
573 case SNDRV_PCM_TRIGGER_STOP:
574 case SNDRV_PCM_TRIGGER_SUSPEND:
575 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
576 break;
577 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
578 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
579 break;
580 }
581
582out:
583 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
584 mutex_unlock(&fe->card->mutex);
585 return ret;
586}
587
Namarta Kohli1245b702012-08-16 17:10:41 +0530588static int soc_compr_set_params(struct snd_compr_stream *cstream,
589 struct snd_compr_params *params)
590{
591 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
592 struct snd_soc_platform *platform = rtd->platform;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000593 struct snd_soc_component *component;
594 struct snd_soc_rtdcom_list *rtdcom;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530595 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000596 int ret = 0, __ret;
Namarta Kohli1245b702012-08-16 17:10:41 +0530597
Charles Keepax15e2e612013-01-24 09:44:29 +0000598 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
599
Namarta Kohli1245b702012-08-16 17:10:41 +0530600 /* first we call set_params for the platform driver
601 * this should configure the soc side
602 * if the machine has compressed ops then we call that as well
603 * expectation is that platform and machine will configure everything
604 * for this compress path, like configuring pcm port for codec
605 */
Vinod Koul2e622ae2016-11-13 12:10:02 +0530606 if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) {
607 ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai);
608 if (ret < 0)
609 goto err;
610 }
611
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000612 if (platform && platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
Namarta Kohli1245b702012-08-16 17:10:41 +0530613 ret = platform->driver->compr_ops->set_params(cstream, params);
614 if (ret < 0)
Charles Keepaxfa40ef22013-03-27 16:39:01 +0000615 goto err;
Namarta Kohli1245b702012-08-16 17:10:41 +0530616 }
617
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000618 for_each_rtdcom(rtd, rtdcom) {
619 component = rtdcom->component;
620
621 /* ignore duplication for now */
622 if (platform && (component == &platform->component))
623 continue;
624
625 if (!component->driver->compr_ops ||
626 !component->driver->compr_ops->set_params)
627 continue;
628
629 __ret = component->driver->compr_ops->set_params(cstream, params);
630 if (__ret < 0)
631 ret = __ret;
632 }
633 if (ret < 0)
634 goto err;
635
Namarta Kohli1245b702012-08-16 17:10:41 +0530636 if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) {
637 ret = rtd->dai_link->compr_ops->set_params(cstream);
638 if (ret < 0)
Charles Keepaxfa40ef22013-03-27 16:39:01 +0000639 goto err;
Namarta Kohli1245b702012-08-16 17:10:41 +0530640 }
641
Charles Keepax2c071ed2013-05-20 08:33:54 +0100642 if (cstream->direction == SND_COMPRESS_PLAYBACK)
643 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
644 SND_SOC_DAPM_STREAM_START);
645 else
646 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
647 SND_SOC_DAPM_STREAM_START);
Namarta Kohli1245b702012-08-16 17:10:41 +0530648
Charles Keepaxfa40ef22013-03-27 16:39:01 +0000649 /* cancel any delayed stream shutdown that is pending */
650 rtd->pop_wait = 0;
651 mutex_unlock(&rtd->pcm_mutex);
652
653 cancel_delayed_work_sync(&rtd->delayed_work);
654
655 return ret;
656
657err:
Charles Keepax15e2e612013-01-24 09:44:29 +0000658 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530659 return ret;
660}
661
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000662static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
663 struct snd_compr_params *params)
664{
665 struct snd_soc_pcm_runtime *fe = cstream->private_data;
Satish Babu Patakokila01b8ced2017-06-16 17:33:40 -0700666 struct snd_pcm_substream *fe_substream =
667 fe->pcm->streams[cstream->direction].substream;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000668 struct snd_soc_platform *platform = fe->platform;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000669 struct snd_soc_component *component;
670 struct snd_soc_rtdcom_list *rtdcom;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530671 struct snd_soc_dai *cpu_dai = fe->cpu_dai;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000672 int ret = 0, __ret, stream;
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000673
674 if (cstream->direction == SND_COMPRESS_PLAYBACK)
675 stream = SNDRV_PCM_STREAM_PLAYBACK;
676 else
677 stream = SNDRV_PCM_STREAM_CAPTURE;
678
679 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
680
Vinod Koul2e622ae2016-11-13 12:10:02 +0530681 if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) {
682 ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai);
683 if (ret < 0)
684 goto out;
685 }
686
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000687 if (platform && platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000688 ret = platform->driver->compr_ops->set_params(cstream, params);
689 if (ret < 0)
690 goto out;
691 }
692
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000693 for_each_rtdcom(fe, rtdcom) {
694 component = rtdcom->component;
695
696 /* ignore duplication for now */
697 if (platform && (component == &platform->component))
698 continue;
699
700 if (!component->driver->compr_ops ||
701 !component->driver->compr_ops->set_params)
702 continue;
703
704 __ret = component->driver->compr_ops->set_params(cstream, params);
705 if (__ret < 0)
706 ret = __ret;
707 }
708 if (ret < 0)
709 goto out;
710
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000711 if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) {
712 ret = fe->dai_link->compr_ops->set_params(cstream);
713 if (ret < 0)
714 goto out;
715 }
716
717 /*
718 * Create an empty hw_params for the BE as the machine driver must
719 * fix this up to match DSP decoder and ASRC configuration.
720 * I.e. machine driver fixup for compressed BE is mandatory.
721 */
722 memset(&fe->dpcm[fe_substream->stream].hw_params, 0,
723 sizeof(struct snd_pcm_hw_params));
724
725 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
726
727 ret = dpcm_be_dai_hw_params(fe, stream);
728 if (ret < 0)
729 goto out;
730
731 ret = dpcm_be_dai_prepare(fe, stream);
732 if (ret < 0)
733 goto out;
734
Daniel Mack15f6b092014-10-19 09:07:35 +0200735 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
Liam Girdwood2a99ef02014-01-17 17:03:56 +0000736 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
737
738out:
739 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
740 mutex_unlock(&fe->card->mutex);
741 return ret;
742}
743
Namarta Kohli1245b702012-08-16 17:10:41 +0530744static int soc_compr_get_params(struct snd_compr_stream *cstream,
745 struct snd_codec *params)
746{
747 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
748 struct snd_soc_platform *platform = rtd->platform;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000749 struct snd_soc_component *component;
750 struct snd_soc_rtdcom_list *rtdcom;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530751 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000752 int ret = 0, __ret;
Namarta Kohli1245b702012-08-16 17:10:41 +0530753
Charles Keepax15e2e612013-01-24 09:44:29 +0000754 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
755
Vinod Koul2e622ae2016-11-13 12:10:02 +0530756 if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_params) {
757 ret = cpu_dai->driver->cops->get_params(cstream, params, cpu_dai);
758 if (ret < 0)
759 goto err;
760 }
761
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000762 if (platform && platform->driver->compr_ops && platform->driver->compr_ops->get_params) {
Namarta Kohli1245b702012-08-16 17:10:41 +0530763 ret = platform->driver->compr_ops->get_params(cstream, params);
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000764 if (ret < 0)
765 goto err;
766 }
767
768 for_each_rtdcom(rtd, rtdcom) {
769 component = rtdcom->component;
770
771 /* ignore duplication for now */
772 if (platform && (component == &platform->component))
773 continue;
774
775 if (!component->driver->compr_ops ||
776 !component->driver->compr_ops->get_params)
777 continue;
778
779 __ret = component->driver->compr_ops->get_params(cstream, params);
780 if (__ret < 0)
781 ret = __ret;
782 }
Namarta Kohli1245b702012-08-16 17:10:41 +0530783
Vinod Koul2e622ae2016-11-13 12:10:02 +0530784err:
Charles Keepax15e2e612013-01-24 09:44:29 +0000785 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530786 return ret;
787}
788
789static int soc_compr_get_caps(struct snd_compr_stream *cstream,
790 struct snd_compr_caps *caps)
791{
792 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
793 struct snd_soc_platform *platform = rtd->platform;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000794 struct snd_soc_component *component;
795 struct snd_soc_rtdcom_list *rtdcom;
796 int ret = 0, __ret;
Namarta Kohli1245b702012-08-16 17:10:41 +0530797
Charles Keepax15e2e612013-01-24 09:44:29 +0000798 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
799
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000800 if (platform && platform->driver->compr_ops && platform->driver->compr_ops->get_caps) {
Namarta Kohli1245b702012-08-16 17:10:41 +0530801 ret = platform->driver->compr_ops->get_caps(cstream, caps);
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000802 if (ret < 0)
803 goto err;
804 }
Namarta Kohli1245b702012-08-16 17:10:41 +0530805
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000806 for_each_rtdcom(rtd, rtdcom) {
807 component = rtdcom->component;
808
809 /* ignore duplication for now */
810 if (platform && (component == &platform->component))
811 continue;
812
813 if (!component->driver->compr_ops ||
814 !component->driver->compr_ops->get_caps)
815 continue;
816
817 __ret = component->driver->compr_ops->get_caps(cstream, caps);
818 if (__ret < 0)
819 ret = __ret;
820 }
821
822err:
Charles Keepax15e2e612013-01-24 09:44:29 +0000823 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530824 return ret;
825}
826
827static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream,
828 struct snd_compr_codec_caps *codec)
829{
830 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
831 struct snd_soc_platform *platform = rtd->platform;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000832 struct snd_soc_component *component;
833 struct snd_soc_rtdcom_list *rtdcom;
834 int ret = 0, __ret;
Namarta Kohli1245b702012-08-16 17:10:41 +0530835
Charles Keepax15e2e612013-01-24 09:44:29 +0000836 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
837
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000838 if (platform && platform->driver->compr_ops && platform->driver->compr_ops->get_codec_caps) {
Namarta Kohli1245b702012-08-16 17:10:41 +0530839 ret = platform->driver->compr_ops->get_codec_caps(cstream, codec);
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000840 if (ret < 0)
841 goto err;
842 }
Namarta Kohli1245b702012-08-16 17:10:41 +0530843
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000844 for_each_rtdcom(rtd, rtdcom) {
845 component = rtdcom->component;
846
847 /* ignore duplication for now */
848 if (platform && (component == &platform->component))
849 continue;
850
851 if (!component->driver->compr_ops ||
852 !component->driver->compr_ops->get_codec_caps)
853 continue;
854
855 __ret = component->driver->compr_ops->get_codec_caps(cstream, codec);
856 if (__ret < 0)
857 ret = __ret;
858 }
859
860err:
Charles Keepax15e2e612013-01-24 09:44:29 +0000861 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530862 return ret;
863}
864
865static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
866{
867 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
868 struct snd_soc_platform *platform = rtd->platform;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000869 struct snd_soc_component *component;
870 struct snd_soc_rtdcom_list *rtdcom;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530871 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000872 int ret = 0, __ret;
Namarta Kohli1245b702012-08-16 17:10:41 +0530873
Charles Keepax15e2e612013-01-24 09:44:29 +0000874 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
875
Vinod Koul2e622ae2016-11-13 12:10:02 +0530876 if (cpu_dai->driver->cops && cpu_dai->driver->cops->ack) {
877 ret = cpu_dai->driver->cops->ack(cstream, bytes, cpu_dai);
878 if (ret < 0)
879 goto err;
880 }
881
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000882 if (platform && platform->driver->compr_ops && platform->driver->compr_ops->ack) {
Namarta Kohli1245b702012-08-16 17:10:41 +0530883 ret = platform->driver->compr_ops->ack(cstream, bytes);
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000884 if (ret < 0)
885 goto err;
886 }
887
888 for_each_rtdcom(rtd, rtdcom) {
889 component = rtdcom->component;
890
891 /* ignore duplication for now */
892 if (platform && (component == &platform->component))
893 continue;
894
895 if (!component->driver->compr_ops ||
896 !component->driver->compr_ops->ack)
897 continue;
898
899 __ret = component->driver->compr_ops->ack(cstream, bytes);
900 if (__ret < 0)
901 ret = __ret;
902 }
Namarta Kohli1245b702012-08-16 17:10:41 +0530903
Vinod Koul2e622ae2016-11-13 12:10:02 +0530904err:
Charles Keepax15e2e612013-01-24 09:44:29 +0000905 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530906 return ret;
907}
908
909static int soc_compr_pointer(struct snd_compr_stream *cstream,
910 struct snd_compr_tstamp *tstamp)
911{
912 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
913 struct snd_soc_platform *platform = rtd->platform;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000914 struct snd_soc_component *component;
915 struct snd_soc_rtdcom_list *rtdcom;
916 int ret = 0, __ret;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530917 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Namarta Kohli1245b702012-08-16 17:10:41 +0530918
Charles Keepax15e2e612013-01-24 09:44:29 +0000919 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
920
Vinod Koul2e622ae2016-11-13 12:10:02 +0530921 if (cpu_dai->driver->cops && cpu_dai->driver->cops->pointer)
922 cpu_dai->driver->cops->pointer(cstream, tstamp, cpu_dai);
923
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000924 if (platform && platform->driver->compr_ops && platform->driver->compr_ops->pointer) {
Charles Keepax7c9190f2016-06-20 09:51:32 +0100925 ret = platform->driver->compr_ops->pointer(cstream, tstamp);
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000926 if (ret < 0)
927 goto err;
928 }
Namarta Kohli1245b702012-08-16 17:10:41 +0530929
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000930 for_each_rtdcom(rtd, rtdcom) {
931 component = rtdcom->component;
932
933 /* ignore duplication for now */
934 if (platform && (component == &platform->component))
935 continue;
936
937 if (!component->driver->compr_ops ||
938 !component->driver->compr_ops->pointer)
939 continue;
940
941 __ret = component->driver->compr_ops->pointer(cstream, tstamp);
942 if (__ret < 0)
943 ret = __ret;
944 }
945
946err:
Charles Keepax15e2e612013-01-24 09:44:29 +0000947 mutex_unlock(&rtd->pcm_mutex);
Charles Keepax7c9190f2016-06-20 09:51:32 +0100948 return ret;
Namarta Kohli1245b702012-08-16 17:10:41 +0530949}
950
Charles Keepax1f88eb02013-02-05 10:41:47 +0000951static int soc_compr_copy(struct snd_compr_stream *cstream,
Charles Keepax4daf8912013-04-18 11:01:38 +0100952 char __user *buf, size_t count)
Charles Keepax1f88eb02013-02-05 10:41:47 +0000953{
954 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
955 struct snd_soc_platform *platform = rtd->platform;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000956 struct snd_soc_component *component;
957 struct snd_soc_rtdcom_list *rtdcom;
Charles Keepax290df4d32018-01-26 13:08:43 +0000958 int ret = 0;
Charles Keepax1f88eb02013-02-05 10:41:47 +0000959
960 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
961
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000962 if (platform && platform->driver->compr_ops && platform->driver->compr_ops->copy) {
Charles Keepax1f88eb02013-02-05 10:41:47 +0000963 ret = platform->driver->compr_ops->copy(cstream, buf, count);
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000964 if (ret < 0)
965 goto err;
966 }
Charles Keepax1f88eb02013-02-05 10:41:47 +0000967
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000968 for_each_rtdcom(rtd, rtdcom) {
969 component = rtdcom->component;
970
971 /* ignore duplication for now */
972 if (platform && (component == &platform->component))
973 continue;
974
975 if (!component->driver->compr_ops ||
976 !component->driver->compr_ops->copy)
977 continue;
978
Charles Keepax290df4d32018-01-26 13:08:43 +0000979 ret = component->driver->compr_ops->copy(cstream, buf, count);
980 break;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000981 }
Charles Keepax290df4d32018-01-26 13:08:43 +0000982
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000983err:
Charles Keepax1f88eb02013-02-05 10:41:47 +0000984 mutex_unlock(&rtd->pcm_mutex);
985 return ret;
986}
987
Vinod Koul02bd90e2013-07-28 20:06:15 +0530988static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
Jeeja KP36953d92013-03-26 21:22:28 +0530989 struct snd_compr_metadata *metadata)
990{
991 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
992 struct snd_soc_platform *platform = rtd->platform;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000993 struct snd_soc_component *component;
994 struct snd_soc_rtdcom_list *rtdcom;
Vinod Koul2e622ae2016-11-13 12:10:02 +0530995 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +0000996 int ret = 0, __ret;
Jeeja KP36953d92013-03-26 21:22:28 +0530997
Vinod Koul2e622ae2016-11-13 12:10:02 +0530998 if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_metadata) {
999 ret = cpu_dai->driver->cops->set_metadata(cstream, metadata, cpu_dai);
1000 if (ret < 0)
1001 return ret;
1002 }
1003
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +00001004 if (platform && platform->driver->compr_ops && platform->driver->compr_ops->set_metadata) {
Jeeja KP36953d92013-03-26 21:22:28 +05301005 ret = platform->driver->compr_ops->set_metadata(cstream, metadata);
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +00001006 if (ret < 0)
1007 return ret;
1008 }
1009
1010 for_each_rtdcom(rtd, rtdcom) {
1011 component = rtdcom->component;
1012
1013 /* ignore duplication for now */
1014 if (platform && (component == &platform->component))
1015 continue;
1016
1017 if (!component->driver->compr_ops ||
1018 !component->driver->compr_ops->set_metadata)
1019 continue;
1020
1021 __ret = component->driver->compr_ops->set_metadata(cstream, metadata);
1022 if (__ret < 0)
1023 ret = __ret;
1024 }
Jeeja KP36953d92013-03-26 21:22:28 +05301025
1026 return ret;
1027}
1028
Vinod Koul02bd90e2013-07-28 20:06:15 +05301029static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
Jeeja KP36953d92013-03-26 21:22:28 +05301030 struct snd_compr_metadata *metadata)
1031{
1032 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
1033 struct snd_soc_platform *platform = rtd->platform;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +00001034 struct snd_soc_component *component;
1035 struct snd_soc_rtdcom_list *rtdcom;
Vinod Koul2e622ae2016-11-13 12:10:02 +05301036 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +00001037 int ret = 0, __ret;
Jeeja KP36953d92013-03-26 21:22:28 +05301038
Vinod Koul2e622ae2016-11-13 12:10:02 +05301039 if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_metadata) {
1040 ret = cpu_dai->driver->cops->get_metadata(cstream, metadata, cpu_dai);
1041 if (ret < 0)
1042 return ret;
1043 }
1044
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +00001045 if (platform && platform->driver->compr_ops && platform->driver->compr_ops->get_metadata) {
Jeeja KP36953d92013-03-26 21:22:28 +05301046 ret = platform->driver->compr_ops->get_metadata(cstream, metadata);
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +00001047 if (ret < 0)
1048 return ret;
1049 }
1050
1051 for_each_rtdcom(rtd, rtdcom) {
1052 component = rtdcom->component;
1053
1054 /* ignore duplication for now */
1055 if (platform && (component == &platform->component))
1056 continue;
1057
1058 if (!component->driver->compr_ops ||
1059 !component->driver->compr_ops->get_metadata)
1060 continue;
1061
1062 __ret = component->driver->compr_ops->get_metadata(cstream, metadata);
1063 if (__ret < 0)
1064 ret = __ret;
1065 }
Jeeja KP36953d92013-03-26 21:22:28 +05301066
1067 return ret;
1068}
Liam Girdwood2a99ef02014-01-17 17:03:56 +00001069
Namarta Kohli1245b702012-08-16 17:10:41 +05301070/* ASoC Compress operations */
1071static struct snd_compr_ops soc_compr_ops = {
1072 .open = soc_compr_open,
1073 .free = soc_compr_free,
1074 .set_params = soc_compr_set_params,
Vinod Koul02bd90e2013-07-28 20:06:15 +05301075 .set_metadata = soc_compr_set_metadata,
1076 .get_metadata = soc_compr_get_metadata,
Namarta Kohli1245b702012-08-16 17:10:41 +05301077 .get_params = soc_compr_get_params,
1078 .trigger = soc_compr_trigger,
1079 .pointer = soc_compr_pointer,
1080 .ack = soc_compr_ack,
1081 .get_caps = soc_compr_get_caps,
1082 .get_codec_caps = soc_compr_get_codec_caps
1083};
1084
Liam Girdwood2a99ef02014-01-17 17:03:56 +00001085/* ASoC Dynamic Compress operations */
1086static struct snd_compr_ops soc_compr_dyn_ops = {
1087 .open = soc_compr_open_fe,
1088 .free = soc_compr_free_fe,
1089 .set_params = soc_compr_set_params_fe,
1090 .get_params = soc_compr_get_params,
1091 .set_metadata = soc_compr_set_metadata,
1092 .get_metadata = soc_compr_get_metadata,
1093 .trigger = soc_compr_trigger_fe,
1094 .pointer = soc_compr_pointer,
1095 .ack = soc_compr_ack,
1096 .get_caps = soc_compr_get_caps,
1097 .get_codec_caps = soc_compr_get_codec_caps
1098};
1099
Jie Yang6f0c4222015-10-13 23:41:00 +08001100/**
1101 * snd_soc_new_compress - create a new compress.
1102 *
1103 * @rtd: The runtime for which we will create compress
1104 * @num: the device index number (zero based - shared with normal PCMs)
1105 *
1106 * Return: 0 for success, else error.
1107 */
1108int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
Namarta Kohli1245b702012-08-16 17:10:41 +05301109{
Charles Keepax1f88eb02013-02-05 10:41:47 +00001110 struct snd_soc_platform *platform = rtd->platform;
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +00001111 struct snd_soc_component *component;
1112 struct snd_soc_rtdcom_list *rtdcom;
Namarta Kohli1245b702012-08-16 17:10:41 +05301113 struct snd_soc_dai *codec_dai = rtd->codec_dai;
1114 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
1115 struct snd_compr *compr;
Liam Girdwood2a99ef02014-01-17 17:03:56 +00001116 struct snd_pcm *be_pcm;
Namarta Kohli1245b702012-08-16 17:10:41 +05301117 char new_name[64];
1118 int ret = 0, direction = 0;
Vinod Koula1068042016-01-07 21:48:14 +05301119 int playback = 0, capture = 0;
Namarta Kohli1245b702012-08-16 17:10:41 +05301120
Benoit Cousson8151d5e2014-07-08 23:19:37 +02001121 if (rtd->num_codecs > 1) {
Charles Keepax141dfc92018-01-26 13:08:45 +00001122 dev_err(rtd->card->dev,
1123 "Compress ASoC: Multicodec not supported\n");
Benoit Cousson8151d5e2014-07-08 23:19:37 +02001124 return -EINVAL;
1125 }
1126
Namarta Kohli1245b702012-08-16 17:10:41 +05301127 /* check client and interface hw capabilities */
Charles Keepaxdaa2db52013-04-18 11:02:38 +01001128 if (codec_dai->driver->playback.channels_min)
Vinod Koula1068042016-01-07 21:48:14 +05301129 playback = 1;
1130 if (codec_dai->driver->capture.channels_min)
1131 capture = 1;
1132
1133 capture = capture && cpu_dai->driver->capture.channels_min;
1134 playback = playback && cpu_dai->driver->playback.channels_min;
1135
1136 /*
1137 * Compress devices are unidirectional so only one of the directions
1138 * should be set, check for that (xor)
1139 */
1140 if (playback + capture != 1) {
Charles Keepax141dfc92018-01-26 13:08:45 +00001141 dev_err(rtd->card->dev,
1142 "Compress ASoC: Invalid direction for P %d, C %d\n",
1143 playback, capture);
Charles Keepaxdaa2db52013-04-18 11:02:38 +01001144 return -EINVAL;
Vinod Koula1068042016-01-07 21:48:14 +05301145 }
1146
Peng Donglinaeb6fa02017-08-16 22:47:53 +08001147 if (playback)
Vinod Koula1068042016-01-07 21:48:14 +05301148 direction = SND_COMPRESS_PLAYBACK;
1149 else
1150 direction = SND_COMPRESS_CAPTURE;
Charles Keepaxdaa2db52013-04-18 11:02:38 +01001151
Namarta Kohli1245b702012-08-16 17:10:41 +05301152 compr = kzalloc(sizeof(*compr), GFP_KERNEL);
Markus Elfring7a0cf422017-08-10 16:21:34 +02001153 if (!compr)
Namarta Kohli1245b702012-08-16 17:10:41 +05301154 return -ENOMEM;
Namarta Kohli1245b702012-08-16 17:10:41 +05301155
Charles Keepax1f88eb02013-02-05 10:41:47 +00001156 compr->ops = devm_kzalloc(rtd->card->dev, sizeof(soc_compr_ops),
1157 GFP_KERNEL);
Markus Elfring7a0cf422017-08-10 16:21:34 +02001158 if (!compr->ops) {
Charles Keepax1f88eb02013-02-05 10:41:47 +00001159 ret = -ENOMEM;
1160 goto compr_err;
1161 }
Liam Girdwood2a99ef02014-01-17 17:03:56 +00001162
1163 if (rtd->dai_link->dynamic) {
1164 snprintf(new_name, sizeof(new_name), "(%s)",
1165 rtd->dai_link->stream_name);
1166
1167 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
Qais Yousefd3268a42015-01-14 08:47:29 +00001168 rtd->dai_link->dpcm_playback,
1169 rtd->dai_link->dpcm_capture, &be_pcm);
Liam Girdwood2a99ef02014-01-17 17:03:56 +00001170 if (ret < 0) {
Charles Keepax141dfc92018-01-26 13:08:45 +00001171 dev_err(rtd->card->dev,
1172 "Compress ASoC: can't create compressed for %s: %d\n",
1173 rtd->dai_link->name, ret);
Liam Girdwood2a99ef02014-01-17 17:03:56 +00001174 goto compr_err;
1175 }
1176
1177 rtd->pcm = be_pcm;
1178 rtd->fe_compr = 1;
Qais Yousefd3268a42015-01-14 08:47:29 +00001179 if (rtd->dai_link->dpcm_playback)
1180 be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
1181 else if (rtd->dai_link->dpcm_capture)
1182 be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
Liam Girdwood2a99ef02014-01-17 17:03:56 +00001183 memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops));
Peng Donglinaeb6fa02017-08-16 22:47:53 +08001184 } else {
1185 snprintf(new_name, sizeof(new_name), "%s %s-%d",
1186 rtd->dai_link->stream_name, codec_dai->name, num);
1187
Liam Girdwood2a99ef02014-01-17 17:03:56 +00001188 memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));
Peng Donglinaeb6fa02017-08-16 22:47:53 +08001189 }
Charles Keepax1f88eb02013-02-05 10:41:47 +00001190
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +00001191
Charles Keepax1f88eb02013-02-05 10:41:47 +00001192 /* Add copy callback for not memory mapped DSPs */
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +00001193 if (platform && platform->driver->compr_ops && platform->driver->compr_ops->copy)
Charles Keepax1f88eb02013-02-05 10:41:47 +00001194 compr->ops->copy = soc_compr_copy;
1195
Kuninori Morimoto9e7e3732017-10-11 01:37:45 +00001196 for_each_rtdcom(rtd, rtdcom) {
1197 component = rtdcom->component;
1198
1199 /* ignore duplication for now */
1200 if (platform && (component == &platform->component))
1201 continue;
1202
1203 if (!component->driver->compr_ops ||
1204 !component->driver->compr_ops->copy)
1205 continue;
1206
1207 compr->ops->copy = soc_compr_copy;
1208 }
1209
1210
Namarta Kohli1245b702012-08-16 17:10:41 +05301211 mutex_init(&compr->lock);
Richard Fitzgeralde5241a82015-11-25 13:00:24 +00001212 ret = snd_compress_new(rtd->card->snd_card, num, direction,
1213 new_name, compr);
Namarta Kohli1245b702012-08-16 17:10:41 +05301214 if (ret < 0) {
Kuninori Morimotoe5acfc72017-12-05 04:23:05 +00001215 component = rtd->codec_dai->component;
Charles Keepax141dfc92018-01-26 13:08:45 +00001216 dev_err(component->dev,
1217 "Compress ASoC: can't create compress for codec %s: %d\n",
1218 component->name, ret);
Charles Keepax1f88eb02013-02-05 10:41:47 +00001219 goto compr_err;
Namarta Kohli1245b702012-08-16 17:10:41 +05301220 }
1221
Charles Keepax202c8f72013-01-24 09:44:30 +00001222 /* DAPM dai link stream work */
1223 INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
1224
Namarta Kohli1245b702012-08-16 17:10:41 +05301225 rtd->compr = compr;
1226 compr->private_data = rtd;
1227
Charles Keepax141dfc92018-01-26 13:08:45 +00001228 dev_info(rtd->card->dev, "Compress ASoC: %s <-> %s mapping ok\n",
1229 codec_dai->name, cpu_dai->name);
Namarta Kohli1245b702012-08-16 17:10:41 +05301230 return ret;
Charles Keepax1f88eb02013-02-05 10:41:47 +00001231
1232compr_err:
1233 kfree(compr);
1234 return ret;
Namarta Kohli1245b702012-08-16 17:10:41 +05301235}
Jie Yang6f0c4222015-10-13 23:41:00 +08001236EXPORT_SYMBOL_GPL(snd_soc_new_compress);