Linux Audio

Check our new training course

Linux BSP development engineering services

Need help to port Linux and bootloaders to your hardware?
Loading...
Note: File does not exist in v3.5.6.
  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);