• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <sound/soc-dpcm.h>
28 
soc_compr_open(struct snd_compr_stream * cstream)29 static 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 	int ret = 0;
34 
35 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
36 
37 	if (platform->driver->compr_ops && platform->driver->compr_ops->open) {
38 		ret = platform->driver->compr_ops->open(cstream);
39 		if (ret < 0) {
40 			pr_err("compress asoc: can't open platform %s\n",
41 				platform->component.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 	snd_soc_runtime_activate(rtd, cstream->direction);
55 
56 	mutex_unlock(&rtd->pcm_mutex);
57 
58 	return 0;
59 
60 machine_err:
61 	if (platform->driver->compr_ops && platform->driver->compr_ops->free)
62 		platform->driver->compr_ops->free(cstream);
63 out:
64 	mutex_unlock(&rtd->pcm_mutex);
65 	return ret;
66 }
67 
soc_compr_open_fe(struct snd_compr_stream * cstream)68 static int soc_compr_open_fe(struct snd_compr_stream *cstream)
69 {
70 	struct snd_soc_pcm_runtime *fe = cstream->private_data;
71 	struct snd_pcm_substream *fe_substream =
72 		 fe->pcm->streams[cstream->direction].substream;
73 	struct snd_soc_platform *platform = fe->platform;
74 	struct snd_soc_dpcm *dpcm;
75 	struct snd_soc_dapm_widget_list *list;
76 	int stream;
77 	int ret = 0;
78 
79 	if (cstream->direction == SND_COMPRESS_PLAYBACK)
80 		stream = SNDRV_PCM_STREAM_PLAYBACK;
81 	else
82 		stream = SNDRV_PCM_STREAM_CAPTURE;
83 
84 	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
85 
86 	if (platform->driver->compr_ops && platform->driver->compr_ops->open) {
87 		ret = platform->driver->compr_ops->open(cstream);
88 		if (ret < 0) {
89 			pr_err("compress asoc: can't open platform %s\n",
90 				platform->component.name);
91 			goto out;
92 		}
93 	}
94 
95 	if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->startup) {
96 		ret = fe->dai_link->compr_ops->startup(cstream);
97 		if (ret < 0) {
98 			pr_err("compress asoc: %s startup failed\n", fe->dai_link->name);
99 			goto machine_err;
100 		}
101 	}
102 
103 	fe->dpcm[stream].runtime = fe_substream->runtime;
104 
105 	ret = dpcm_path_get(fe, stream, &list);
106 	if (ret < 0)
107 		goto fe_err;
108 	else if (ret == 0)
109 		dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
110 			fe->dai_link->name, stream ? "capture" : "playback");
111 
112 	/* calculate valid and active FE <-> BE dpcms */
113 	dpcm_process_paths(fe, stream, &list, 1);
114 
115 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
116 
117 	ret = dpcm_be_dai_startup(fe, stream);
118 	if (ret < 0) {
119 		/* clean up all links */
120 		list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
121 			dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
122 
123 		dpcm_be_disconnect(fe, stream);
124 		fe->dpcm[stream].runtime = NULL;
125 		goto path_err;
126 	}
127 
128 	dpcm_clear_pending_state(fe, stream);
129 	dpcm_path_put(&list);
130 
131 	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
132 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
133 
134 	snd_soc_runtime_activate(fe, stream);
135 
136 	mutex_unlock(&fe->card->mutex);
137 
138 	return 0;
139 
140 path_err:
141 	dpcm_path_put(&list);
142 fe_err:
143 	if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
144 		fe->dai_link->compr_ops->shutdown(cstream);
145 machine_err:
146 	if (platform->driver->compr_ops && platform->driver->compr_ops->free)
147 		platform->driver->compr_ops->free(cstream);
148 out:
149 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
150 	mutex_unlock(&fe->card->mutex);
151 	return ret;
152 }
153 
154 /*
155  * Power down the audio subsystem pmdown_time msecs after close is called.
156  * This is to ensure there are no pops or clicks in between any music tracks
157  * due to DAPM power cycling.
158  */
close_delayed_work(struct work_struct * work)159 static void close_delayed_work(struct work_struct *work)
160 {
161 	struct snd_soc_pcm_runtime *rtd =
162 			container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
163 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
164 
165 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
166 
167 	dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n",
168 		 codec_dai->driver->playback.stream_name,
169 		 codec_dai->playback_active ? "active" : "inactive",
170 		 rtd->pop_wait ? "yes" : "no");
171 
172 	/* are we waiting on this codec DAI stream */
173 	if (rtd->pop_wait == 1) {
174 		rtd->pop_wait = 0;
175 		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
176 					  SND_SOC_DAPM_STREAM_STOP);
177 	}
178 
179 	mutex_unlock(&rtd->pcm_mutex);
180 }
181 
soc_compr_free(struct snd_compr_stream * cstream)182 static int soc_compr_free(struct snd_compr_stream *cstream)
183 {
184 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
185 	struct snd_soc_platform *platform = rtd->platform;
186 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
187 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
188 	int stream;
189 
190 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
191 
192 	if (cstream->direction == SND_COMPRESS_PLAYBACK)
193 		stream = SNDRV_PCM_STREAM_PLAYBACK;
194 	else
195 		stream = SNDRV_PCM_STREAM_CAPTURE;
196 
197 	snd_soc_runtime_deactivate(rtd, stream);
198 
199 	snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
200 
201 	if (!cpu_dai->active)
202 		cpu_dai->rate = 0;
203 
204 	if (!codec_dai->active)
205 		codec_dai->rate = 0;
206 
207 
208 	if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown)
209 		rtd->dai_link->compr_ops->shutdown(cstream);
210 
211 	if (platform->driver->compr_ops && platform->driver->compr_ops->free)
212 		platform->driver->compr_ops->free(cstream);
213 
214 	if (cstream->direction == SND_COMPRESS_PLAYBACK) {
215 		if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
216 			snd_soc_dapm_stream_event(rtd,
217 					SNDRV_PCM_STREAM_PLAYBACK,
218 					SND_SOC_DAPM_STREAM_STOP);
219 		} else {
220 			rtd->pop_wait = 1;
221 			queue_delayed_work(system_power_efficient_wq,
222 					   &rtd->delayed_work,
223 					   msecs_to_jiffies(rtd->pmdown_time));
224 		}
225 	} else {
226 		/* capture streams can be powered down now */
227 		snd_soc_dapm_stream_event(rtd,
228 			SNDRV_PCM_STREAM_CAPTURE,
229 			SND_SOC_DAPM_STREAM_STOP);
230 	}
231 
232 	mutex_unlock(&rtd->pcm_mutex);
233 	return 0;
234 }
235 
soc_compr_free_fe(struct snd_compr_stream * cstream)236 static int soc_compr_free_fe(struct snd_compr_stream *cstream)
237 {
238 	struct snd_soc_pcm_runtime *fe = cstream->private_data;
239 	struct snd_soc_platform *platform = fe->platform;
240 	struct snd_soc_dpcm *dpcm;
241 	int stream, ret;
242 
243 	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
244 
245 	if (cstream->direction == SND_COMPRESS_PLAYBACK)
246 		stream = SNDRV_PCM_STREAM_PLAYBACK;
247 	else
248 		stream = SNDRV_PCM_STREAM_CAPTURE;
249 
250 	snd_soc_runtime_deactivate(fe, stream);
251 
252 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
253 
254 	ret = dpcm_be_dai_hw_free(fe, stream);
255 	if (ret < 0)
256 		dev_err(fe->dev, "compressed hw_free failed %d\n", ret);
257 
258 	ret = dpcm_be_dai_shutdown(fe, stream);
259 
260 	/* mark FE's links ready to prune */
261 	list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
262 		dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
263 
264 	dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
265 
266 	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
267 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
268 
269 	dpcm_be_disconnect(fe, stream);
270 
271 	fe->dpcm[stream].runtime = NULL;
272 
273 	if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
274 		fe->dai_link->compr_ops->shutdown(cstream);
275 
276 	if (platform->driver->compr_ops && platform->driver->compr_ops->free)
277 		platform->driver->compr_ops->free(cstream);
278 
279 	mutex_unlock(&fe->card->mutex);
280 	return 0;
281 }
282 
soc_compr_trigger(struct snd_compr_stream * cstream,int cmd)283 static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
284 {
285 
286 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
287 	struct snd_soc_platform *platform = rtd->platform;
288 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
289 	int ret = 0;
290 
291 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
292 
293 	if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
294 		ret = platform->driver->compr_ops->trigger(cstream, cmd);
295 		if (ret < 0)
296 			goto out;
297 	}
298 
299 	switch (cmd) {
300 	case SNDRV_PCM_TRIGGER_START:
301 		snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction);
302 		break;
303 	case SNDRV_PCM_TRIGGER_STOP:
304 		snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
305 		break;
306 	}
307 
308 out:
309 	mutex_unlock(&rtd->pcm_mutex);
310 	return ret;
311 }
312 
soc_compr_trigger_fe(struct snd_compr_stream * cstream,int cmd)313 static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
314 {
315 	struct snd_soc_pcm_runtime *fe = cstream->private_data;
316 	struct snd_soc_platform *platform = fe->platform;
317 	int ret = 0, stream;
318 
319 	if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN ||
320 		cmd == SND_COMPR_TRIGGER_DRAIN) {
321 
322 		if (platform->driver->compr_ops &&
323 		    platform->driver->compr_ops->trigger)
324 			return platform->driver->compr_ops->trigger(cstream,
325 								    cmd);
326 	}
327 
328 	if (cstream->direction == SND_COMPRESS_PLAYBACK)
329 		stream = SNDRV_PCM_STREAM_PLAYBACK;
330 	else
331 		stream = SNDRV_PCM_STREAM_CAPTURE;
332 
333 
334 	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
335 
336 	if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
337 		ret = platform->driver->compr_ops->trigger(cstream, cmd);
338 		if (ret < 0)
339 			goto out;
340 	}
341 
342 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
343 
344 	ret = dpcm_be_dai_trigger(fe, stream, cmd);
345 
346 	switch (cmd) {
347 	case SNDRV_PCM_TRIGGER_START:
348 	case SNDRV_PCM_TRIGGER_RESUME:
349 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
350 		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
351 		break;
352 	case SNDRV_PCM_TRIGGER_STOP:
353 	case SNDRV_PCM_TRIGGER_SUSPEND:
354 		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
355 		break;
356 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
357 		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
358 		break;
359 	}
360 
361 out:
362 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
363 	mutex_unlock(&fe->card->mutex);
364 	return ret;
365 }
366 
soc_compr_set_params(struct snd_compr_stream * cstream,struct snd_compr_params * params)367 static int soc_compr_set_params(struct snd_compr_stream *cstream,
368 					struct snd_compr_params *params)
369 {
370 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
371 	struct snd_soc_platform *platform = rtd->platform;
372 	int ret = 0;
373 
374 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
375 
376 	/* first we call set_params for the platform driver
377 	 * this should configure the soc side
378 	 * if the machine has compressed ops then we call that as well
379 	 * expectation is that platform and machine will configure everything
380 	 * for this compress path, like configuring pcm port for codec
381 	 */
382 	if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
383 		ret = platform->driver->compr_ops->set_params(cstream, params);
384 		if (ret < 0)
385 			goto err;
386 	}
387 
388 	if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) {
389 		ret = rtd->dai_link->compr_ops->set_params(cstream);
390 		if (ret < 0)
391 			goto err;
392 	}
393 
394 	if (cstream->direction == SND_COMPRESS_PLAYBACK)
395 		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
396 					SND_SOC_DAPM_STREAM_START);
397 	else
398 		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
399 					SND_SOC_DAPM_STREAM_START);
400 
401 	/* cancel any delayed stream shutdown that is pending */
402 	rtd->pop_wait = 0;
403 	mutex_unlock(&rtd->pcm_mutex);
404 
405 	cancel_delayed_work_sync(&rtd->delayed_work);
406 
407 	return ret;
408 
409 err:
410 	mutex_unlock(&rtd->pcm_mutex);
411 	return ret;
412 }
413 
soc_compr_set_params_fe(struct snd_compr_stream * cstream,struct snd_compr_params * params)414 static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
415 					struct snd_compr_params *params)
416 {
417 	struct snd_soc_pcm_runtime *fe = cstream->private_data;
418 	struct snd_pcm_substream *fe_substream =
419 		 fe->pcm->streams[cstream->direction].substream;
420 	struct snd_soc_platform *platform = fe->platform;
421 	int ret = 0, stream;
422 
423 	if (cstream->direction == SND_COMPRESS_PLAYBACK)
424 		stream = SNDRV_PCM_STREAM_PLAYBACK;
425 	else
426 		stream = SNDRV_PCM_STREAM_CAPTURE;
427 
428 	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
429 
430 	if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
431 		ret = platform->driver->compr_ops->set_params(cstream, params);
432 		if (ret < 0)
433 			goto out;
434 	}
435 
436 	if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) {
437 		ret = fe->dai_link->compr_ops->set_params(cstream);
438 		if (ret < 0)
439 			goto out;
440 	}
441 
442 	/*
443 	 * Create an empty hw_params for the BE as the machine driver must
444 	 * fix this up to match DSP decoder and ASRC configuration.
445 	 * I.e. machine driver fixup for compressed BE is mandatory.
446 	 */
447 	memset(&fe->dpcm[fe_substream->stream].hw_params, 0,
448 		sizeof(struct snd_pcm_hw_params));
449 
450 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
451 
452 	ret = dpcm_be_dai_hw_params(fe, stream);
453 	if (ret < 0)
454 		goto out;
455 
456 	ret = dpcm_be_dai_prepare(fe, stream);
457 	if (ret < 0)
458 		goto out;
459 
460 	dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
461 	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
462 
463 out:
464 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
465 	mutex_unlock(&fe->card->mutex);
466 	return ret;
467 }
468 
soc_compr_get_params(struct snd_compr_stream * cstream,struct snd_codec * params)469 static int soc_compr_get_params(struct snd_compr_stream *cstream,
470 					struct snd_codec *params)
471 {
472 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
473 	struct snd_soc_platform *platform = rtd->platform;
474 	int ret = 0;
475 
476 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
477 
478 	if (platform->driver->compr_ops && platform->driver->compr_ops->get_params)
479 		ret = platform->driver->compr_ops->get_params(cstream, params);
480 
481 	mutex_unlock(&rtd->pcm_mutex);
482 	return ret;
483 }
484 
soc_compr_get_caps(struct snd_compr_stream * cstream,struct snd_compr_caps * caps)485 static int soc_compr_get_caps(struct snd_compr_stream *cstream,
486 				struct snd_compr_caps *caps)
487 {
488 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
489 	struct snd_soc_platform *platform = rtd->platform;
490 	int ret = 0;
491 
492 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
493 
494 	if (platform->driver->compr_ops && platform->driver->compr_ops->get_caps)
495 		ret = platform->driver->compr_ops->get_caps(cstream, caps);
496 
497 	mutex_unlock(&rtd->pcm_mutex);
498 	return ret;
499 }
500 
soc_compr_get_codec_caps(struct snd_compr_stream * cstream,struct snd_compr_codec_caps * codec)501 static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream,
502 				struct snd_compr_codec_caps *codec)
503 {
504 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
505 	struct snd_soc_platform *platform = rtd->platform;
506 	int ret = 0;
507 
508 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
509 
510 	if (platform->driver->compr_ops && platform->driver->compr_ops->get_codec_caps)
511 		ret = platform->driver->compr_ops->get_codec_caps(cstream, codec);
512 
513 	mutex_unlock(&rtd->pcm_mutex);
514 	return ret;
515 }
516 
soc_compr_ack(struct snd_compr_stream * cstream,size_t bytes)517 static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
518 {
519 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
520 	struct snd_soc_platform *platform = rtd->platform;
521 	int ret = 0;
522 
523 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
524 
525 	if (platform->driver->compr_ops && platform->driver->compr_ops->ack)
526 		ret = platform->driver->compr_ops->ack(cstream, bytes);
527 
528 	mutex_unlock(&rtd->pcm_mutex);
529 	return ret;
530 }
531 
soc_compr_pointer(struct snd_compr_stream * cstream,struct snd_compr_tstamp * tstamp)532 static int soc_compr_pointer(struct snd_compr_stream *cstream,
533 			struct snd_compr_tstamp *tstamp)
534 {
535 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
536 	struct snd_soc_platform *platform = rtd->platform;
537 	int ret = 0;
538 
539 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
540 
541 	if (platform->driver->compr_ops && platform->driver->compr_ops->pointer)
542 		ret = platform->driver->compr_ops->pointer(cstream, tstamp);
543 
544 	mutex_unlock(&rtd->pcm_mutex);
545 	return ret;
546 }
547 
soc_compr_copy(struct snd_compr_stream * cstream,char __user * buf,size_t count)548 static int soc_compr_copy(struct snd_compr_stream *cstream,
549 			  char __user *buf, size_t count)
550 {
551 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
552 	struct snd_soc_platform *platform = rtd->platform;
553 	int ret = 0;
554 
555 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
556 
557 	if (platform->driver->compr_ops && platform->driver->compr_ops->copy)
558 		ret = platform->driver->compr_ops->copy(cstream, buf, count);
559 
560 	mutex_unlock(&rtd->pcm_mutex);
561 	return ret;
562 }
563 
soc_compr_set_metadata(struct snd_compr_stream * cstream,struct snd_compr_metadata * metadata)564 static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
565 				struct snd_compr_metadata *metadata)
566 {
567 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
568 	struct snd_soc_platform *platform = rtd->platform;
569 	int ret = 0;
570 
571 	if (platform->driver->compr_ops && platform->driver->compr_ops->set_metadata)
572 		ret = platform->driver->compr_ops->set_metadata(cstream, metadata);
573 
574 	return ret;
575 }
576 
soc_compr_get_metadata(struct snd_compr_stream * cstream,struct snd_compr_metadata * metadata)577 static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
578 				struct snd_compr_metadata *metadata)
579 {
580 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
581 	struct snd_soc_platform *platform = rtd->platform;
582 	int ret = 0;
583 
584 	if (platform->driver->compr_ops && platform->driver->compr_ops->get_metadata)
585 		ret = platform->driver->compr_ops->get_metadata(cstream, metadata);
586 
587 	return ret;
588 }
589 
590 /* ASoC Compress operations */
591 static struct snd_compr_ops soc_compr_ops = {
592 	.open		= soc_compr_open,
593 	.free		= soc_compr_free,
594 	.set_params	= soc_compr_set_params,
595 	.set_metadata   = soc_compr_set_metadata,
596 	.get_metadata	= soc_compr_get_metadata,
597 	.get_params	= soc_compr_get_params,
598 	.trigger	= soc_compr_trigger,
599 	.pointer	= soc_compr_pointer,
600 	.ack		= soc_compr_ack,
601 	.get_caps	= soc_compr_get_caps,
602 	.get_codec_caps = soc_compr_get_codec_caps
603 };
604 
605 /* ASoC Dynamic Compress operations */
606 static struct snd_compr_ops soc_compr_dyn_ops = {
607 	.open		= soc_compr_open_fe,
608 	.free		= soc_compr_free_fe,
609 	.set_params	= soc_compr_set_params_fe,
610 	.get_params	= soc_compr_get_params,
611 	.set_metadata   = soc_compr_set_metadata,
612 	.get_metadata	= soc_compr_get_metadata,
613 	.trigger	= soc_compr_trigger_fe,
614 	.pointer	= soc_compr_pointer,
615 	.ack		= soc_compr_ack,
616 	.get_caps	= soc_compr_get_caps,
617 	.get_codec_caps = soc_compr_get_codec_caps
618 };
619 
620 /**
621  * snd_soc_new_compress - create a new compress.
622  *
623  * @rtd: The runtime for which we will create compress
624  * @num: the device index number (zero based - shared with normal PCMs)
625  *
626  * Return: 0 for success, else error.
627  */
snd_soc_new_compress(struct snd_soc_pcm_runtime * rtd,int num)628 int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
629 {
630 	struct snd_soc_codec *codec = rtd->codec;
631 	struct snd_soc_platform *platform = rtd->platform;
632 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
633 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
634 	struct snd_compr *compr;
635 	struct snd_pcm *be_pcm;
636 	char new_name[64];
637 	int ret = 0, direction = 0;
638 	int playback = 0, capture = 0;
639 
640 	if (rtd->num_codecs > 1) {
641 		dev_err(rtd->card->dev, "Multicodec not supported for compressed stream\n");
642 		return -EINVAL;
643 	}
644 
645 	/* check client and interface hw capabilities */
646 	snprintf(new_name, sizeof(new_name), "%s %s-%d",
647 			rtd->dai_link->stream_name, codec_dai->name, num);
648 
649 	if (codec_dai->driver->playback.channels_min)
650 		playback = 1;
651 	if (codec_dai->driver->capture.channels_min)
652 		capture = 1;
653 
654 	capture = capture && cpu_dai->driver->capture.channels_min;
655 	playback = playback && cpu_dai->driver->playback.channels_min;
656 
657 	/*
658 	 * Compress devices are unidirectional so only one of the directions
659 	 * should be set, check for that (xor)
660 	 */
661 	if (playback + capture != 1) {
662 		dev_err(rtd->card->dev, "Invalid direction for compress P %d, C %d\n",
663 				playback, capture);
664 		return -EINVAL;
665 	}
666 
667 	if(playback)
668 		direction = SND_COMPRESS_PLAYBACK;
669 	else
670 		direction = SND_COMPRESS_CAPTURE;
671 
672 	compr = kzalloc(sizeof(*compr), GFP_KERNEL);
673 	if (compr == NULL) {
674 		snd_printk(KERN_ERR "Cannot allocate compr\n");
675 		return -ENOMEM;
676 	}
677 
678 	compr->ops = devm_kzalloc(rtd->card->dev, sizeof(soc_compr_ops),
679 				  GFP_KERNEL);
680 	if (compr->ops == NULL) {
681 		dev_err(rtd->card->dev, "Cannot allocate compressed ops\n");
682 		ret = -ENOMEM;
683 		goto compr_err;
684 	}
685 
686 	if (rtd->dai_link->dynamic) {
687 		snprintf(new_name, sizeof(new_name), "(%s)",
688 			rtd->dai_link->stream_name);
689 
690 		ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
691 				rtd->dai_link->dpcm_playback,
692 				rtd->dai_link->dpcm_capture, &be_pcm);
693 		if (ret < 0) {
694 			dev_err(rtd->card->dev, "ASoC: can't create compressed for %s\n",
695 				rtd->dai_link->name);
696 			goto compr_err;
697 		}
698 
699 		rtd->pcm = be_pcm;
700 		rtd->fe_compr = 1;
701 		if (rtd->dai_link->dpcm_playback)
702 			be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
703 		else if (rtd->dai_link->dpcm_capture)
704 			be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
705 		memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops));
706 	} else
707 		memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));
708 
709 	/* Add copy callback for not memory mapped DSPs */
710 	if (platform->driver->compr_ops && platform->driver->compr_ops->copy)
711 		compr->ops->copy = soc_compr_copy;
712 
713 	mutex_init(&compr->lock);
714 
715 	snprintf(new_name, sizeof(new_name), "%s %s-%d",
716 		 rtd->dai_link->stream_name,
717 		 rtd->codec_dai->name, num);
718 
719 	ret = snd_compress_new(rtd->card->snd_card, num, direction,
720 				new_name, compr);
721 	if (ret < 0) {
722 		pr_err("compress asoc: can't create compress for codec %s\n",
723 			codec->component.name);
724 		goto compr_err;
725 	}
726 
727 	/* DAPM dai link stream work */
728 	INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
729 
730 	rtd->compr = compr;
731 	compr->private_data = rtd;
732 
733 	printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name,
734 		cpu_dai->name);
735 	return ret;
736 
737 compr_err:
738 	kfree(compr);
739 	return ret;
740 }
741 EXPORT_SYMBOL_GPL(snd_soc_new_compress);
742