Linux Audio

Check our new training course

In-person Linux kernel drivers training

Jun 16-20, 2025
Register
Loading...
v5.4
  1// SPDX-License-Identifier: GPL-2.0+
  2//
  3// soc-compress.c  --  ALSA SoC Compress
  4//
  5// Copyright (C) 2012 Intel Corp.
  6//
  7// Authors: Namarta Kohli <namartax.kohli@intel.com>
  8//          Ramesh Babu K V <ramesh.babu@linux.intel.com>
  9//          Vinod Koul <vinod.koul@linux.intel.com>
 
 
 
 
 
 
 10
 11#include <linux/kernel.h>
 12#include <linux/init.h>
 13#include <linux/delay.h>
 14#include <linux/slab.h>
 15#include <linux/workqueue.h>
 16#include <sound/core.h>
 17#include <sound/compress_params.h>
 18#include <sound/compress_driver.h>
 19#include <sound/soc.h>
 20#include <sound/initval.h>
 21#include <sound/soc-dpcm.h>
 22
 23static int soc_compr_components_open(struct snd_compr_stream *cstream,
 24				     struct snd_soc_component **last)
 25{
 26	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 27	struct snd_soc_component *component;
 28	struct snd_soc_rtdcom_list *rtdcom;
 29	int ret;
 30
 31	for_each_rtdcom(rtd, rtdcom) {
 32		component = rtdcom->component;
 33
 34		if (!component->driver->compr_ops ||
 35		    !component->driver->compr_ops->open)
 36			continue;
 37
 38		ret = component->driver->compr_ops->open(cstream);
 39		if (ret < 0) {
 40			dev_err(component->dev,
 41				"Compress ASoC: can't open platform %s: %d\n",
 42				component->name, ret);
 43
 44			*last = component;
 45			return ret;
 46		}
 47	}
 48
 49	*last = NULL;
 50	return 0;
 51}
 52
 53static int soc_compr_components_free(struct snd_compr_stream *cstream,
 54				     struct snd_soc_component *last)
 55{
 56	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 57	struct snd_soc_component *component;
 58	struct snd_soc_rtdcom_list *rtdcom;
 59
 60	for_each_rtdcom(rtd, rtdcom) {
 61		component = rtdcom->component;
 62
 63		if (component == last)
 64			break;
 65
 66		if (!component->driver->compr_ops ||
 67		    !component->driver->compr_ops->free)
 68			continue;
 69
 70		component->driver->compr_ops->free(cstream);
 71	}
 72
 73	return 0;
 74}
 75
 76static int soc_compr_open(struct snd_compr_stream *cstream)
 77{
 78	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 79	struct snd_soc_component *component;
 80	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 81	int ret;
 82
 83	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
 84
 85	if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) {
 86		ret = cpu_dai->driver->cops->startup(cstream, cpu_dai);
 87		if (ret < 0) {
 88			dev_err(cpu_dai->dev,
 89				"Compress ASoC: can't open interface %s: %d\n",
 90				cpu_dai->name, ret);
 91			goto out;
 92		}
 93	}
 94
 95	ret = soc_compr_components_open(cstream, &component);
 96	if (ret < 0)
 97		goto machine_err;
 98
 99	if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->startup) {
100		ret = rtd->dai_link->compr_ops->startup(cstream);
101		if (ret < 0) {
102			dev_err(rtd->dev,
103				"Compress ASoC: %s startup failed: %d\n",
104				rtd->dai_link->name, ret);
105			goto machine_err;
106		}
107	}
108
109	snd_soc_runtime_activate(rtd, cstream->direction);
110
111	mutex_unlock(&rtd->card->pcm_mutex);
112
113	return 0;
114
115machine_err:
116	soc_compr_components_free(cstream, component);
117
118	if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
119		cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
120out:
121	mutex_unlock(&rtd->card->pcm_mutex);
122	return ret;
123}
124
125static int soc_compr_open_fe(struct snd_compr_stream *cstream)
126{
127	struct snd_soc_pcm_runtime *fe = cstream->private_data;
128	struct snd_pcm_substream *fe_substream =
129		 fe->pcm->streams[cstream->direction].substream;
130	struct snd_soc_component *component;
131	struct snd_soc_dai *cpu_dai = fe->cpu_dai;
132	struct snd_soc_dpcm *dpcm;
133	struct snd_soc_dapm_widget_list *list;
134	int stream;
135	int ret;
136
137	if (cstream->direction == SND_COMPRESS_PLAYBACK)
138		stream = SNDRV_PCM_STREAM_PLAYBACK;
139	else
140		stream = SNDRV_PCM_STREAM_CAPTURE;
141
142	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143	fe->dpcm[stream].runtime = fe_substream->runtime;
144
145	ret = dpcm_path_get(fe, stream, &list);
146	if (ret < 0)
147		goto be_err;
148	else if (ret == 0)
149		dev_dbg(fe->dev, "Compress ASoC: %s no valid %s route\n",
150			fe->dai_link->name, stream ? "capture" : "playback");
 
 
151	/* calculate valid and active FE <-> BE dpcms */
152	dpcm_process_paths(fe, stream, &list, 1);
153	fe->dpcm[stream].runtime = fe_substream->runtime;
154
155	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
156
157	ret = dpcm_be_dai_startup(fe, stream);
158	if (ret < 0) {
159		/* clean up all links */
160		for_each_dpcm_be(fe, stream, dpcm)
161			dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
162
163		dpcm_be_disconnect(fe, stream);
164		fe->dpcm[stream].runtime = NULL;
165		goto out;
166	}
167
168	if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) {
169		ret = cpu_dai->driver->cops->startup(cstream, cpu_dai);
170		if (ret < 0) {
171			dev_err(cpu_dai->dev,
172				"Compress ASoC: can't open interface %s: %d\n",
173				cpu_dai->name, ret);
174			goto out;
175		}
176	}
177
178	ret = soc_compr_components_open(cstream, &component);
179	if (ret < 0)
180		goto open_err;
181
182	if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->startup) {
183		ret = fe->dai_link->compr_ops->startup(cstream);
184		if (ret < 0) {
185			pr_err("Compress ASoC: %s startup failed: %d\n",
186			       fe->dai_link->name, ret);
187			goto machine_err;
188		}
189	}
190
191	dpcm_clear_pending_state(fe, stream);
192	dpcm_path_put(&list);
193
194	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
195	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
196
197	snd_soc_runtime_activate(fe, stream);
198
199	mutex_unlock(&fe->card->mutex);
200
201	return 0;
202
 
 
 
