blob: 3d8033bddbddad9ce17a762a262247e03ba1797c [file] [log] [blame]
Namarta Kohli9f052a72012-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 Girdwood660db5a2013-05-21 10:25:51 +010027#include <sound/soc-dpcm.h>
Namarta Kohli9f052a72012-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;
33 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
34 struct snd_soc_dai *codec_dai = rtd->codec_dai;
35 int ret = 0;
36
Charles Keepaxed87d162013-01-24 09:44:29 +000037 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
38
Namarta Kohli9f052a72012-08-16 17:10:41 +053039 if (platform->driver->compr_ops && platform->driver->compr_ops->open) {
40 ret = platform->driver->compr_ops->open(cstream);
41 if (ret < 0) {
42 pr_err("compress asoc: can't open platform %s\n", platform->name);
43 goto out;
44 }
45 }
46
47 if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->startup) {
48 ret = rtd->dai_link->compr_ops->startup(cstream);
49 if (ret < 0) {
50 pr_err("compress asoc: %s startup failed\n", rtd->dai_link->name);
51 goto machine_err;
52 }
53 }
54
55 if (cstream->direction == SND_COMPRESS_PLAYBACK) {
56 cpu_dai->playback_active++;
57 codec_dai->playback_active++;
58 } else {
59 cpu_dai->capture_active++;
60 codec_dai->capture_active++;
61 }
62
63 cpu_dai->active++;
64 codec_dai->active++;
65 rtd->codec->active++;
66
Charles Keepaxed87d162013-01-24 09:44:29 +000067 mutex_unlock(&rtd->pcm_mutex);
68
Namarta Kohli9f052a72012-08-16 17:10:41 +053069 return 0;
70
71machine_err:
72 if (platform->driver->compr_ops && platform->driver->compr_ops->free)
73 platform->driver->compr_ops->free(cstream);
74out:
Charles Keepaxed87d162013-01-24 09:44:29 +000075 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli9f052a72012-08-16 17:10:41 +053076 return ret;
77}
78
Liam Girdwood660db5a2013-05-21 10:25:51 +010079static int soc_compr_open_fe(struct snd_compr_stream *cstream)
80{
81 struct snd_soc_pcm_runtime *fe = cstream->private_data;
82 struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;
83 struct snd_soc_platform *platform = fe->platform;
84 struct snd_soc_dpcm_params *dpcm;
85 struct snd_soc_dapm_widget_list *list;
86 int stream;
87 int ret = 0;
88
89 if (cstream->direction == SND_COMPRESS_PLAYBACK)
90 stream = SNDRV_PCM_STREAM_PLAYBACK;
91 else
92 stream = SNDRV_PCM_STREAM_CAPTURE;
93
94 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
95
96 if (platform->driver->compr_ops && platform->driver->compr_ops->open) {
97 ret = platform->driver->compr_ops->open(cstream);
98 if (ret < 0) {
99 pr_err("compress asoc: can't open platform %s\n", platform->name);
100 goto out;
101 }
102 }
103
104 if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->startup) {
105 ret = fe->dai_link->compr_ops->startup(cstream);
106 if (ret < 0) {
107 pr_err("compress asoc: %s startup failed\n", fe->dai_link->name);
108 goto machine_err;
109 }
110 }
111
112 fe->dpcm[stream].runtime = fe_substream->runtime;
113
114 if (dpcm_path_get(fe, stream, &list) <= 0) {
115 dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
116 fe->dai_link->name, stream ? "capture" : "playback");
117 }
118
119 /* calculate valid and active FE <-> BE dpcms */
120 dpcm_process_paths(fe, stream, &list, 1);
121
Eric Laurentdb88f282013-07-15 10:00:45 -0700122 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
123
Liam Girdwood660db5a2013-05-21 10:25:51 +0100124 ret = dpcm_be_dai_startup(fe, stream);
125 if (ret < 0) {
126 /* clean up all links */
127 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
128 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
129
130 dpcm_be_disconnect(fe, stream);
131 fe->dpcm[stream].runtime = NULL;
132 goto fe_err;
133 }
134
135 dpcm_clear_pending_state(fe, stream);
136 dpcm_path_put(&list);
137
Eric Laurentdb88f282013-07-15 10:00:45 -0700138 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
139 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
Liam Girdwood660db5a2013-05-21 10:25:51 +0100140 mutex_unlock(&fe->card->mutex);
141
142 return 0;
143
144fe_err:
145 if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
146 fe->dai_link->compr_ops->shutdown(cstream);
147machine_err:
148 if (platform->driver->compr_ops && platform->driver->compr_ops->free)
149 platform->driver->compr_ops->free(cstream);
150out:
Eric Laurentdb88f282013-07-15 10:00:45 -0700151 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
Liam Girdwood660db5a2013-05-21 10:25:51 +0100152 mutex_unlock(&fe->card->mutex);
153 return ret;
154}
155
Charles Keepax57f8e792013-01-24 09:44:30 +0000156/*
157 * Power down the audio subsystem pmdown_time msecs after close is called.
158 * This is to ensure there are no pops or clicks in between any music tracks
159 * due to DAPM power cycling.
160 */
161static void close_delayed_work(struct work_struct *work)
162{
163 struct snd_soc_pcm_runtime *rtd =
164 container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
165 struct snd_soc_dai *codec_dai = rtd->codec_dai;
166
167 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
168
169 dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n",
170 codec_dai->driver->playback.stream_name,
171 codec_dai->playback_active ? "active" : "inactive",
Eric Laurent3359ca32013-04-08 16:07:19 -0700172 codec_dai->pop_wait ? "yes" : "no");
Charles Keepax57f8e792013-01-24 09:44:30 +0000173
174 /* are we waiting on this codec DAI stream */
Eric Laurent3359ca32013-04-08 16:07:19 -0700175 if (codec_dai->pop_wait == 1) {
176 codec_dai->pop_wait = 0;
Charles Keepax57f8e792013-01-24 09:44:30 +0000177 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
178 SND_SOC_DAPM_STREAM_STOP);
179 }
180
181 mutex_unlock(&rtd->pcm_mutex);
182}
183
Namarta Kohli9f052a72012-08-16 17:10:41 +0530184static int soc_compr_free(struct snd_compr_stream *cstream)
185{
186 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
187 struct snd_soc_platform *platform = rtd->platform;
188 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
189 struct snd_soc_dai *codec_dai = rtd->codec_dai;
190 struct snd_soc_codec *codec = rtd->codec;
191
Charles Keepaxed87d162013-01-24 09:44:29 +0000192 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
193
Namarta Kohli9f052a72012-08-16 17:10:41 +0530194 if (cstream->direction == SND_COMPRESS_PLAYBACK) {
195 cpu_dai->playback_active--;
196 codec_dai->playback_active--;
Mark Brown12a6e632013-02-06 13:52:42 +0000197 snd_soc_dai_digital_mute(codec_dai, 1);
Namarta Kohli9f052a72012-08-16 17:10:41 +0530198 } else {
199 cpu_dai->capture_active--;
200 codec_dai->capture_active--;
201 }
202
Namarta Kohli9f052a72012-08-16 17:10:41 +0530203 cpu_dai->active--;
204 codec_dai->active--;
205 codec->active--;
206
207 if (!cpu_dai->active)
208 cpu_dai->rate = 0;
209
210 if (!codec_dai->active)
211 codec_dai->rate = 0;
212
213
214 if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown)
215 rtd->dai_link->compr_ops->shutdown(cstream);
216
217 if (platform->driver->compr_ops && platform->driver->compr_ops->free)
218 platform->driver->compr_ops->free(cstream);
Vinod Koule3ee8fa2012-08-21 12:15:02 +0530219 cpu_dai->runtime = NULL;
Namarta Kohli9f052a72012-08-16 17:10:41 +0530220
221 if (cstream->direction == SND_COMPRESS_PLAYBACK) {
222 if (!rtd->pmdown_time || codec->ignore_pmdown_time ||
223 rtd->dai_link->ignore_pmdown_time) {
224 snd_soc_dapm_stream_event(rtd,
Eric Laurentf2615f72013-04-08 15:52:05 -0700225 codec_dai->driver->playback.stream_name,
Namarta Kohli9f052a72012-08-16 17:10:41 +0530226 SND_SOC_DAPM_STREAM_STOP);
Charles Keepax808dc722013-01-24 09:44:28 +0000227 } else {
Namarta Kohli9f052a72012-08-16 17:10:41 +0530228 codec_dai->pop_wait = 1;
229 schedule_delayed_work(&rtd->delayed_work,
230 msecs_to_jiffies(rtd->pmdown_time));
Charles Keepax808dc722013-01-24 09:44:28 +0000231 }
Namarta Kohli9f052a72012-08-16 17:10:41 +0530232 } else {
233 /* capture streams can be powered down now */
234 snd_soc_dapm_stream_event(rtd,
Eric Laurentf2615f72013-04-08 15:52:05 -0700235 codec_dai->driver->capture.stream_name,
Namarta Kohli9f052a72012-08-16 17:10:41 +0530236 SND_SOC_DAPM_STREAM_STOP);
237 }
238
Charles Keepaxed87d162013-01-24 09:44:29 +0000239 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli9f052a72012-08-16 17:10:41 +0530240 return 0;
241}
242
Liam Girdwood660db5a2013-05-21 10:25:51 +0100243static int soc_compr_free_fe(struct snd_compr_stream *cstream)
244{
245 struct snd_soc_pcm_runtime *fe = cstream->private_data;
246 struct snd_soc_platform *platform = fe->platform;
247 struct snd_soc_dpcm_params *dpcm;
248 int stream, ret;
249
250 if (cstream->direction == SND_COMPRESS_PLAYBACK)
251 stream = SNDRV_PCM_STREAM_PLAYBACK;
252 else
253 stream = SNDRV_PCM_STREAM_CAPTURE;
254
255 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
256
Eric Laurentdb88f282013-07-15 10:00:45 -0700257 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
258
Liam Girdwood660db5a2013-05-21 10:25:51 +0100259 ret = dpcm_be_dai_hw_free(fe, stream);
260 if (ret < 0)
261 dev_err(fe->dev, "compressed hw_free failed %d\n", ret);
262
263 ret = dpcm_be_dai_shutdown(fe, stream);
264
265 /* mark FE's links ready to prune */
266 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
267 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
268
Eric Laurentdb88f282013-07-15 10:00:45 -0700269 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
270 dpcm_dapm_stream_event(fe, stream,
271 fe->cpu_dai->driver->playback.stream_name,
272 SND_SOC_DAPM_STREAM_STOP);
273 else
274 dpcm_dapm_stream_event(fe, stream,
275 fe->cpu_dai->driver->capture.stream_name,
276 SND_SOC_DAPM_STREAM_STOP);
277
278 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
279 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
280
Liam Girdwood660db5a2013-05-21 10:25:51 +0100281 dpcm_be_disconnect(fe, stream);
282
283 fe->dpcm[stream].runtime = NULL;
284
285 if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
286 fe->dai_link->compr_ops->shutdown(cstream);
287
288 if (platform->driver->compr_ops && platform->driver->compr_ops->free)
289 platform->driver->compr_ops->free(cstream);
290 //cpu_dai->runtime = NULL;
291
292 mutex_unlock(&fe->card->mutex);
293 return 0;
294}
295
Namarta Kohli9f052a72012-08-16 17:10:41 +0530296static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
297{
298
299 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
300 struct snd_soc_platform *platform = rtd->platform;
301 struct snd_soc_dai *codec_dai = rtd->codec_dai;
302 int ret = 0;
303
Eric Laurentc0c29a02013-08-28 14:53:09 -0700304 /* for partial drain and drain cmd, don't acquire lock while invoking DSP.
305 * These calls will be blocked till these operation can complete which
306 * will be a while. And during that time, app can invoke STOP, PAUSE etc
307 */
308 if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN ||
309 cmd == SND_COMPR_TRIGGER_DRAIN) {
310 if (platform->driver->compr_ops &&
311 platform->driver->compr_ops->trigger)
312 return platform->driver->compr_ops->trigger(cstream, cmd);
313 }
314
Charles Keepaxed87d162013-01-24 09:44:29 +0000315 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
316
Namarta Kohli9f052a72012-08-16 17:10:41 +0530317 if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
318 ret = platform->driver->compr_ops->trigger(cstream, cmd);
319 if (ret < 0)
Charles Keepaxed87d162013-01-24 09:44:29 +0000320 goto out;
Namarta Kohli9f052a72012-08-16 17:10:41 +0530321 }
322
Mark Brown12a6e632013-02-06 13:52:42 +0000323 if (cstream->direction == SND_COMPRESS_PLAYBACK) {
324 switch (cmd) {
325 case SNDRV_PCM_TRIGGER_START:
326 snd_soc_dai_digital_mute(codec_dai, 0);
327 break;
328 case SNDRV_PCM_TRIGGER_STOP:
329 snd_soc_dai_digital_mute(codec_dai, 1);
330 break;
331 }
332 }
Namarta Kohli9f052a72012-08-16 17:10:41 +0530333
Charles Keepaxed87d162013-01-24 09:44:29 +0000334out:
335 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli9f052a72012-08-16 17:10:41 +0530336 return ret;
337}
338
Liam Girdwood660db5a2013-05-21 10:25:51 +0100339static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
340{
341 struct snd_soc_pcm_runtime *fe = cstream->private_data;
342 struct snd_soc_platform *platform = fe->platform;
343 int ret = 0, stream;
344
Eric Laurentc0c29a02013-08-28 14:53:09 -0700345 /* for partial drain and drain cmd, don't acquire lock while invoking DSP.
346 * These calls will be blocked till these operation can complete which
347 * will be a while. And during that time, app can invoke STOP, PAUSE etc
348 */
349 if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN ||
350 cmd == SND_COMPR_TRIGGER_DRAIN) {
351 if (platform->driver->compr_ops &&
352 platform->driver->compr_ops->trigger)
353 return platform->driver->compr_ops->trigger(cstream, cmd);
354 }
355
Liam Girdwood660db5a2013-05-21 10:25:51 +0100356 if (cstream->direction == SND_COMPRESS_PLAYBACK)
357 stream = SNDRV_PCM_STREAM_PLAYBACK;
358 else
359 stream = SNDRV_PCM_STREAM_CAPTURE;
360
361
362 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
363
364 if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
365 ret = platform->driver->compr_ops->trigger(cstream, cmd);
366 if (ret < 0)
367 goto out;
368 }
369
Eric Laurentdb88f282013-07-15 10:00:45 -0700370 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
371
Liam Girdwood660db5a2013-05-21 10:25:51 +0100372 ret = dpcm_be_dai_trigger(fe, stream, cmd);
373
Eric Laurentdb88f282013-07-15 10:00:45 -0700374 switch (cmd) {
375 case SNDRV_PCM_TRIGGER_START:
376 case SNDRV_PCM_TRIGGER_RESUME:
377 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
378 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
379 break;
380 case SNDRV_PCM_TRIGGER_STOP:
381 case SNDRV_PCM_TRIGGER_SUSPEND:
382 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
383 break;
384 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
385 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
386 break;
387 }
388
Liam Girdwood660db5a2013-05-21 10:25:51 +0100389out:
Eric Laurentdb88f282013-07-15 10:00:45 -0700390 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
Liam Girdwood660db5a2013-05-21 10:25:51 +0100391 mutex_unlock(&fe->card->mutex);
392 return ret;
393}
394
Namarta Kohli9f052a72012-08-16 17:10:41 +0530395static int soc_compr_set_params(struct snd_compr_stream *cstream,
396 struct snd_compr_params *params)
397{
398 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
399 struct snd_soc_platform *platform = rtd->platform;
400 struct snd_soc_dai *codec_dai = rtd->codec_dai;
401 int ret = 0;
402
Charles Keepaxed87d162013-01-24 09:44:29 +0000403 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
404
Namarta Kohli9f052a72012-08-16 17:10:41 +0530405 /* first we call set_params for the platform driver
406 * this should configure the soc side
407 * if the machine has compressed ops then we call that as well
408 * expectation is that platform and machine will configure everything
409 * for this compress path, like configuring pcm port for codec
410 */
411 if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
412 ret = platform->driver->compr_ops->set_params(cstream, params);
413 if (ret < 0)
Charles Keepax32cfb4f2013-03-27 16:39:01 +0000414 goto err;
Namarta Kohli9f052a72012-08-16 17:10:41 +0530415 }
416
417 if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) {
418 ret = rtd->dai_link->compr_ops->set_params(cstream);
419 if (ret < 0)
Charles Keepax32cfb4f2013-03-27 16:39:01 +0000420 goto err;
Namarta Kohli9f052a72012-08-16 17:10:41 +0530421 }
422
Eric Laurentf2615f72013-04-08 15:52:05 -0700423 snd_soc_dapm_stream_event(rtd,
424 codec_dai->driver->playback.stream_name,
Namarta Kohli9f052a72012-08-16 17:10:41 +0530425 SND_SOC_DAPM_STREAM_START);
426
Charles Keepax32cfb4f2013-03-27 16:39:01 +0000427 /* cancel any delayed stream shutdown that is pending */
Eric Laurent429c06f2013-05-17 14:40:59 -0700428 codec_dai->pop_wait = 0;
Charles Keepax32cfb4f2013-03-27 16:39:01 +0000429 mutex_unlock(&rtd->pcm_mutex);
430
431 cancel_delayed_work_sync(&rtd->delayed_work);
432
433 return ret;
434
435err:
Charles Keepaxed87d162013-01-24 09:44:29 +0000436 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli9f052a72012-08-16 17:10:41 +0530437 return ret;
438}
439
Liam Girdwood660db5a2013-05-21 10:25:51 +0100440static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
441 struct snd_compr_params *params)
442{
443 struct snd_soc_pcm_runtime *fe = cstream->private_data;
444 struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;
445 struct snd_soc_platform *platform = fe->platform;
446 struct snd_pcm_hw_params *hw_params;
447 int ret = 0, stream;
448
449 if (cstream->direction == SND_COMPRESS_PLAYBACK)
450 stream = SNDRV_PCM_STREAM_PLAYBACK;
451 else
452 stream = SNDRV_PCM_STREAM_CAPTURE;
453
454 hw_params = kzalloc(sizeof(*hw_params), GFP_KERNEL);
455 if (hw_params == NULL)
456 return -ENOMEM;
457
458 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
459
460 /* first we call set_params for the platform driver
461 * this should configure the soc side
462 * if the machine has compressed ops then we call that as well
463 * expectation is that platform and machine will configure everything
464 * for this compress path, like configuring pcm port for codec
465 */
466 if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
467 ret = platform->driver->compr_ops->set_params(cstream, params);
468 if (ret < 0)
469 goto out;
470 }
471
472 if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) {
473 ret = fe->dai_link->compr_ops->set_params(cstream);
474 if (ret < 0)
475 goto out;
476 }
477
Liam Girdwood660db5a2013-05-21 10:25:51 +0100478 memcpy(&fe->dpcm[fe_substream->stream].hw_params, params,
479 sizeof(struct snd_pcm_hw_params));
Eric Laurentdb88f282013-07-15 10:00:45 -0700480
481 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
482
Liam Girdwood660db5a2013-05-21 10:25:51 +0100483 ret = dpcm_be_dai_hw_params(fe, stream);
484 if (ret < 0)
485 goto out;
486
487 ret = dpcm_be_dai_prepare(fe, stream);
488 if (ret < 0)
489 goto out;
490
Eric Laurentdb88f282013-07-15 10:00:45 -0700491 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
492 dpcm_dapm_stream_event(fe, stream,
493 fe->cpu_dai->driver->playback.stream_name,
494 SND_SOC_DAPM_STREAM_START);
495 else
496 dpcm_dapm_stream_event(fe, stream,
497 fe->cpu_dai->driver->capture.stream_name,
498 SND_SOC_DAPM_STREAM_START);
499
500 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
501
Liam Girdwood660db5a2013-05-21 10:25:51 +0100502out:
Eric Laurentdb88f282013-07-15 10:00:45 -0700503 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
Liam Girdwood660db5a2013-05-21 10:25:51 +0100504 mutex_unlock(&fe->card->mutex);
505 return ret;
506}
507
Namarta Kohli9f052a72012-08-16 17:10:41 +0530508static int soc_compr_get_params(struct snd_compr_stream *cstream,
509 struct snd_codec *params)
510{
511 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
512 struct snd_soc_platform *platform = rtd->platform;
513 int ret = 0;
514
Charles Keepaxed87d162013-01-24 09:44:29 +0000515 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
516
Namarta Kohli9f052a72012-08-16 17:10:41 +0530517 if (platform->driver->compr_ops && platform->driver->compr_ops->get_params)
518 ret = platform->driver->compr_ops->get_params(cstream, params);
519
Charles Keepaxed87d162013-01-24 09:44:29 +0000520 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli9f052a72012-08-16 17:10:41 +0530521 return ret;
522}
523
524static int soc_compr_get_caps(struct snd_compr_stream *cstream,
525 struct snd_compr_caps *caps)
526{
527 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
528 struct snd_soc_platform *platform = rtd->platform;
529 int ret = 0;
530
Charles Keepaxed87d162013-01-24 09:44:29 +0000531 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
532
Namarta Kohli9f052a72012-08-16 17:10:41 +0530533 if (platform->driver->compr_ops && platform->driver->compr_ops->get_caps)
534 ret = platform->driver->compr_ops->get_caps(cstream, caps);
535
Charles Keepaxed87d162013-01-24 09:44:29 +0000536 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli9f052a72012-08-16 17:10:41 +0530537 return ret;
538}
539
540static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream,
541 struct snd_compr_codec_caps *codec)
542{
543 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
544 struct snd_soc_platform *platform = rtd->platform;
545 int ret = 0;
546
Charles Keepaxed87d162013-01-24 09:44:29 +0000547 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
548
Namarta Kohli9f052a72012-08-16 17:10:41 +0530549 if (platform->driver->compr_ops && platform->driver->compr_ops->get_codec_caps)
550 ret = platform->driver->compr_ops->get_codec_caps(cstream, codec);
551
Charles Keepaxed87d162013-01-24 09:44:29 +0000552 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli9f052a72012-08-16 17:10:41 +0530553 return ret;
554}
555
556static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
557{
558 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
559 struct snd_soc_platform *platform = rtd->platform;
560 int ret = 0;
561
Charles Keepaxed87d162013-01-24 09:44:29 +0000562 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
563
Namarta Kohli9f052a72012-08-16 17:10:41 +0530564 if (platform->driver->compr_ops && platform->driver->compr_ops->ack)
565 ret = platform->driver->compr_ops->ack(cstream, bytes);
566
Charles Keepaxed87d162013-01-24 09:44:29 +0000567 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli9f052a72012-08-16 17:10:41 +0530568 return ret;
569}
570
571static int soc_compr_pointer(struct snd_compr_stream *cstream,
572 struct snd_compr_tstamp *tstamp)
573{
574 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
575 struct snd_soc_platform *platform = rtd->platform;
576
Charles Keepaxed87d162013-01-24 09:44:29 +0000577 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
578
Namarta Kohli9f052a72012-08-16 17:10:41 +0530579 if (platform->driver->compr_ops && platform->driver->compr_ops->pointer)
580 platform->driver->compr_ops->pointer(cstream, tstamp);
581
Charles Keepaxed87d162013-01-24 09:44:29 +0000582 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli9f052a72012-08-16 17:10:41 +0530583 return 0;
584}
585
Charles Keepax67f29ae2013-02-05 10:41:47 +0000586static int soc_compr_copy(struct snd_compr_stream *cstream,
587 const char __user *buf, size_t count)
588{
589 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
590 struct snd_soc_platform *platform = rtd->platform;
591 int ret = 0;
592
593 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
594
595 if (platform->driver->compr_ops && platform->driver->compr_ops->copy)
596 ret = platform->driver->compr_ops->copy(cstream, buf, count);
597
598 mutex_unlock(&rtd->pcm_mutex);
599 return ret;
600}
601
Jeeja KP1a1f1432013-03-26 21:22:28 +0530602static int sst_compr_set_metadata(struct snd_compr_stream *cstream,
603 struct snd_compr_metadata *metadata)
604{
605 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
606 struct snd_soc_platform *platform = rtd->platform;
607 int ret = 0;
608
609 if (platform->driver->compr_ops && platform->driver->compr_ops->set_metadata)
610 ret = platform->driver->compr_ops->set_metadata(cstream, metadata);
611
612 return ret;
613}
614
615static int sst_compr_get_metadata(struct snd_compr_stream *cstream,
616 struct snd_compr_metadata *metadata)
617{
618 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
619 struct snd_soc_platform *platform = rtd->platform;
620 int ret = 0;
621
622 if (platform->driver->compr_ops && platform->driver->compr_ops->get_metadata)
623 ret = platform->driver->compr_ops->get_metadata(cstream, metadata);
624
625 return ret;
626}
Namarta Kohli9f052a72012-08-16 17:10:41 +0530627/* ASoC Compress operations */
628static struct snd_compr_ops soc_compr_ops = {
629 .open = soc_compr_open,
630 .free = soc_compr_free,
631 .set_params = soc_compr_set_params,
Jeeja KP1a1f1432013-03-26 21:22:28 +0530632 .set_metadata = sst_compr_set_metadata,
633 .get_metadata = sst_compr_get_metadata,
Namarta Kohli9f052a72012-08-16 17:10:41 +0530634 .get_params = soc_compr_get_params,
635 .trigger = soc_compr_trigger,
636 .pointer = soc_compr_pointer,
637 .ack = soc_compr_ack,
638 .get_caps = soc_compr_get_caps,
639 .get_codec_caps = soc_compr_get_codec_caps
640};
641
Liam Girdwood660db5a2013-05-21 10:25:51 +0100642/* ASoC Dynamic Compress operations */
643static struct snd_compr_ops soc_compr_dyn_ops = {
644 .open = soc_compr_open_fe,
645 .free = soc_compr_free_fe,
646 .set_params = soc_compr_set_params_fe,
647 .get_params = soc_compr_get_params,
648 .trigger = soc_compr_trigger_fe,
649 .pointer = soc_compr_pointer,
650 .ack = soc_compr_ack,
651 .get_caps = soc_compr_get_caps,
652 .get_codec_caps = soc_compr_get_codec_caps
653};
654
Namarta Kohli9f052a72012-08-16 17:10:41 +0530655/* create a new compress */
656int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
657{
658 struct snd_soc_codec *codec = rtd->codec;
Charles Keepax67f29ae2013-02-05 10:41:47 +0000659 struct snd_soc_platform *platform = rtd->platform;
Namarta Kohli9f052a72012-08-16 17:10:41 +0530660 struct snd_soc_dai *codec_dai = rtd->codec_dai;
661 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
662 struct snd_compr *compr;
Liam Girdwood660db5a2013-05-21 10:25:51 +0100663 struct snd_pcm *be_pcm;
Namarta Kohli9f052a72012-08-16 17:10:41 +0530664 char new_name[64];
665 int ret = 0, direction = 0;
666
667 /* check client and interface hw capabilities */
668 snprintf(new_name, sizeof(new_name), "%s %s-%d",
669 rtd->dai_link->stream_name, codec_dai->name, num);
670 direction = SND_COMPRESS_PLAYBACK;
671 compr = kzalloc(sizeof(*compr), GFP_KERNEL);
672 if (compr == NULL) {
673 snd_printk(KERN_ERR "Cannot allocate compr\n");
674 return -ENOMEM;
675 }
676
Charles Keepax67f29ae2013-02-05 10:41:47 +0000677 compr->ops = devm_kzalloc(rtd->card->dev, sizeof(soc_compr_ops),
678 GFP_KERNEL);
679 if (compr->ops == NULL) {
680 dev_err(rtd->card->dev, "Cannot allocate compressed ops\n");
681 ret = -ENOMEM;
682 goto compr_err;
683 }
Liam Girdwood660db5a2013-05-21 10:25:51 +0100684
685 if (rtd->dai_link->dynamic) {
686 snprintf(new_name, sizeof(new_name), "(%s)",
687 rtd->dai_link->stream_name);
688
689 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
690 1, 0, &be_pcm);
691 if (ret < 0) {
692 dev_err(rtd->card->dev, "ASoC: can't create compressed for %s\n",
693 rtd->dai_link->name);
694 goto compr_err;
695 }
696
697 rtd->pcm = be_pcm;
698 rtd->fe_compr = 1;
699 be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
700 //be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
701 memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops));
702 } else
703 memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));
Charles Keepax67f29ae2013-02-05 10:41:47 +0000704
705 /* Add copy callback for not memory mapped DSPs */
706 if (platform->driver->compr_ops && platform->driver->compr_ops->copy)
707 compr->ops->copy = soc_compr_copy;
708
Namarta Kohli9f052a72012-08-16 17:10:41 +0530709 mutex_init(&compr->lock);
710 ret = snd_compress_new(rtd->card->snd_card, num, direction, compr);
711 if (ret < 0) {
712 pr_err("compress asoc: can't create compress for codec %s\n",
713 codec->name);
Charles Keepax67f29ae2013-02-05 10:41:47 +0000714 goto compr_err;
Namarta Kohli9f052a72012-08-16 17:10:41 +0530715 }
716
Charles Keepax57f8e792013-01-24 09:44:30 +0000717 /* DAPM dai link stream work */
718 INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
719
Namarta Kohli9f052a72012-08-16 17:10:41 +0530720 rtd->compr = compr;
721 compr->private_data = rtd;
722
723 printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name,
724 cpu_dai->name);
725 return ret;
Charles Keepax67f29ae2013-02-05 10:41:47 +0000726
727compr_err:
728 kfree(compr);
729 return ret;
Namarta Kohli9f052a72012-08-16 17:10:41 +0530730}