blob: c48db6391ad53696ed17e91af54272965c304d92 [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>
27
28static int soc_compr_open(struct snd_compr_stream *cstream)
29{
30 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
31 struct snd_soc_platform *platform = rtd->platform;
32 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
33 struct snd_soc_dai *codec_dai = rtd->codec_dai;
34 int ret = 0;
35
Charles Keepax15e2e612013-01-24 09:44:29 +000036 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
37
Namarta Kohli1245b702012-08-16 17:10:41 +053038 if (platform->driver->compr_ops && platform->driver->compr_ops->open) {
39 ret = platform->driver->compr_ops->open(cstream);
40 if (ret < 0) {
41 pr_err("compress asoc: can't open platform %s\n", platform->name);
42 goto out;
43 }
44 }
45
46 if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->startup) {
47 ret = rtd->dai_link->compr_ops->startup(cstream);
48 if (ret < 0) {
49 pr_err("compress asoc: %s startup failed\n", rtd->dai_link->name);
50 goto machine_err;
51 }
52 }
53
54 if (cstream->direction == SND_COMPRESS_PLAYBACK) {
55 cpu_dai->playback_active++;
56 codec_dai->playback_active++;
57 } else {
58 cpu_dai->capture_active++;
59 codec_dai->capture_active++;
60 }
61
62 cpu_dai->active++;
63 codec_dai->active++;
64 rtd->codec->active++;
65
Charles Keepax15e2e612013-01-24 09:44:29 +000066 mutex_unlock(&rtd->pcm_mutex);
67
Namarta Kohli1245b702012-08-16 17:10:41 +053068 return 0;
69
70machine_err:
71 if (platform->driver->compr_ops && platform->driver->compr_ops->free)
72 platform->driver->compr_ops->free(cstream);
73out:
Charles Keepax15e2e612013-01-24 09:44:29 +000074 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +053075 return ret;
76}
77
78static int soc_compr_free(struct snd_compr_stream *cstream)
79{
80 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
81 struct snd_soc_platform *platform = rtd->platform;
82 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
83 struct snd_soc_dai *codec_dai = rtd->codec_dai;
84 struct snd_soc_codec *codec = rtd->codec;
85
Charles Keepax15e2e612013-01-24 09:44:29 +000086 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
87
Namarta Kohli1245b702012-08-16 17:10:41 +053088 if (cstream->direction == SND_COMPRESS_PLAYBACK) {
89 cpu_dai->playback_active--;
90 codec_dai->playback_active--;
91 } else {
92 cpu_dai->capture_active--;
93 codec_dai->capture_active--;
94 }
95
96 snd_soc_dai_digital_mute(codec_dai, 1);
97
98 cpu_dai->active--;
99 codec_dai->active--;
100 codec->active--;
101
102 if (!cpu_dai->active)
103 cpu_dai->rate = 0;
104
105 if (!codec_dai->active)
106 codec_dai->rate = 0;
107
108
109 if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown)
110 rtd->dai_link->compr_ops->shutdown(cstream);
111
112 if (platform->driver->compr_ops && platform->driver->compr_ops->free)
113 platform->driver->compr_ops->free(cstream);
Vinod Koul9d2667a2012-08-21 12:15:02 +0530114 cpu_dai->runtime = NULL;
Namarta Kohli1245b702012-08-16 17:10:41 +0530115
116 if (cstream->direction == SND_COMPRESS_PLAYBACK) {
117 if (!rtd->pmdown_time || codec->ignore_pmdown_time ||
118 rtd->dai_link->ignore_pmdown_time) {
119 snd_soc_dapm_stream_event(rtd,
120 SNDRV_PCM_STREAM_PLAYBACK,
121 SND_SOC_DAPM_STREAM_STOP);
Charles Keepax8c3d2aa2013-01-24 09:44:28 +0000122 } else {
Misael Lopez Cruz9bffb1f2012-12-13 12:23:05 -0600123 rtd->pop_wait = 1;
Namarta Kohli1245b702012-08-16 17:10:41 +0530124 schedule_delayed_work(&rtd->delayed_work,
125 msecs_to_jiffies(rtd->pmdown_time));
Charles Keepax8c3d2aa2013-01-24 09:44:28 +0000126 }
Namarta Kohli1245b702012-08-16 17:10:41 +0530127 } else {
128 /* capture streams can be powered down now */
129 snd_soc_dapm_stream_event(rtd,
130 SNDRV_PCM_STREAM_CAPTURE,
131 SND_SOC_DAPM_STREAM_STOP);
132 }
133
Charles Keepax15e2e612013-01-24 09:44:29 +0000134 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530135 return 0;
136}
137
138static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
139{
140
141 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
142 struct snd_soc_platform *platform = rtd->platform;
143 struct snd_soc_dai *codec_dai = rtd->codec_dai;
144 int ret = 0;
145
Charles Keepax15e2e612013-01-24 09:44:29 +0000146 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
147
Namarta Kohli1245b702012-08-16 17:10:41 +0530148 if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
149 ret = platform->driver->compr_ops->trigger(cstream, cmd);
150 if (ret < 0)
Charles Keepax15e2e612013-01-24 09:44:29 +0000151 goto out;
Namarta Kohli1245b702012-08-16 17:10:41 +0530152 }
153
154 if (cmd == SNDRV_PCM_TRIGGER_START)
155 snd_soc_dai_digital_mute(codec_dai, 0);
156 else if (cmd == SNDRV_PCM_TRIGGER_STOP)
157 snd_soc_dai_digital_mute(codec_dai, 1);
158
Charles Keepax15e2e612013-01-24 09:44:29 +0000159out:
160 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530161 return ret;
162}
163
164static int soc_compr_set_params(struct snd_compr_stream *cstream,
165 struct snd_compr_params *params)
166{
167 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
168 struct snd_soc_platform *platform = rtd->platform;
Namarta Kohli1245b702012-08-16 17:10:41 +0530169 int ret = 0;
170
Charles Keepax15e2e612013-01-24 09:44:29 +0000171 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
172
Namarta Kohli1245b702012-08-16 17:10:41 +0530173 /* first we call set_params for the platform driver
174 * this should configure the soc side
175 * if the machine has compressed ops then we call that as well
176 * expectation is that platform and machine will configure everything
177 * for this compress path, like configuring pcm port for codec
178 */
179 if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
180 ret = platform->driver->compr_ops->set_params(cstream, params);
181 if (ret < 0)
Charles Keepax15e2e612013-01-24 09:44:29 +0000182 goto out;
Namarta Kohli1245b702012-08-16 17:10:41 +0530183 }
184
185 if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) {
186 ret = rtd->dai_link->compr_ops->set_params(cstream);
187 if (ret < 0)
Charles Keepax15e2e612013-01-24 09:44:29 +0000188 goto out;
Namarta Kohli1245b702012-08-16 17:10:41 +0530189 }
190
191 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
192 SND_SOC_DAPM_STREAM_START);
193
Charles Keepax15e2e612013-01-24 09:44:29 +0000194out:
195 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530196 return ret;
197}
198
199static int soc_compr_get_params(struct snd_compr_stream *cstream,
200 struct snd_codec *params)
201{
202 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
203 struct snd_soc_platform *platform = rtd->platform;
204 int ret = 0;
205
Charles Keepax15e2e612013-01-24 09:44:29 +0000206 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
207
Namarta Kohli1245b702012-08-16 17:10:41 +0530208 if (platform->driver->compr_ops && platform->driver->compr_ops->get_params)
209 ret = platform->driver->compr_ops->get_params(cstream, params);
210
Charles Keepax15e2e612013-01-24 09:44:29 +0000211 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530212 return ret;
213}
214
215static int soc_compr_get_caps(struct snd_compr_stream *cstream,
216 struct snd_compr_caps *caps)
217{
218 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
219 struct snd_soc_platform *platform = rtd->platform;
220 int ret = 0;
221
Charles Keepax15e2e612013-01-24 09:44:29 +0000222 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
223
Namarta Kohli1245b702012-08-16 17:10:41 +0530224 if (platform->driver->compr_ops && platform->driver->compr_ops->get_caps)
225 ret = platform->driver->compr_ops->get_caps(cstream, caps);
226
Charles Keepax15e2e612013-01-24 09:44:29 +0000227 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530228 return ret;
229}
230
231static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream,
232 struct snd_compr_codec_caps *codec)
233{
234 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
235 struct snd_soc_platform *platform = rtd->platform;
236 int ret = 0;
237
Charles Keepax15e2e612013-01-24 09:44:29 +0000238 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
239
Namarta Kohli1245b702012-08-16 17:10:41 +0530240 if (platform->driver->compr_ops && platform->driver->compr_ops->get_codec_caps)
241 ret = platform->driver->compr_ops->get_codec_caps(cstream, codec);
242
Charles Keepax15e2e612013-01-24 09:44:29 +0000243 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530244 return ret;
245}
246
247static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
248{
249 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
250 struct snd_soc_platform *platform = rtd->platform;
251 int ret = 0;
252
Charles Keepax15e2e612013-01-24 09:44:29 +0000253 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
254
Namarta Kohli1245b702012-08-16 17:10:41 +0530255 if (platform->driver->compr_ops && platform->driver->compr_ops->ack)
256 ret = platform->driver->compr_ops->ack(cstream, bytes);
257
Charles Keepax15e2e612013-01-24 09:44:29 +0000258 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530259 return ret;
260}
261
262static int soc_compr_pointer(struct snd_compr_stream *cstream,
263 struct snd_compr_tstamp *tstamp)
264{
265 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
266 struct snd_soc_platform *platform = rtd->platform;
267
Charles Keepax15e2e612013-01-24 09:44:29 +0000268 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
269
Namarta Kohli1245b702012-08-16 17:10:41 +0530270 if (platform->driver->compr_ops && platform->driver->compr_ops->pointer)
271 platform->driver->compr_ops->pointer(cstream, tstamp);
272
Charles Keepax15e2e612013-01-24 09:44:29 +0000273 mutex_unlock(&rtd->pcm_mutex);
Namarta Kohli1245b702012-08-16 17:10:41 +0530274 return 0;
275}
276
277/* ASoC Compress operations */
278static struct snd_compr_ops soc_compr_ops = {
279 .open = soc_compr_open,
280 .free = soc_compr_free,
281 .set_params = soc_compr_set_params,
282 .get_params = soc_compr_get_params,
283 .trigger = soc_compr_trigger,
284 .pointer = soc_compr_pointer,
285 .ack = soc_compr_ack,
286 .get_caps = soc_compr_get_caps,
287 .get_codec_caps = soc_compr_get_codec_caps
288};
289
290/* create a new compress */
291int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
292{
293 struct snd_soc_codec *codec = rtd->codec;
294 struct snd_soc_dai *codec_dai = rtd->codec_dai;
295 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
296 struct snd_compr *compr;
297 char new_name[64];
298 int ret = 0, direction = 0;
299
300 /* check client and interface hw capabilities */
301 snprintf(new_name, sizeof(new_name), "%s %s-%d",
302 rtd->dai_link->stream_name, codec_dai->name, num);
303 direction = SND_COMPRESS_PLAYBACK;
304 compr = kzalloc(sizeof(*compr), GFP_KERNEL);
305 if (compr == NULL) {
306 snd_printk(KERN_ERR "Cannot allocate compr\n");
307 return -ENOMEM;
308 }
309
310 compr->ops = &soc_compr_ops;
311 mutex_init(&compr->lock);
312 ret = snd_compress_new(rtd->card->snd_card, num, direction, compr);
313 if (ret < 0) {
314 pr_err("compress asoc: can't create compress for codec %s\n",
315 codec->name);
316 kfree(compr);
317 return ret;
318 }
319
320 rtd->compr = compr;
321 compr->private_data = rtd;
322
323 printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name,
324 cpu_dai->name);
325 return ret;
326}