203machine_err:
204	soc_compr_components_free(cstream, component);
205open_err:
206	if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
207		cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
208out:
209	dpcm_path_put(&list);
210be_err:
211	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
212	mutex_unlock(&fe->card->mutex);
213	return ret;
214}
215
216/*
217 * Power down the audio subsystem pmdown_time msecs after close is called.
218 * This is to ensure there are no pops or clicks in between any music tracks
219 * due to DAPM power cycling.
220 */
221static void close_delayed_work(struct work_struct *work)
222{
223	struct snd_soc_pcm_runtime *rtd =
224			container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
225	struct snd_soc_dai *codec_dai = rtd->codec_dai;
226
227	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
228
229	dev_dbg(rtd->dev,
230		"Compress ASoC: pop wq checking: %s status: %s waiting: %s\n",
231		codec_dai->driver->playback.stream_name,
232		codec_dai->playback_active ? "active" : "inactive",
233		rtd->pop_wait ? "yes" : "no");
234
235	/* are we waiting on this codec DAI stream */
236	if (rtd->pop_wait == 1) {
237		rtd->pop_wait = 0;
238		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
239					  SND_SOC_DAPM_STREAM_STOP);
240	}
241
242	mutex_unlock(&rtd->card->pcm_mutex);
243}
244
245static int soc_compr_free(struct snd_compr_stream *cstream)
246{
247	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 
248	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
249	struct snd_soc_dai *codec_dai = rtd->codec_dai;
250	int stream;
251
252	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
253
254	if (cstream->direction == SND_COMPRESS_PLAYBACK)
255		stream = SNDRV_PCM_STREAM_PLAYBACK;
256	else
257		stream = SNDRV_PCM_STREAM_CAPTURE;
258
259	snd_soc_runtime_deactivate(rtd, stream);
260
261	snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
262
263	if (!cpu_dai->active)
264		cpu_dai->rate = 0;
265
266	if (!codec_dai->active)
267		codec_dai->rate = 0;
268
 
269	if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown)
270		rtd->dai_link->compr_ops->shutdown(cstream);
271
272	soc_compr_components_free(cstream, NULL);
273
274	if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
275		cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
276
277	if (cstream->direction == SND_COMPRESS_PLAYBACK) {
278		if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
279			snd_soc_dapm_stream_event(rtd,
280						  SNDRV_PCM_STREAM_PLAYBACK,
281						  SND_SOC_DAPM_STREAM_STOP);
282		} else {
283			rtd->pop_wait = 1;
284			queue_delayed_work(system_power_efficient_wq,
285					   &rtd->delayed_work,
286					   msecs_to_jiffies(rtd->pmdown_time));
287		}
288	} else {
289		/* capture streams can be powered down now */
290		snd_soc_dapm_stream_event(rtd,
291					  SNDRV_PCM_STREAM_CAPTURE,
292					  SND_SOC_DAPM_STREAM_STOP);
293	}
294
295	mutex_unlock(&rtd->card->pcm_mutex);
296	return 0;
297}
298
299static int soc_compr_free_fe(struct snd_compr_stream *cstream)
300{
301	struct snd_soc_pcm_runtime *fe = cstream->private_data;
302	struct snd_soc_dai *cpu_dai = fe->cpu_dai;
303	struct snd_soc_dpcm *dpcm;
304	int stream, ret;
305
306	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
307
308	if (cstream->direction == SND_COMPRESS_PLAYBACK)
309		stream = SNDRV_PCM_STREAM_PLAYBACK;
310	else
311		stream = SNDRV_PCM_STREAM_CAPTURE;
312
313	snd_soc_runtime_deactivate(fe, stream);
314
315	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
316
317	ret = dpcm_be_dai_hw_free(fe, stream);
318	if (ret < 0)
319		dev_err(fe->dev, "Compressed ASoC: hw_free failed: %d\n", ret);
320
321	ret = dpcm_be_dai_shutdown(fe, stream);
322
323	/* mark FE's links ready to prune */
324	for_each_dpcm_be(fe, stream, dpcm)
325		dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
326
327	dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
 
 
 
328
329	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
330	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
331
332	dpcm_be_disconnect(fe, stream);
333
334	fe->dpcm[stream].runtime = NULL;
335
336	if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
337		fe->dai_link->compr_ops->shutdown(cstream);
338
339	soc_compr_components_free(cstream, NULL);
340
341	if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
342		cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
343
344	mutex_unlock(&fe->card->mutex);
345	return 0;
346}
347
348static int soc_compr_components_trigger(struct snd_compr_stream *cstream,
349					int cmd)
350{
351	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
352	struct snd_soc_component *component;
353	struct snd_soc_rtdcom_list *rtdcom;
354	int ret;
355
356	for_each_rtdcom(rtd, rtdcom) {
357		component = rtdcom->component;
358
359		if (!component->driver->compr_ops ||
360		    !component->driver->compr_ops->trigger)
361			continue;
362
363		ret = component->driver->compr_ops->trigger(cstream, cmd);
364		if (ret < 0)
365			return ret;
366	}
367
368	return 0;
369}
370
371static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
372{
 
373	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 
374	struct snd_soc_dai *codec_dai = rtd->codec_dai;
375	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
376	int ret;
377
378	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
379
380	ret = soc_compr_components_trigger(cstream, cmd);
381	if (ret < 0)
382		goto out;
383
384	if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger)
385		cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai);
 
 
 
386
387	switch (cmd) {
388	case SNDRV_PCM_TRIGGER_START:
389		snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction);
390		break;
391	case SNDRV_PCM_TRIGGER_STOP:
392		snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
393		break;
394	}
395
396out:
397	mutex_unlock(&rtd->card->pcm_mutex);
398	return ret;
399}
400
401static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
402{
403	struct snd_soc_pcm_runtime *fe = cstream->private_data;
404	struct snd_soc_dai *cpu_dai = fe->cpu_dai;
405	int ret, stream;
406
407	if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN ||
408	    cmd == SND_COMPR_TRIGGER_DRAIN)
409		return soc_compr_components_trigger(cstream, cmd);
 
 
 
 
410
411	if (cstream->direction == SND_COMPRESS_PLAYBACK)
412		stream = SNDRV_PCM_STREAM_PLAYBACK;
413	else
414		stream = SNDRV_PCM_STREAM_CAPTURE;
415
 
