diff options
author | Namarta Kohli <namartax.kohli@intel.com> | 2012-08-16 07:40:41 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-08-20 15:50:38 -0400 |
commit | 1245b7005de02d5bfa0c321df925f5b6c83c99e1 (patch) | |
tree | 2b97e0fd6a3cf560b8844568ba517bda24d75b9d | |
parent | 4968107786e75f5aaba3c1c8e959ccbae929457f (diff) |
ASoC: add compress stream support
This patch adds the support to parse the compress dai's and then also adds the
soc-compress.c file while handles the compress stream operations, mostly analogus
to what is done in the soc-pcm.c and aditional handling of the compress
opertaions
Signed-off-by: Namarta Kohli <namartax.kohli@intel.com>
Signed-off-by: Ramesh Babu K V <ramesh.babu@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r-- | sound/soc/Kconfig | 1 | ||||
-rw-r--r-- | sound/soc/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/soc-compress.c | 295 | ||||
-rw-r--r-- | sound/soc/soc-core.c | 57 |
4 files changed, 331 insertions, 24 deletions
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index c5de0a84566f..c24de902f5f5 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig | |||
@@ -9,6 +9,7 @@ menuconfig SND_SOC | |||
9 | select SND_JACK if INPUT=y || INPUT=SND | 9 | select SND_JACK if INPUT=y || INPUT=SND |
10 | select REGMAP_I2C if I2C | 10 | select REGMAP_I2C if I2C |
11 | select REGMAP_SPI if SPI_MASTER | 11 | select REGMAP_SPI if SPI_MASTER |
12 | select SND_COMPRESS_OFFLOAD | ||
12 | ---help--- | 13 | ---help--- |
13 | 14 | ||
14 | If you want ASoC support, you should say Y here and also to the | 15 | If you want ASoC support, you should say Y here and also to the |
diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 00a555a743b6..c1264007b4ee 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o | 1 | snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o |
2 | snd-soc-core-objs += soc-pcm.o soc-io.o | 2 | snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o |
3 | 3 | ||
4 | snd-soc-dmaengine-pcm-objs := soc-dmaengine-pcm.o | 4 | snd-soc-dmaengine-pcm-objs := soc-dmaengine-pcm.o |
5 | obj-$(CONFIG_SND_SOC_DMAENGINE_PCM) += snd-soc-dmaengine-pcm.o | 5 | obj-$(CONFIG_SND_SOC_DMAENGINE_PCM) += snd-soc-dmaengine-pcm.o |
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c new file mode 100644 index 000000000000..88d85badd932 --- /dev/null +++ b/sound/soc/soc-compress.c | |||
@@ -0,0 +1,295 @@ | |||
1 | /* | ||
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 | |||
28 | static 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 | |||
36 | if (platform->driver->compr_ops && platform->driver->compr_ops->open) { | ||
37 | ret = platform->driver->compr_ops->open(cstream); | ||
38 | if (ret < 0) { | ||
39 | pr_err("compress asoc: can't open platform %s\n", platform->name); | ||
40 | goto out; | ||
41 | } | ||
42 | } | ||
43 | |||
44 | if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->startup) { | ||
45 | ret = rtd->dai_link->compr_ops->startup(cstream); | ||
46 | if (ret < 0) { | ||
47 | pr_err("compress asoc: %s startup failed\n", rtd->dai_link->name); | ||
48 | goto machine_err; | ||
49 | } | ||
50 | } | ||
51 | |||
52 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { | ||
53 | cpu_dai->playback_active++; | ||
54 | codec_dai->playback_active++; | ||
55 | } else { | ||
56 | cpu_dai->capture_active++; | ||
57 | codec_dai->capture_active++; | ||
58 | } | ||
59 | |||
60 | cpu_dai->active++; | ||
61 | codec_dai->active++; | ||
62 | rtd->codec->active++; | ||
63 | |||
64 | return 0; | ||
65 | |||
66 | machine_err: | ||
67 | if (platform->driver->compr_ops && platform->driver->compr_ops->free) | ||
68 | platform->driver->compr_ops->free(cstream); | ||
69 | out: | ||
70 | return ret; | ||
71 | } | ||
72 | |||
73 | static int soc_compr_free(struct snd_compr_stream *cstream) | ||
74 | { | ||
75 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | ||
76 | struct snd_soc_platform *platform = rtd->platform; | ||
77 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
78 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
79 | struct snd_soc_codec *codec = rtd->codec; | ||
80 | |||
81 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { | ||
82 | cpu_dai->playback_active--; | ||
83 | codec_dai->playback_active--; | ||
84 | } else { | ||
85 | cpu_dai->capture_active--; | ||
86 | codec_dai->capture_active--; | ||
87 | } | ||
88 | |||
89 | snd_soc_dai_digital_mute(codec_dai, 1); | ||
90 | |||
91 | cpu_dai->active--; | ||
92 | codec_dai->active--; | ||
93 | codec->active--; | ||
94 | |||
95 | if (!cpu_dai->active) | ||
96 | cpu_dai->rate = 0; | ||
97 | |||
98 | if (!codec_dai->active) | ||
99 | codec_dai->rate = 0; | ||
100 | |||
101 | |||
102 | if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown) | ||
103 | rtd->dai_link->compr_ops->shutdown(cstream); | ||
104 | |||
105 | if (platform->driver->compr_ops && platform->driver->compr_ops->free) | ||
106 | platform->driver->compr_ops->free(cstream); | ||
107 | cpu_dai->runtime = NULL; | ||
108 | |||
109 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { | ||
110 | if (!rtd->pmdown_time || codec->ignore_pmdown_time || | ||
111 | rtd->dai_link->ignore_pmdown_time) { | ||
112 | snd_soc_dapm_stream_event(rtd, | ||
113 | SNDRV_PCM_STREAM_PLAYBACK, | ||
114 | SND_SOC_DAPM_STREAM_STOP); | ||
115 | } else | ||
116 | codec_dai->pop_wait = 1; | ||
117 | schedule_delayed_work(&rtd->delayed_work, | ||
118 | msecs_to_jiffies(rtd->pmdown_time)); | ||
119 | } else { | ||
120 | /* capture streams can be powered down now */ | ||
121 | snd_soc_dapm_stream_event(rtd, | ||
122 | SNDRV_PCM_STREAM_CAPTURE, | ||
123 | SND_SOC_DAPM_STREAM_STOP); | ||
124 | } | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) | ||
130 | { | ||
131 | |||
132 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | ||
133 | struct snd_soc_platform *platform = rtd->platform; | ||
134 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
135 | int ret = 0; | ||
136 | |||
137 | if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) { | ||
138 | ret = platform->driver->compr_ops->trigger(cstream, cmd); | ||
139 | if (ret < 0) | ||
140 | return ret; | ||
141 | } | ||
142 | |||
143 | if (cmd == SNDRV_PCM_TRIGGER_START) | ||
144 | snd_soc_dai_digital_mute(codec_dai, 0); | ||
145 | else if (cmd == SNDRV_PCM_TRIGGER_STOP) | ||
146 | snd_soc_dai_digital_mute(codec_dai, 1); | ||
147 | |||
148 | return ret; | ||
149 | } | ||
150 | |||
151 | static int soc_compr_set_params(struct snd_compr_stream *cstream, | ||
152 | struct snd_compr_params *params) | ||
153 | { | ||
154 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | ||
155 | struct snd_soc_platform *platform = rtd->platform; | ||
156 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
157 | int ret = 0; | ||
158 | |||
159 | /* first we call set_params for the platform driver | ||
160 | * this should configure the soc side | ||
161 | * if the machine has compressed ops then we call that as well | ||
162 | * expectation is that platform and machine will configure everything | ||
163 | * for this compress path, like configuring pcm port for codec | ||
164 | */ | ||
165 | if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) { | ||
166 | ret = platform->driver->compr_ops->set_params(cstream, params); | ||
167 | if (ret < 0) | ||
168 | return ret; | ||
169 | } | ||
170 | |||
171 | if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) { | ||
172 | ret = rtd->dai_link->compr_ops->set_params(cstream); | ||
173 | if (ret < 0) | ||
174 | return ret; | ||
175 | } | ||
176 | |||
177 | snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, | ||
178 | SND_SOC_DAPM_STREAM_START); | ||
179 | |||
180 | return ret; | ||
181 | } | ||
182 | |||
183 | static int soc_compr_get_params(struct snd_compr_stream *cstream, | ||
184 | struct snd_codec *params) | ||
185 | { | ||
186 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | ||
187 | struct snd_soc_platform *platform = rtd->platform; | ||
188 | int ret = 0; | ||
189 | |||
190 | if (platform->driver->compr_ops && platform->driver->compr_ops->get_params) | ||
191 | ret = platform->driver->compr_ops->get_params(cstream, params); | ||
192 | |||
193 | return ret; | ||
194 | } | ||
195 | |||
196 | static int soc_compr_get_caps(struct snd_compr_stream *cstream, | ||
197 | struct snd_compr_caps *caps) | ||
198 | { | ||
199 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | ||
200 | struct snd_soc_platform *platform = rtd->platform; | ||
201 | int ret = 0; | ||
202 | |||
203 | if (platform->driver->compr_ops && platform->driver->compr_ops->get_caps) | ||
204 | ret = platform->driver->compr_ops->get_caps(cstream, caps); | ||
205 | |||
206 | return ret; | ||
207 | } | ||
208 | |||
209 | static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, | ||
210 | struct snd_compr_codec_caps *codec) | ||
211 | { | ||
212 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | ||
213 | struct snd_soc_platform *platform = rtd->platform; | ||
214 | int ret = 0; | ||
215 | |||
216 | if (platform->driver->compr_ops && platform->driver->compr_ops->get_codec_caps) | ||
217 | ret = platform->driver->compr_ops->get_codec_caps(cstream, codec); | ||
218 | |||
219 | return ret; | ||
220 | } | ||
221 | |||
222 | static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) | ||
223 | { | ||
224 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | ||
225 | struct snd_soc_platform *platform = rtd->platform; | ||
226 | int ret = 0; | ||
227 | |||
228 | if (platform->driver->compr_ops && platform->driver->compr_ops->ack) | ||
229 | ret = platform->driver->compr_ops->ack(cstream, bytes); | ||
230 | |||
231 | return ret; | ||
232 | } | ||
233 | |||
234 | static int soc_compr_pointer(struct snd_compr_stream *cstream, | ||
235 | struct snd_compr_tstamp *tstamp) | ||
236 | { | ||
237 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | ||
238 | struct snd_soc_platform *platform = rtd->platform; | ||
239 | |||
240 | if (platform->driver->compr_ops && platform->driver->compr_ops->pointer) | ||
241 | platform->driver->compr_ops->pointer(cstream, tstamp); | ||
242 | |||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | /* ASoC Compress operations */ | ||
247 | static struct snd_compr_ops soc_compr_ops = { | ||
248 | .open = soc_compr_open, | ||
249 | .free = soc_compr_free, | ||
250 | .set_params = soc_compr_set_params, | ||
251 | .get_params = soc_compr_get_params, | ||
252 | .trigger = soc_compr_trigger, | ||
253 | .pointer = soc_compr_pointer, | ||
254 | .ack = soc_compr_ack, | ||
255 | .get_caps = soc_compr_get_caps, | ||
256 | .get_codec_caps = soc_compr_get_codec_caps | ||
257 | }; | ||
258 | |||
259 | /* create a new compress */ | ||
260 | int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) | ||
261 | { | ||
262 | struct snd_soc_codec *codec = rtd->codec; | ||
263 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
264 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
265 | struct snd_compr *compr; | ||
266 | char new_name[64]; | ||
267 | int ret = 0, direction = 0; | ||
268 | |||
269 | /* check client and interface hw capabilities */ | ||
270 | snprintf(new_name, sizeof(new_name), "%s %s-%d", | ||
271 | rtd->dai_link->stream_name, codec_dai->name, num); | ||
272 | direction = SND_COMPRESS_PLAYBACK; | ||
273 | compr = kzalloc(sizeof(*compr), GFP_KERNEL); | ||
274 | if (compr == NULL) { | ||
275 | snd_printk(KERN_ERR "Cannot allocate compr\n"); | ||
276 | return -ENOMEM; | ||
277 | } | ||
278 | |||
279 | compr->ops = &soc_compr_ops; | ||
280 | mutex_init(&compr->lock); | ||
281 | ret = snd_compress_new(rtd->card->snd_card, num, direction, compr); | ||
282 | if (ret < 0) { | ||
283 | pr_err("compress asoc: can't create compress for codec %s\n", | ||
284 | codec->name); | ||
285 | kfree(compr); | ||
286 | return ret; | ||
287 | } | ||
288 | |||
289 | rtd->compr = compr; | ||
290 | compr->private_data = rtd; | ||
291 | |||
292 | printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name, | ||
293 | cpu_dai->name); | ||
294 | return ret; | ||
295 | } | ||
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f585d0239551..c7a00fd8cc66 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -1388,37 +1388,48 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) | |||
1388 | if (ret < 0) | 1388 | if (ret < 0) |
1389 | pr_warn("asoc: failed to add pmdown_time sysfs:%d\n", ret); | 1389 | pr_warn("asoc: failed to add pmdown_time sysfs:%d\n", ret); |
1390 | 1390 | ||
1391 | if (!dai_link->params) { | 1391 | if (cpu_dai->driver->compress_dai) { |
1392 | /* create the pcm */ | 1392 | /*create compress_device"*/ |
1393 | ret = soc_new_pcm(rtd, num); | 1393 | ret = soc_new_compress(rtd, num); |
1394 | if (ret < 0) { | 1394 | if (ret < 0) { |
1395 | pr_err("asoc: can't create pcm %s :%d\n", | 1395 | pr_err("asoc: can't create compress %s\n", |
1396 | dai_link->stream_name, ret); | 1396 | dai_link->stream_name); |
1397 | return ret; | 1397 | return ret; |
1398 | } | 1398 | } |
1399 | } else { | 1399 | } else { |
1400 | /* link the DAI widgets */ | 1400 | |
1401 | play_w = codec_dai->playback_widget; | 1401 | if (!dai_link->params) { |
1402 | capture_w = cpu_dai->capture_widget; | 1402 | /* create the pcm */ |
1403 | if (play_w && capture_w) { | 1403 | ret = soc_new_pcm(rtd, num); |
1404 | ret = snd_soc_dapm_new_pcm(card, dai_link->params, | 1404 | if (ret < 0) { |
1405 | capture_w, play_w); | 1405 | pr_err("asoc: can't create pcm %s :%d\n", |
1406 | if (ret != 0) { | 1406 | dai_link->stream_name, ret); |
1407 | dev_err(card->dev, "Can't link %s to %s: %d\n", | ||
1408 | play_w->name, capture_w->name, ret); | ||
1409 | return ret; | 1407 | return ret; |
1410 | } | 1408 | } |
1411 | } | 1409 | } else { |
1410 | /* link the DAI widgets */ | ||
1411 | play_w = codec_dai->playback_widget; | ||
1412 | capture_w = cpu_dai->capture_widget; | ||
1413 | if (play_w && capture_w) { | ||
1414 | ret = snd_soc_dapm_new_pcm(card, dai_link->params, | ||
1415 | capture_w, play_w); | ||
1416 | if (ret != 0) { | ||
1417 | dev_err(card->dev, "Can't link %s to %s: %d\n", | ||
1418 | play_w->name, capture_w->name, ret); | ||
1419 | return ret; | ||
1420 | } | ||
1421 | } | ||
1412 | 1422 | ||
1413 | play_w = cpu_dai->playback_widget; | 1423 | play_w = cpu_dai->playback_widget; |
1414 | capture_w = codec_dai->capture_widget; | 1424 | capture_w = codec_dai->capture_widget; |
1415 | if (play_w && capture_w) { | 1425 | if (play_w && capture_w) { |
1416 | ret = snd_soc_dapm_new_pcm(card, dai_link->params, | 1426 | ret = snd_soc_dapm_new_pcm(card, dai_link->params, |
1417 | capture_w, play_w); | 1427 | capture_w, play_w); |
1418 | if (ret != 0) { | 1428 | if (ret != 0) { |
1419 | dev_err(card->dev, "Can't link %s to %s: %d\n", | 1429 | dev_err(card->dev, "Can't link %s to %s: %d\n", |
1420 | play_w->name, capture_w->name, ret); | 1430 | play_w->name, capture_w->name, ret); |
1421 | return ret; | 1431 | return ret; |
1432 | } | ||
1422 | } | 1433 | } |
1423 | } | 1434 | } |
1424 | } | 1435 | } |