aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-compress.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/soc-compress.c')
-rw-r--r--sound/soc/soc-compress.c123
1 files changed, 111 insertions, 12 deletions
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 5fbfb06e8083..b5b3db71e253 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -33,6 +33,8 @@ static int soc_compr_open(struct snd_compr_stream *cstream)
33 struct snd_soc_dai *codec_dai = rtd->codec_dai; 33 struct snd_soc_dai *codec_dai = rtd->codec_dai;
34 int ret = 0; 34 int ret = 0;
35 35
36 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
37
36 if (platform->driver->compr_ops && platform->driver->compr_ops->open) { 38 if (platform->driver->compr_ops && platform->driver->compr_ops->open) {
37 ret = platform->driver->compr_ops->open(cstream); 39 ret = platform->driver->compr_ops->open(cstream);
38 if (ret < 0) { 40 if (ret < 0) {
@@ -61,15 +63,46 @@ static int soc_compr_open(struct snd_compr_stream *cstream)
61 codec_dai->active++; 63 codec_dai->active++;
62 rtd->codec->active++; 64 rtd->codec->active++;
63 65
66 mutex_unlock(&rtd->pcm_mutex);
67
64 return 0; 68 return 0;
65 69
66machine_err: 70machine_err:
67 if (platform->driver->compr_ops && platform->driver->compr_ops->free) 71 if (platform->driver->compr_ops && platform->driver->compr_ops->free)
68 platform->driver->compr_ops->free(cstream); 72 platform->driver->compr_ops->free(cstream);
69out: 73out:
74 mutex_unlock(&rtd->pcm_mutex);
70 return ret; 75 return ret;
71} 76}
72 77
78/*
79 * Power down the audio subsystem pmdown_time msecs after close is called.
80 * This is to ensure there are no pops or clicks in between any music tracks
81 * due to DAPM power cycling.
82 */
83static void close_delayed_work(struct work_struct *work)
84{
85 struct snd_soc_pcm_runtime *rtd =
86 container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
87 struct snd_soc_dai *codec_dai = rtd->codec_dai;
88
89 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
90
91 dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n",
92 codec_dai->driver->playback.stream_name,
93 codec_dai->playback_active ? "active" : "inactive",
94 rtd->pop_wait ? "yes" : "no");
95
96 /* are we waiting on this codec DAI stream */
97 if (rtd->pop_wait == 1) {
98 rtd->pop_wait = 0;
99 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
100 SND_SOC_DAPM_STREAM_STOP);
101 }
102
103 mutex_unlock(&rtd->pcm_mutex);
104}
105
73static int soc_compr_free(struct snd_compr_stream *cstream) 106static int soc_compr_free(struct snd_compr_stream *cstream)
74{ 107{
75 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 108 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
@@ -78,6 +111,8 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
78 struct snd_soc_dai *codec_dai = rtd->codec_dai; 111 struct snd_soc_dai *codec_dai = rtd->codec_dai;
79 struct snd_soc_codec *codec = rtd->codec; 112 struct snd_soc_codec *codec = rtd->codec;
80 113
114 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
115
81 if (cstream->direction == SND_COMPRESS_PLAYBACK) { 116 if (cstream->direction == SND_COMPRESS_PLAYBACK) {
82 cpu_dai->playback_active--; 117 cpu_dai->playback_active--;
83 codec_dai->playback_active--; 118 codec_dai->playback_active--;
@@ -86,7 +121,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
86 codec_dai->capture_active--; 121 codec_dai->capture_active--;
87 } 122 }
88 123
89 snd_soc_dai_digital_mute(codec_dai, 1); 124 snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
90 125
91 cpu_dai->active--; 126 cpu_dai->active--;
92 codec_dai->active--; 127 codec_dai->active--;
@@ -112,10 +147,11 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
112 snd_soc_dapm_stream_event(rtd, 147 snd_soc_dapm_stream_event(rtd,
113 SNDRV_PCM_STREAM_PLAYBACK, 148 SNDRV_PCM_STREAM_PLAYBACK,
114 SND_SOC_DAPM_STREAM_STOP); 149 SND_SOC_DAPM_STREAM_STOP);
115 } else 150 } else {
116 rtd->pop_wait = 1; 151 rtd->pop_wait = 1;
117 schedule_delayed_work(&rtd->delayed_work, 152 schedule_delayed_work(&rtd->delayed_work,
118 msecs_to_jiffies(rtd->pmdown_time)); 153 msecs_to_jiffies(rtd->pmdown_time));
154 }
119 } else { 155 } else {
120 /* capture streams can be powered down now */ 156 /* capture streams can be powered down now */
121 snd_soc_dapm_stream_event(rtd, 157 snd_soc_dapm_stream_event(rtd,
@@ -123,6 +159,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
123 SND_SOC_DAPM_STREAM_STOP); 159 SND_SOC_DAPM_STREAM_STOP);
124 } 160 }
125 161
162 mutex_unlock(&rtd->pcm_mutex);
126 return 0; 163 return 0;
127} 164}
128 165
@@ -134,17 +171,25 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
134 struct snd_soc_dai *codec_dai = rtd->codec_dai; 171 struct snd_soc_dai *codec_dai = rtd->codec_dai;
135 int ret = 0; 172 int ret = 0;
136 173
174 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
175
137 if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) { 176 if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
138 ret = platform->driver->compr_ops->trigger(cstream, cmd); 177 ret = platform->driver->compr_ops->trigger(cstream, cmd);
139 if (ret < 0) 178 if (ret < 0)
140 return ret; 179 goto out;
141 } 180 }
142 181
143 if (cmd == SNDRV_PCM_TRIGGER_START) 182 switch (cmd) {
144 snd_soc_dai_digital_mute(codec_dai, 0); 183 case SNDRV_PCM_TRIGGER_START:
145 else if (cmd == SNDRV_PCM_TRIGGER_STOP) 184 snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction);
146 snd_soc_dai_digital_mute(codec_dai, 1); 185 break;
186 case SNDRV_PCM_TRIGGER_STOP:
187 snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
188 break;
189 }
147 190
191out:
192 mutex_unlock(&rtd->pcm_mutex);
148 return ret; 193 return ret;
149} 194}
150 195
@@ -155,6 +200,8 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream,
155 struct snd_soc_platform *platform = rtd->platform; 200 struct snd_soc_platform *platform = rtd->platform;
156 int ret = 0; 201 int ret = 0;
157 202
203 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
204
158 /* first we call set_params for the platform driver 205 /* first we call set_params for the platform driver
159 * this should configure the soc side 206 * this should configure the soc side
160 * if the machine has compressed ops then we call that as well 207 * if the machine has compressed ops then we call that as well
@@ -164,18 +211,20 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream,
164 if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) { 211 if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
165 ret = platform->driver->compr_ops->set_params(cstream, params); 212 ret = platform->driver->compr_ops->set_params(cstream, params);
166 if (ret < 0) 213 if (ret < 0)
167 return ret; 214 goto out;
168 } 215 }
169 216
170 if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) { 217 if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) {
171 ret = rtd->dai_link->compr_ops->set_params(cstream); 218 ret = rtd->dai_link->compr_ops->set_params(cstream);
172 if (ret < 0) 219 if (ret < 0)
173 return ret; 220 goto out;
174 } 221 }
175 222
176 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, 223 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
177 SND_SOC_DAPM_STREAM_START); 224 SND_SOC_DAPM_STREAM_START);
178 225
226out:
227 mutex_unlock(&rtd->pcm_mutex);
179 return ret; 228 return ret;
180} 229}
181 230
@@ -186,9 +235,12 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream,
186 struct snd_soc_platform *platform = rtd->platform; 235 struct snd_soc_platform *platform = rtd->platform;
187 int ret = 0; 236 int ret = 0;
188 237
238 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
239
189 if (platform->driver->compr_ops && platform->driver->compr_ops->get_params) 240 if (platform->driver->compr_ops && platform->driver->compr_ops->get_params)
190 ret = platform->driver->compr_ops->get_params(cstream, params); 241 ret = platform->driver->compr_ops->get_params(cstream, params);
191 242
243 mutex_unlock(&rtd->pcm_mutex);
192 return ret; 244 return ret;
193} 245}
194 246
@@ -199,9 +251,12 @@ static int soc_compr_get_caps(struct snd_compr_stream *cstream,
199 struct snd_soc_platform *platform = rtd->platform; 251 struct snd_soc_platform *platform = rtd->platform;
200 int ret = 0; 252 int ret = 0;
201 253
254 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
255
202 if (platform->driver->compr_ops && platform->driver->compr_ops->get_caps) 256 if (platform->driver->compr_ops && platform->driver->compr_ops->get_caps)
203 ret = platform->driver->compr_ops->get_caps(cstream, caps); 257 ret = platform->driver->compr_ops->get_caps(cstream, caps);
204 258
259 mutex_unlock(&rtd->pcm_mutex);
205 return ret; 260 return ret;
206} 261}
207 262
@@ -212,9 +267,12 @@ static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream,
212 struct snd_soc_platform *platform = rtd->platform; 267 struct snd_soc_platform *platform = rtd->platform;
213 int ret = 0; 268 int ret = 0;
214 269
270 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
271
215 if (platform->driver->compr_ops && platform->driver->compr_ops->get_codec_caps) 272 if (platform->driver->compr_ops && platform->driver->compr_ops->get_codec_caps)
216 ret = platform->driver->compr_ops->get_codec_caps(cstream, codec); 273 ret = platform->driver->compr_ops->get_codec_caps(cstream, codec);
217 274
275 mutex_unlock(&rtd->pcm_mutex);
218 return ret; 276 return ret;
219} 277}
220 278
@@ -224,9 +282,12 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
224 struct snd_soc_platform *platform = rtd->platform; 282 struct snd_soc_platform *platform = rtd->platform;
225 int ret = 0; 283 int ret = 0;
226 284
285 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
286
227 if (platform->driver->compr_ops && platform->driver->compr_ops->ack) 287 if (platform->driver->compr_ops && platform->driver->compr_ops->ack)
228 ret = platform->driver->compr_ops->ack(cstream, bytes); 288 ret = platform->driver->compr_ops->ack(cstream, bytes);
229 289
290 mutex_unlock(&rtd->pcm_mutex);
230 return ret; 291 return ret;
231} 292}
232 293
@@ -236,12 +297,31 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream,
236 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 297 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
237 struct snd_soc_platform *platform = rtd->platform; 298 struct snd_soc_platform *platform = rtd->platform;
238 299
300 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
301
239 if (platform->driver->compr_ops && platform->driver->compr_ops->pointer) 302 if (platform->driver->compr_ops && platform->driver->compr_ops->pointer)
240 platform->driver->compr_ops->pointer(cstream, tstamp); 303 platform->driver->compr_ops->pointer(cstream, tstamp);
241 304
305 mutex_unlock(&rtd->pcm_mutex);
242 return 0; 306 return 0;
243} 307}
244 308
309static int soc_compr_copy(struct snd_compr_stream *cstream,
310 const char __user *buf, size_t count)
311{
312 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
313 struct snd_soc_platform *platform = rtd->platform;
314 int ret = 0;
315
316 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
317
318 if (platform->driver->compr_ops && platform->driver->compr_ops->copy)
319 ret = platform->driver->compr_ops->copy(cstream, buf, count);
320
321 mutex_unlock(&rtd->pcm_mutex);
322 return ret;
323}
324
245/* ASoC Compress operations */ 325/* ASoC Compress operations */
246static struct snd_compr_ops soc_compr_ops = { 326static struct snd_compr_ops soc_compr_ops = {
247 .open = soc_compr_open, 327 .open = soc_compr_open,
@@ -259,6 +339,7 @@ static struct snd_compr_ops soc_compr_ops = {
259int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) 339int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
260{ 340{
261 struct snd_soc_codec *codec = rtd->codec; 341 struct snd_soc_codec *codec = rtd->codec;
342 struct snd_soc_platform *platform = rtd->platform;
262 struct snd_soc_dai *codec_dai = rtd->codec_dai; 343 struct snd_soc_dai *codec_dai = rtd->codec_dai;
263 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 344 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
264 struct snd_compr *compr; 345 struct snd_compr *compr;
@@ -275,20 +356,38 @@ int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
275 return -ENOMEM; 356 return -ENOMEM;
276 } 357 }
277 358
278 compr->ops = &soc_compr_ops; 359 compr->ops = devm_kzalloc(rtd->card->dev, sizeof(soc_compr_ops),
360 GFP_KERNEL);
361 if (compr->ops == NULL) {
362 dev_err(rtd->card->dev, "Cannot allocate compressed ops\n");
363 ret = -ENOMEM;
364 goto compr_err;
365 }
366 memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));
367
368 /* Add copy callback for not memory mapped DSPs */
369 if (platform->driver->compr_ops && platform->driver->compr_ops->copy)
370 compr->ops->copy = soc_compr_copy;
371
279 mutex_init(&compr->lock); 372 mutex_init(&compr->lock);
280 ret = snd_compress_new(rtd->card->snd_card, num, direction, compr); 373 ret = snd_compress_new(rtd->card->snd_card, num, direction, compr);
281 if (ret < 0) { 374 if (ret < 0) {
282 pr_err("compress asoc: can't create compress for codec %s\n", 375 pr_err("compress asoc: can't create compress for codec %s\n",
283 codec->name); 376 codec->name);
284 kfree(compr); 377 goto compr_err;
285 return ret;
286 } 378 }
287 379
380 /* DAPM dai link stream work */
381 INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
382
288 rtd->compr = compr; 383 rtd->compr = compr;
289 compr->private_data = rtd; 384 compr->private_data = rtd;
290 385
291 printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name, 386 printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name,
292 cpu_dai->name); 387 cpu_dai->name);
293 return ret; 388 return ret;
389
390compr_err:
391 kfree(compr);
392 return ret;
294} 393}