416	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
417
418	if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) {
419		ret = cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai);
420		if (ret < 0)
421			goto out;
422	}
423
424	ret = soc_compr_components_trigger(cstream, cmd);
425	if (ret < 0)
426		goto out;
427
428	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
429
430	ret = dpcm_be_dai_trigger(fe, stream, cmd);
431
432	switch (cmd) {
433	case SNDRV_PCM_TRIGGER_START:
434	case SNDRV_PCM_TRIGGER_RESUME:
435	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
436		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
437		break;
438	case SNDRV_PCM_TRIGGER_STOP:
439	case SNDRV_PCM_TRIGGER_SUSPEND:
440		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
441		break;
442	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
443		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
444		break;
445	}
446
447out:
448	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
449	mutex_unlock(&fe->card->mutex);
450	return ret;
451}
452
453static int soc_compr_components_set_params(struct snd_compr_stream *cstream,
454					   struct snd_compr_params *params)
455{
456	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
457	struct snd_soc_component *component;
458	struct snd_soc_rtdcom_list *rtdcom;
459	int ret;
460
461	for_each_rtdcom(rtd, rtdcom) {
462		component = rtdcom->component;
463
464		if (!component->driver->compr_ops ||
465		    !component->driver->compr_ops->set_params)
466			continue;
467
468		ret = component->driver->compr_ops->set_params(cstream, params);
469		if (ret < 0)
470			return ret;
471	}
472
473	return 0;
474}
475
476static int soc_compr_set_params(struct snd_compr_stream *cstream,
477				struct snd_compr_params *params)
478{
479	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
480	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
481	int ret;
482
483	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
484
485	/*
486	 * First we call set_params for the CPU DAI, then the component
487	 * driver this should configure the SoC side. If the machine has
488	 * compressed ops then we call that as well. The expectation is
489	 * that these callbacks will configure everything for this compress
490	 * path, like configuring a PCM port for a CODEC.
491	 */
492	if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) {
493		ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai);
494		if (ret < 0)
495			goto err;
496	}
497
498	ret = soc_compr_components_set_params(cstream, params);
499	if (ret < 0)
500		goto err;
501
502	if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) {
503		ret = rtd->dai_link->compr_ops->set_params(cstream);
504		if (ret < 0)
505			goto err;
506	}
507
508	if (cstream->direction == SND_COMPRESS_PLAYBACK)
509		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
510					  SND_SOC_DAPM_STREAM_START);
511	else
512		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
513					  SND_SOC_DAPM_STREAM_START);
514
515	/* cancel any delayed stream shutdown that is pending */
516	rtd->pop_wait = 0;
517	mutex_unlock(&rtd->card->pcm_mutex);
518
519	cancel_delayed_work_sync(&rtd->delayed_work);
520
521	return 0;
522
523err:
524	mutex_unlock(&rtd->card->pcm_mutex);
525	return ret;
526}
527
528static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
529				   struct snd_compr_params *params)
530{
531	struct snd_soc_pcm_runtime *fe = cstream->private_data;
532	struct snd_pcm_substream *fe_substream =
533		 fe->pcm->streams[cstream->direction].substream;
534	struct snd_soc_dai *cpu_dai = fe->cpu_dai;
535	int ret, stream;
536
537	if (cstream->direction == SND_COMPRESS_PLAYBACK)
538		stream = SNDRV_PCM_STREAM_PLAYBACK;
539	else
540		stream = SNDRV_PCM_STREAM_CAPTURE;
541
542	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
543
 
 
 
 
 
 
 
 
 
 
 
 
544	/*
545	 * Create an empty hw_params for the BE as the machine driver must
546	 * fix this up to match DSP decoder and ASRC configuration.
547	 * I.e. machine driver fixup for compressed BE is mandatory.
548	 */
549	memset(&fe->dpcm[fe_substream->stream].hw_params, 0,
550		sizeof(struct snd_pcm_hw_params));
551
552	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
553
554	ret = dpcm_be_dai_hw_params(fe, stream);
555	if (ret < 0)
556		goto out;
557
558	ret = dpcm_be_dai_prepare(fe, stream);
559	if (ret < 0)
560		goto out;
561
562	if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) {
563		ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai);
564		if (ret < 0)
565			goto out;
566	}
567
568	ret = soc_compr_components_set_params(cstream, params);
569	if (ret < 0)
570		goto out;
571
572	if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) {
573		ret = fe->dai_link->compr_ops->set_params(cstream);
574		if (ret < 0)
575			goto out;
576	}
577
578	dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
579	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
580
581out:
582	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
583	mutex_unlock(&fe->card->mutex);
584	return ret;
585}
586
587static int soc_compr_get_params(struct snd_compr_stream *cstream,
588				struct snd_codec *params)
589{
590	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
591	struct snd_soc_component *component;
592	struct snd_soc_rtdcom_list *rtdcom;
593	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
594	int ret = 0;
595
596	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
597
598	if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_params) {
599		ret = cpu_dai->driver->cops->get_params(cstream, params, cpu_dai);
600		if (ret < 0)
601			goto err;
602	}
603
604	for_each_rtdcom(rtd, rtdcom) {
605		component = rtdcom->component;
606
607		if (!component->driver->compr_ops ||
608		    !component->driver->compr_ops->get_params)
609			continue;
610
611		ret = component->driver->compr_ops->get_params(cstream, params);
612		break;
613	}
614
615err:
616	mutex_unlock(&rtd->card->pcm_mutex);
617	return ret;
618}
619
620static int soc_compr_get_caps(struct snd_compr_stream *cstream,
621			      struct snd_compr_caps *caps)
622{
623	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
624	struct snd_soc_component *component;
625	struct snd_soc_rtdcom_list *rtdcom;
626	int ret = 0;
627
628	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
629
630	for_each_rtdcom(rtd, rtdcom) {
631		component = rtdcom->component;
632
633		if (!component->driver->compr_ops ||
634		    !component->driver->compr_ops->get_caps)
635			continue;
636
637		ret = component->driver->compr_ops->get_caps(cstream, caps);
638		break;
639	}
640
641	mutex_unlock(&rtd->card->pcm_mutex);
642	return ret;
643}
644
645static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream,
646				    struct snd_compr_codec_caps *codec)
647{
648	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
649	struct snd_soc_component *component;
650	struct snd_soc_rtdcom_list *rtdcom;
651	int ret = 0;
652
653	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
654
655	for_each_rtdcom(rtd, rtdcom) {
656		component = rtdcom->component;
657
658		if (!component->driver->compr_ops ||
659		    !component->driver->compr_ops->get_codec_caps)
660			continue;
661
662		ret = component->driver->compr_ops->get_codec_caps(cstream,
663								   codec);
664		break;
665	}
666
667	mutex_unlock(&rtd->card->pcm_mutex);
668	return ret;
669}
670
671static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
672{
673	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
674	struct snd_soc_component *component;
675	struct snd_soc_rtdcom_list *rtdcom;
676	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
677	int ret = 0;
678
679	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
680
681	if (cpu_dai->driver->cops && cpu_dai->driver->cops->ack) {
682		ret = cpu_dai->driver->cops->ack(cstream, bytes, cpu_dai);
683		if (ret < 0)
684			goto err;
685	}
686
687	for_each_rtdcom(rtd, rtdcom) {
688		component = rtdcom->component;
689
690		if (!component->driver->compr_ops ||
691		    !component->driver->compr_ops->ack)
692			continue;
693
694		ret = component->driver->compr_ops->ack(cstream, bytes);
695		if (ret < 0)
696			goto err;
697	}
698
699err:
700	mutex_unlock(&rtd->card->pcm_mutex);
701	return ret;
702}
703
704static int soc_compr_pointer(struct snd_compr_stream *cstream,
705			     struct snd_compr_tstamp *tstamp)
706{
707	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
708	struct snd_soc_component *component;
709	struct snd_soc_rtdcom_list *rtdcom;
710	int ret = 0;
711	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
712
713	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
714
715	if (cpu_dai->driver->cops && cpu_dai->driver->cops->pointer)
716		cpu_dai->driver->cops->pointer(cstream, tstamp, cpu_dai);
717
718	for_each_rtdcom(rtd, rtdcom) {
719		component = rtdcom->component;
720
721		if (!component->driver->compr_ops ||
722		    !component->driver->compr_ops->pointer)
723			continue;
724
725		ret = component->driver->compr_ops->pointer(cstream, tstamp);
726		break;
727	}
728
729	mutex_unlock(&rtd->card->pcm_mutex);
730	return ret;
731}
732
733static int soc_compr_copy(struct snd_compr_stream *cstream,
734			  char __user *buf, size_t count)
735{
736	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
737	struct snd_soc_component *component;
738	struct snd_soc_rtdcom_list *rtdcom;
739	int ret = 0;
740
741	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
742
743	for_each_rtdcom(rtd, rtdcom) {
744		component = rtdcom->component;
745
746		if (!component->driver->compr_ops ||
747		    !component->driver->compr_ops->copy)
748			continue;
749
750		ret = component->driver->compr_ops->copy(cstream, buf, count);
751		break;
752	}
753
754	mutex_unlock(&rtd->card->pcm_mutex);
755	return ret;
756}
757
758static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
759				  struct snd_compr_metadata *metadata)
760{
761	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
762	struct snd_soc_component *component;
763	struct snd_soc_rtdcom_list *rtdcom;
764	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
765	int ret;
766
767	if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_metadata) {
768		ret = cpu_dai->driver->cops->set_metadata(cstream, metadata, cpu_dai);
769		if (ret < 0)
770			return ret;
771	}
772
773	for_each_rtdcom(rtd, rtdcom) {
774		component = rtdcom->component;
775
776		if (!component->driver->compr_ops ||
777		    !component->driver->compr_ops->set_metadata)
778			continue;
779
780		ret = component->driver->compr_ops->set_metadata(cstream,
781								 metadata);
782		if (ret < 0)
783			return ret;
784	}
785
786	return 0;
787}
788
789static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
790				  struct snd_compr_metadata *metadata)
791{
792	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
793	struct snd_soc_component *component;
794	struct snd_soc_rtdcom_list *rtdcom;
795	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
796	int ret;
797
798	if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_metadata) {
799		ret = cpu_dai->driver->cops->get_metadata(cstream, metadata, cpu_dai);
800		if (ret < 0)
801			return ret;
802	}
803
804	for_each_rtdcom(rtd, rtdcom) {
805		component = rtdcom->component;
806
807		if (!component->driver->compr_ops ||
808		    !component->driver->compr_ops->get_metadata)
809			continue;
810
811		return component->driver->compr_ops->get_metadata(cstream,
812								  metadata);
813	}
814
815	return 0;
816}
817
818/* ASoC Compress operations */
819static struct snd_compr_ops soc_compr_ops = {
820	.open		= soc_compr_open,
821	.free		= soc_compr_free,
822	.set_params	= soc_compr_set_params,
823	.set_metadata   = soc_compr_set_metadata,
824	.get_metadata	= soc_compr_get_metadata,
825	.get_params	= soc_compr_get_params,
826	.trigger	= soc_compr_trigger,
827	.pointer	= soc_compr_pointer,
828	.ack		= soc_compr_ack,
829	.get_caps	= soc_compr_get_caps,
830	.get_codec_caps = soc_compr_get_codec_caps
831};
832
833/* ASoC Dynamic Compress operations */
834static struct snd_compr_ops soc_compr_dyn_ops = {
835	.open		= soc_compr_open_fe,
836	.free		= soc_compr_free_fe,
837	.set_params	= soc_compr_set_params_fe,
838	.get_params	= soc_compr_get_params,
839	.set_metadata   = soc_compr_set_metadata,
840	.get_metadata	= soc_compr_get_metadata,
841	.trigger	= soc_compr_trigger_fe,
842	.pointer	= soc_compr_pointer,
843	.ack		= soc_compr_ack,
844	.get_caps	= soc_compr_get_caps,
845	.get_codec_caps = soc_compr_get_codec_caps
846};
847
848/**
849 * snd_soc_new_compress - create a new compress.
850 *
851 * @rtd: The runtime for which we will create compress
852 * @num: the device index number (zero based - shared with normal PCMs)
853 *
854 * Return: 0 for success, else error.
855 */
856int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
857{
858	struct snd_soc_component *component;
859	struct snd_soc_rtdcom_list *rtdcom;
860	struct snd_soc_dai *codec_dai = rtd->codec_dai;
861	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
862	struct snd_compr *compr;
863	struct snd_pcm *be_pcm;
864	char new_name[64];
865	int ret = 0, direction = 0;
866	int playback = 0, capture = 0;
867
868	if (rtd->num_codecs > 1) {
869		dev_err(rtd->card->dev,
870			"Compress ASoC: Multicodec not supported\n");
871		return -EINVAL;
872	}
873
874	/* check client and interface hw capabilities */
875	if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
876	    snd_soc_dai_stream_valid(cpu_dai,   SNDRV_PCM_STREAM_PLAYBACK))
877		playback = 1;
878	if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
879	    snd_soc_dai_stream_valid(cpu_dai,   SNDRV_PCM_STREAM_CAPTURE))
880		capture = 1;
881
882	/*
883	 * Compress devices are unidirectional so only one of the directions
884	 * should be set, check for that (xor)
885	 */
886	if (playback + capture != 1) {
887		dev_err(rtd->card->dev,
888			"Compress ASoC: Invalid direction for P %d, C %d\n",
889			playback, capture);
890		return -EINVAL;
891	}
892
893	if (playback)
894		direction = SND_COMPRESS_PLAYBACK;
895	else
896		direction = SND_COMPRESS_CAPTURE;
 
 
897
898	compr = devm_kzalloc(rtd->card->dev, sizeof(*compr), GFP_KERNEL);
899	if (!compr)
 
900		return -ENOMEM;
 
901
902	compr->ops = devm_kzalloc(rtd->card->dev, sizeof(soc_compr_ops),
903				  GFP_KERNEL);
904	if (!compr->ops)
905		return -ENOMEM;
 
 
 
906
907	if (rtd->dai_link->dynamic) {
908		snprintf(new_name, sizeof(new_name), "(%s)",
909			rtd->dai_link->stream_name);
910
911		ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
912				rtd->dai_link->dpcm_playback,
913				rtd->dai_link->dpcm_capture, &be_pcm);
914		if (ret < 0) {
915			dev_err(rtd->card->dev,
916				"Compress ASoC: can't create compressed for %s: %d\n",
917				rtd->dai_link->name, ret);
918			return ret;
919		}
920
921		rtd->pcm = be_pcm;
922		rtd->fe_compr = 1;
923		if (rtd->dai_link->dpcm_playback)
924			be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
925		else if (rtd->dai_link->dpcm_capture)
926			be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
927		memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops));
928	} else {
929		snprintf(new_name, sizeof(new_name), "%s %s-%d",
930			rtd->dai_link->stream_name, codec_dai->name, num);
931
932		memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));
933	}
934
935	for_each_rtdcom(rtd, rtdcom) {
936		component = rtdcom->component;
937
938		if (!component->driver->compr_ops ||
939		    !component->driver->compr_ops->copy)
940			continue;
941
 
 
942		compr->ops->copy = soc_compr_copy;
943		break;
944	}
945
946	mutex_init(&compr->lock);
947	ret = snd_compress_new(rtd->card->snd_card, num, direction,
948				new_name, compr);
949	if (ret < 0) {
950		component = rtd->codec_dai->component;
951		dev_err(component->dev,
952			"Compress ASoC: can't create compress for codec %s: %d\n",
953			component->name, ret);
954		return ret;
955	}
956
957	/* DAPM dai link stream work */
958	INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
959
960	rtd->compr = compr;
961	compr->private_data = rtd;
962
963	dev_info(rtd->card->dev, "Compress ASoC: %s <-> %s mapping ok\n",
964		 codec_dai->name, cpu_dai->name);
 
965
966	return 0;
 
 
967}
968EXPORT_SYMBOL_GPL(snd_soc_new_compress);
v3.15
  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
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 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	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", platform->name);
 
 
 41			goto out;
 42		}
 43	}
 44
 
 
 
 
 45	if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->startup) {
 46		ret = rtd->dai_link->compr_ops->startup(cstream);
 47		if (ret < 0) {
 48			pr_err("compress asoc: %s startup failed\n", rtd->dai_link->name);
 
 
 49			goto machine_err;
 50		}
 51	}
 52
 53	snd_soc_runtime_activate(rtd, cstream->direction);
 54
 55	mutex_unlock(&rtd->pcm_mutex);
 56
 57	return 0;
 58
 59machine_err:
 60	if (platform->driver->compr_ops && platform->driver->compr_ops->free)
 61		platform->driver->compr_ops->free(cstream);
 
 
 62out:
 63	mutex_unlock(&rtd->pcm_mutex);
 64	return ret;
 65}
 66
 67static int soc_compr_open_fe(struct snd_compr_stream *cstream)
 68{
 69	struct snd_soc_pcm_runtime *fe = cstream->private_data;
 70	struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;
 71	struct snd_soc_platform *platform = fe->platform;
 
 
 72	struct snd_soc_dpcm *dpcm;
 73	struct snd_soc_dapm_widget_list *list;
 74	int stream;
 75	int ret = 0;
 76
 77	if (cstream->direction == SND_COMPRESS_PLAYBACK)
 78		stream = SNDRV_PCM_STREAM_PLAYBACK;
 79	else
 80		stream = SNDRV_PCM_STREAM_CAPTURE;
 81
 82	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
 83
 84	if (platform->driver->compr_ops && platform->driver->compr_ops->open) {
 85		ret = platform->driver->compr_ops->open(cstream);
 86		if (ret < 0) {
 87			pr_err("compress asoc: can't open platform %s\n", platform->name);
 88			goto out;
 89		}
 90	}
 91
 92	if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->startup) {
 93		ret = fe->dai_link->compr_ops->startup(cstream);
 94		if (ret < 0) {
 95			pr_err("compress asoc: %s startup failed\n", fe->dai_link->name);
 96			goto machine_err;
 97		}
 98	}
 99
100	fe->dpcm[stream].runtime = fe_substream->runtime;
101
102	if (dpcm_path_get(fe, stream, &list) <= 0) {
103		dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
 
 
 
104			fe->dai_link->name, stream ? "capture" : "playback");
105	}
106
107	/* calculate valid and active FE <-> BE dpcms */
108	dpcm_process_paths(fe, stream, &list, 1);
 
109
110	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
111
112	ret = dpcm_be_dai_startup(fe, stream);
113	if (ret < 0) {
114		/* clean up all links */
115		list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
116			dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
117
118		dpcm_be_disconnect(fe, stream);
119		fe->dpcm[stream].runtime = NULL;
120		goto fe_err;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121	}
122
123	dpcm_clear_pending_state(fe, stream);
124	dpcm_path_put(&list);
125
126	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
127	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
128
129	snd_soc_runtime_activate(fe, stream);
130
131	mutex_unlock(&fe->card->mutex);
132
133	return 0;
134
135fe_err:
136	if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
137		fe->dai_link->compr_ops->shutdown(cstream);
138machine_err:
139	if (platform->driver->compr_ops && platform->driver->compr_ops->free)
140		platform->driver->compr_ops->free(cstream);
 
 
141out:
 
 
142	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
143	mutex_unlock(&fe->card->mutex);
144	return ret;
145}
146
147/*
148 * Power down the audio subsystem pmdown_time msecs after close is called.
149 * This is to ensure there are no pops or clicks in between any music tracks
150 * due to DAPM power cycling.
151 */
152static void close_delayed_work(struct work_struct *work)
153{
154	struct snd_soc_pcm_runtime *rtd =
155			container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
156	struct snd_soc_dai *codec_dai = rtd->codec_dai;
157
158	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
159
160	dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n",
161		 codec_dai->driver->playback.stream_name,
162		 codec_dai->playback_active ? "active" : "inactive",
163		 rtd->pop_wait ? "yes" : "no");
 
164
165	/* are we waiting on this codec DAI stream */
166	if (rtd->pop_wait == 1) {
167		rtd->pop_wait = 0;
168		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
169					  SND_SOC_DAPM_STREAM_STOP);
170	}
171
172	mutex_unlock(&rtd->pcm_mutex);
173}
174
175static int soc_compr_free(struct snd_compr_stream *cstream)
176{
177	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
178	struct snd_soc_platform *platform = rtd->platform;
179	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
180	struct snd_soc_dai *codec_dai = rtd->codec_dai;
181	int stream;
182
183	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
184
185	if (cstream->direction == SND_COMPRESS_PLAYBACK)
186		stream = SNDRV_PCM_STREAM_PLAYBACK;
187	else
188		stream = SNDRV_PCM_STREAM_CAPTURE;
189
190	snd_soc_runtime_deactivate(rtd, stream);
191
192	snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
193
194	if (!cpu_dai->active)
195		cpu_dai->rate = 0;
196
197	if (!codec_dai->active)
198		codec_dai->rate = 0;
199
200
201	if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown)
202		rtd->dai_link->compr_ops->shutdown(cstream);
203
204	if (platform->driver->compr_ops && platform->driver->compr_ops->free)
205		platform->driver->compr_ops->free(cstream);
206	cpu_dai->runtime = NULL;
 
207
208	if (cstream->direction == SND_COMPRESS_PLAYBACK) {
209		if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
210			snd_soc_dapm_stream_event(rtd,
211					SNDRV_PCM_STREAM_PLAYBACK,
212					SND_SOC_DAPM_STREAM_STOP);
213		} else {
214			rtd->pop_wait = 1;
215			queue_delayed_work(system_power_efficient_wq,
216					   &rtd->delayed_work,
217					   msecs_to_jiffies(rtd->pmdown_time));
218		}
219	} else {
220		/* capture streams can be powered down now */
221		snd_soc_dapm_stream_event(rtd,
222			SNDRV_PCM_STREAM_CAPTURE,
223			SND_SOC_DAPM_STREAM_STOP);
224	}
225
226	mutex_unlock(&rtd->pcm_mutex);
227	return 0;
228}
229
230static int soc_compr_free_fe(struct snd_compr_stream *cstream)
231{
232	struct snd_soc_pcm_runtime *fe = cstream->private_data;
233	struct snd_soc_platform *platform = fe->platform;
234	struct snd_soc_dpcm *dpcm;
235	int stream, ret;
236
237	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
238
239	if (cstream->direction == SND_COMPRESS_PLAYBACK)
240		stream = SNDRV_PCM_STREAM_PLAYBACK;
241	else
242		stream = SNDRV_PCM_STREAM_CAPTURE;
243
244	snd_soc_runtime_deactivate(fe, stream);
245
246	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
247
248	ret = dpcm_be_dai_hw_free(fe, stream);
249	if (ret < 0)
250		dev_err(fe->dev, "compressed hw_free failed %d\n", ret);
251
252	ret = dpcm_be_dai_shutdown(fe, stream);
253
254	/* mark FE's links ready to prune */
255	list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
256		dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
257
258	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
259		dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
260	else
261		dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
262
263	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
264	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
265
266	dpcm_be_disconnect(fe, stream);
267
268	fe->dpcm[stream].runtime = NULL;
269
270	if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
271		fe->dai_link->compr_ops->shutdown(cstream);
272
273	if (platform->driver->compr_ops && platform->driver->compr_ops->free)
274		platform->driver->compr_ops->free(cstream);
 
 
275
276	mutex_unlock(&fe->card->mutex);
277	return 0;
278}
279
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
280static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
281{
282
283	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
284	struct snd_soc_platform *platform = rtd->platform;
285	struct snd_soc_dai *codec_dai = rtd->codec_dai;
286	int ret = 0;
 
 
 
287
288	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
 
289
290	if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
291		ret = platform->driver->compr_ops->trigger(cstream, cmd);
292		if (ret < 0)
293			goto out;
294	}
295
296	switch (cmd) {
297	case SNDRV_PCM_TRIGGER_START:
298		snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction);
299		break;
300	case SNDRV_PCM_TRIGGER_STOP:
301		snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
302		break;
303	}
304
305out:
306	mutex_unlock(&rtd->pcm_mutex);
307	return ret;
308}
309
310static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
311{
312	struct snd_soc_pcm_runtime *fe = cstream->private_data;
313	struct snd_soc_platform *platform = fe->platform;
314	int ret = 0, stream;
315
316	if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN ||
317		cmd == SND_COMPR_TRIGGER_DRAIN) {
318
319		if (platform->driver->compr_ops &&
320			platform->driver->compr_ops->trigger)
321		return platform->driver->compr_ops->trigger(cstream, cmd);
322	}
323
324	if (cstream->direction == SND_COMPRESS_PLAYBACK)
325		stream = SNDRV_PCM_STREAM_PLAYBACK;
326	else
327		stream = SNDRV_PCM_STREAM_CAPTURE;
328
329
330	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
331
332	if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
333		ret = platform->driver->compr_ops->trigger(cstream, cmd);
334		if (ret < 0)
335			goto out;
336	}
337
 
 
 
 
338	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
339
340	ret = dpcm_be_dai_trigger(fe, stream, cmd);
341
342	switch (cmd) {
343	case SNDRV_PCM_TRIGGER_START:
344	case SNDRV_PCM_TRIGGER_RESUME:
345	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
346		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
347		break;
348	case SNDRV_PCM_TRIGGER_STOP:
349	case SNDRV_PCM_TRIGGER_SUSPEND:
350		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
351		break;
352	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
353		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
354		break;
355	}
356
357out:
358	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
359	mutex_unlock(&fe->card->mutex);
360	return ret;
361}
362
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
363static int soc_compr_set_params(struct snd_compr_stream *cstream,
364					struct snd_compr_params *params)
365{
366	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
367	struct snd_soc_platform *platform = rtd->platform;
368	int ret = 0;
369
370	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
371
372	/* first we call set_params for the platform driver
373	 * this should configure the soc side
374	 * if the machine has compressed ops then we call that as well
375	 * expectation is that platform and machine will configure everything
376	 * for this compress path, like configuring pcm port for codec
 
377	 */
378	if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
379		ret = platform->driver->compr_ops->set_params(cstream, params);
380		if (ret < 0)
381			goto err;
382	}
383
 
 
 
 
384	if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) {
385		ret = rtd->dai_link->compr_ops->set_params(cstream);
386		if (ret < 0)
387			goto err;
388	}
389
390	if (cstream->direction == SND_COMPRESS_PLAYBACK)
391		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
392					SND_SOC_DAPM_STREAM_START);
393	else
394		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
395					SND_SOC_DAPM_STREAM_START);
396
397	/* cancel any delayed stream shutdown that is pending */
398	rtd->pop_wait = 0;
399	mutex_unlock(&rtd->pcm_mutex);
400
401	cancel_delayed_work_sync(&rtd->delayed_work);
402
403	return ret;
404
405err:
406	mutex_unlock(&rtd->pcm_mutex);
407	return ret;
408}
409
410static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
411					struct snd_compr_params *params)
412{
413	struct snd_soc_pcm_runtime *fe = cstream->private_data;
414	struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;
415	struct snd_soc_platform *platform = fe->platform;
416	int ret = 0, stream;
 
417
418	if (cstream->direction == SND_COMPRESS_PLAYBACK)
419		stream = SNDRV_PCM_STREAM_PLAYBACK;
420	else
421		stream = SNDRV_PCM_STREAM_CAPTURE;
422
423	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
424
425	if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
426		ret = platform->driver->compr_ops->set_params(cstream, params);
427		if (ret < 0)
428			goto out;
429	}
430
431	if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) {
432		ret = fe->dai_link->compr_ops->set_params(cstream);
433		if (ret < 0)
434			goto out;
435	}
436
437	/*
438	 * Create an empty hw_params for the BE as the machine driver must
439	 * fix this up to match DSP decoder and ASRC configuration.
440	 * I.e. machine driver fixup for compressed BE is mandatory.
441	 */
442	memset(&fe->dpcm[fe_substream->stream].hw_params, 0,
443		sizeof(struct snd_pcm_hw_params));
444
445	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
446
447	ret = dpcm_be_dai_hw_params(fe, stream);
448	if (ret < 0)
449		goto out;
450
451	ret = dpcm_be_dai_prepare(fe, stream);
452	if (ret < 0)
453		goto out;
454
455	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
456		dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
457	else
458		dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
 
 
 
 
 
 
 
 
 
 
 
459
 
460	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
461
462out:
463	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
464	mutex_unlock(&fe->card->mutex);
465	return ret;
466}
467
468static int soc_compr_get_params(struct snd_compr_stream *cstream,
469					struct snd_codec *params)
470{
471	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
472	struct snd_soc_platform *platform = rtd->platform;
 
 
473	int ret = 0;
474
475	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
 
 
 
 
 
476
477	if (platform->driver->compr_ops && platform->driver->compr_ops->get_params)
478		ret = platform->driver->compr_ops->get_params(cstream, params);
479
480	mutex_unlock(&rtd->pcm_mutex);
 
 
 
 
 
 
 
 
 
481	return ret;
482}
483
484static int soc_compr_get_caps(struct snd_compr_stream *cstream,
485				struct snd_compr_caps *caps)
486{
487	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
488	struct snd_soc_platform *platform = rtd->platform;
 
489	int ret = 0;
490
491	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
 
 
492
493	if (platform->driver->compr_ops && platform->driver->compr_ops->get_caps)
494		ret = platform->driver->compr_ops->get_caps(cstream, caps);
 
495
496	mutex_unlock(&rtd->pcm_mutex);
 
 
 
 
497	return ret;
498}
499
500static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream,
501				struct snd_compr_codec_caps *codec)
502{
503	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
504	struct snd_soc_platform *platform = rtd->platform;
 
505	int ret = 0;
506
507	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
 
 
508
509	if (platform->driver->compr_ops && platform->driver->compr_ops->get_codec_caps)
510		ret = platform->driver->compr_ops->get_codec_caps(cstream, codec);
 
511
512	mutex_unlock(&rtd->pcm_mutex);
 
 
 
 
 
513	return ret;
514}
515
516static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
517{
518	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
519	struct snd_soc_platform *platform = rtd->platform;
 
 
520	int ret = 0;
521
522	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
523
524	if (platform->driver->compr_ops && platform->driver->compr_ops->ack)
525		ret = platform->driver->compr_ops->ack(cstream, bytes);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
526
527	mutex_unlock(&rtd->pcm_mutex);
 
528	return ret;
529}
530
531static int soc_compr_pointer(struct snd_compr_stream *cstream,
532			struct snd_compr_tstamp *tstamp)
533{
534	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
535	struct snd_soc_platform *platform = rtd->platform;
 
 
 
536
537	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
538
539	if (platform->driver->compr_ops && platform->driver->compr_ops->pointer)
540		 platform->driver->compr_ops->pointer(cstream, tstamp);
541
542	mutex_unlock(&rtd->pcm_mutex);
543	return 0;
 
 
 
 
 
 
 
 
 
 
 
544}
545
546static int soc_compr_copy(struct snd_compr_stream *cstream,
547			  char __user *buf, size_t count)
548{
549	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
550	struct snd_soc_platform *platform = rtd->platform;
 
551	int ret = 0;
552
553	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
554
555	if (platform->driver->compr_ops && platform->driver->compr_ops->copy)
556		ret = platform->driver->compr_ops->copy(cstream, buf, count);
 
 
 
 
 
 
 
 
557
558	mutex_unlock(&rtd->pcm_mutex);
559	return ret;
560}
561
562static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
563				struct snd_compr_metadata *metadata)
564{
565	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
566	struct snd_soc_platform *platform = rtd->platform;
567	int ret = 0;
 
 
 
 
 
 
 
 
 
 
 
568
569	if (platform->driver->compr_ops && platform->driver->compr_ops->set_metadata)
570		ret = platform->driver->compr_ops->set_metadata(cstream, metadata);
 
571
572	return ret;
 
 
 
 
 
 
573}
574
575static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
576				struct snd_compr_metadata *metadata)
577{
578	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
579	struct snd_soc_platform *platform = rtd->platform;
580	int ret = 0;
 
 
 
 
 
 
 
 
 
 
 
581
582	if (platform->driver->compr_ops && platform->driver->compr_ops->get_metadata)
583		ret = platform->driver->compr_ops->get_metadata(cstream, metadata);
 
584
585	return ret;
 
 
 
 
586}
587
588/* ASoC Compress operations */
589static struct snd_compr_ops soc_compr_ops = {
590	.open		= soc_compr_open,
591	.free		= soc_compr_free,
592	.set_params	= soc_compr_set_params,
593	.set_metadata   = soc_compr_set_metadata,
594	.get_metadata	= soc_compr_get_metadata,
595	.get_params	= soc_compr_get_params,
596	.trigger	= soc_compr_trigger,
597	.pointer	= soc_compr_pointer,
598	.ack		= soc_compr_ack,
599	.get_caps	= soc_compr_get_caps,
600	.get_codec_caps = soc_compr_get_codec_caps
601};
602
603/* ASoC Dynamic Compress operations */
604static struct snd_compr_ops soc_compr_dyn_ops = {
605	.open		= soc_compr_open_fe,
606	.free		= soc_compr_free_fe,
607	.set_params	= soc_compr_set_params_fe,
608	.get_params	= soc_compr_get_params,
609	.set_metadata   = soc_compr_set_metadata,
610	.get_metadata	= soc_compr_get_metadata,
611	.trigger	= soc_compr_trigger_fe,
612	.pointer	= soc_compr_pointer,
613	.ack		= soc_compr_ack,
614	.get_caps	= soc_compr_get_caps,
615	.get_codec_caps = soc_compr_get_codec_caps
616};
617
618/* create a new compress */
619int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
 
 
 
 
 
 
 
620{
621	struct snd_soc_codec *codec = rtd->codec;
622	struct snd_soc_platform *platform = rtd->platform;
623	struct snd_soc_dai *codec_dai = rtd->codec_dai;
624	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
625	struct snd_compr *compr;
626	struct snd_pcm *be_pcm;
627	char new_name[64];
628	int ret = 0, direction = 0;
 
 
 
 
 
 
 
629
630	/* check client and interface hw capabilities */
631	snprintf(new_name, sizeof(new_name), "%s %s-%d",
632			rtd->dai_link->stream_name, codec_dai->name, num);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
633
634	if (codec_dai->driver->playback.channels_min)
635		direction = SND_COMPRESS_PLAYBACK;
636	else if (codec_dai->driver->capture.channels_min)
637		direction = SND_COMPRESS_CAPTURE;
638	else
639		return -EINVAL;
640
641	compr = kzalloc(sizeof(*compr), GFP_KERNEL);
642	if (compr == NULL) {
643		snd_printk(KERN_ERR "Cannot allocate compr\n");
644		return -ENOMEM;
645	}
646
647	compr->ops = devm_kzalloc(rtd->card->dev, sizeof(soc_compr_ops),
648				  GFP_KERNEL);
649	if (compr->ops == NULL) {
650		dev_err(rtd->card->dev, "Cannot allocate compressed ops\n");
651		ret = -ENOMEM;
652		goto compr_err;
653	}
654
655	if (rtd->dai_link->dynamic) {
656		snprintf(new_name, sizeof(new_name), "(%s)",
657			rtd->dai_link->stream_name);
658
659		ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
660				1, 0, &be_pcm);
 
661		if (ret < 0) {
662			dev_err(rtd->card->dev, "ASoC: can't create compressed for %s\n",
663				rtd->dai_link->name);
664			goto compr_err;
 
665		}
666
667		rtd->pcm = be_pcm;
668		rtd->fe_compr = 1;
669		be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
670		be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
 
 
671		memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops));
672	} else
 
 
 
673		memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));
 
 
 
 
 
 
 
 
674
675	/* Add copy callback for not memory mapped DSPs */
676	if (platform->driver->compr_ops && platform->driver->compr_ops->copy)
677		compr->ops->copy = soc_compr_copy;
 
 
678
679	mutex_init(&compr->lock);
680	ret = snd_compress_new(rtd->card->snd_card, num, direction, compr);
 
681	if (ret < 0) {
682		pr_err("compress asoc: can't create compress for codec %s\n",
683			codec->name);
684		goto compr_err;
 
 
685	}
686
687	/* DAPM dai link stream work */
688	INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
689
690	rtd->compr = compr;
691	compr->private_data = rtd;
692
693	printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name,
694		cpu_dai->name);
695	return ret;
696
697compr_err:
698	kfree(compr);
699	return ret;
700}