xref: /openbmc/linux/sound/soc/soc-compress.c (revision 2e622ae4)
11245b700SNamarta Kohli /*
21245b700SNamarta Kohli  * soc-compress.c  --  ALSA SoC Compress
31245b700SNamarta Kohli  *
41245b700SNamarta Kohli  * Copyright (C) 2012 Intel Corp.
51245b700SNamarta Kohli  *
61245b700SNamarta Kohli  * Authors: Namarta Kohli <namartax.kohli@intel.com>
71245b700SNamarta Kohli  *          Ramesh Babu K V <ramesh.babu@linux.intel.com>
81245b700SNamarta Kohli  *          Vinod Koul <vinod.koul@linux.intel.com>
91245b700SNamarta Kohli  *
101245b700SNamarta Kohli  *  This program is free software; you can redistribute  it and/or modify it
111245b700SNamarta Kohli  *  under  the terms of  the GNU General  Public License as published by the
121245b700SNamarta Kohli  *  Free Software Foundation;  either version 2 of the  License, or (at your
131245b700SNamarta Kohli  *  option) any later version.
141245b700SNamarta Kohli  *
151245b700SNamarta Kohli  */
161245b700SNamarta Kohli 
171245b700SNamarta Kohli #include <linux/kernel.h>
181245b700SNamarta Kohli #include <linux/init.h>
191245b700SNamarta Kohli #include <linux/delay.h>
201245b700SNamarta Kohli #include <linux/slab.h>
211245b700SNamarta Kohli #include <linux/workqueue.h>
221245b700SNamarta Kohli #include <sound/core.h>
231245b700SNamarta Kohli #include <sound/compress_params.h>
241245b700SNamarta Kohli #include <sound/compress_driver.h>
251245b700SNamarta Kohli #include <sound/soc.h>
261245b700SNamarta Kohli #include <sound/initval.h>
272a99ef0fSLiam Girdwood #include <sound/soc-dpcm.h>
281245b700SNamarta Kohli 
291245b700SNamarta Kohli static int soc_compr_open(struct snd_compr_stream *cstream)
301245b700SNamarta Kohli {
311245b700SNamarta Kohli 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
321245b700SNamarta Kohli 	struct snd_soc_platform *platform = rtd->platform;
332e622ae4SVinod Koul 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
341245b700SNamarta Kohli 	int ret = 0;
351245b700SNamarta Kohli 
3615e2e619SCharles Keepax 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
3715e2e619SCharles Keepax 
382e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) {
392e622ae4SVinod Koul 		ret = cpu_dai->driver->cops->startup(cstream, cpu_dai);
402e622ae4SVinod Koul 		if (ret < 0) {
412e622ae4SVinod Koul 			dev_err(cpu_dai->dev, "Compress ASoC: can't open interface %s: %d\n",
422e622ae4SVinod Koul 				cpu_dai->name, ret);
432e622ae4SVinod Koul 			goto out;
442e622ae4SVinod Koul 		}
452e622ae4SVinod Koul 	}
462e622ae4SVinod Koul 
471245b700SNamarta Kohli 	if (platform->driver->compr_ops && platform->driver->compr_ops->open) {
481245b700SNamarta Kohli 		ret = platform->driver->compr_ops->open(cstream);
491245b700SNamarta Kohli 		if (ret < 0) {
50f4333203SLars-Peter Clausen 			pr_err("compress asoc: can't open platform %s\n",
51f4333203SLars-Peter Clausen 				platform->component.name);
522e622ae4SVinod Koul 			goto plat_err;
531245b700SNamarta Kohli 		}
541245b700SNamarta Kohli 	}
551245b700SNamarta Kohli 
561245b700SNamarta Kohli 	if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->startup) {
571245b700SNamarta Kohli 		ret = rtd->dai_link->compr_ops->startup(cstream);
581245b700SNamarta Kohli 		if (ret < 0) {
591245b700SNamarta Kohli 			pr_err("compress asoc: %s startup failed\n", rtd->dai_link->name);
601245b700SNamarta Kohli 			goto machine_err;
611245b700SNamarta Kohli 		}
621245b700SNamarta Kohli 	}
631245b700SNamarta Kohli 
6424894b76SLars-Peter Clausen 	snd_soc_runtime_activate(rtd, cstream->direction);
651245b700SNamarta Kohli 
6615e2e619SCharles Keepax 	mutex_unlock(&rtd->pcm_mutex);
6715e2e619SCharles Keepax 
681245b700SNamarta Kohli 	return 0;
691245b700SNamarta Kohli 
701245b700SNamarta Kohli machine_err:
711245b700SNamarta Kohli 	if (platform->driver->compr_ops && platform->driver->compr_ops->free)
721245b700SNamarta Kohli 		platform->driver->compr_ops->free(cstream);
732e622ae4SVinod Koul plat_err:
742e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
752e622ae4SVinod Koul 		cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
761245b700SNamarta Kohli out:
7715e2e619SCharles Keepax 	mutex_unlock(&rtd->pcm_mutex);
781245b700SNamarta Kohli 	return ret;
791245b700SNamarta Kohli }
801245b700SNamarta Kohli 
812a99ef0fSLiam Girdwood static int soc_compr_open_fe(struct snd_compr_stream *cstream)
822a99ef0fSLiam Girdwood {
832a99ef0fSLiam Girdwood 	struct snd_soc_pcm_runtime *fe = cstream->private_data;
842a99ef0fSLiam Girdwood 	struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;
852a99ef0fSLiam Girdwood 	struct snd_soc_platform *platform = fe->platform;
862e622ae4SVinod Koul 	struct snd_soc_dai *cpu_dai = fe->cpu_dai;
872a99ef0fSLiam Girdwood 	struct snd_soc_dpcm *dpcm;
882a99ef0fSLiam Girdwood 	struct snd_soc_dapm_widget_list *list;
892a99ef0fSLiam Girdwood 	int stream;
902a99ef0fSLiam Girdwood 	int ret = 0;
912a99ef0fSLiam Girdwood 
922a99ef0fSLiam Girdwood 	if (cstream->direction == SND_COMPRESS_PLAYBACK)
932a99ef0fSLiam Girdwood 		stream = SNDRV_PCM_STREAM_PLAYBACK;
942a99ef0fSLiam Girdwood 	else
952a99ef0fSLiam Girdwood 		stream = SNDRV_PCM_STREAM_CAPTURE;
962a99ef0fSLiam Girdwood 
972a99ef0fSLiam Girdwood 	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
982a99ef0fSLiam Girdwood 
992e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) {
1002e622ae4SVinod Koul 		ret = cpu_dai->driver->cops->startup(cstream, cpu_dai);
1012e622ae4SVinod Koul 		if (ret < 0) {
1022e622ae4SVinod Koul 			dev_err(cpu_dai->dev, "Compress ASoC: can't open interface %s: %d\n",
1032e622ae4SVinod Koul 				cpu_dai->name, ret);
1042e622ae4SVinod Koul 			goto out;
1052e622ae4SVinod Koul 		}
1062e622ae4SVinod Koul 	}
1072e622ae4SVinod Koul 
1082e622ae4SVinod Koul 
1092a99ef0fSLiam Girdwood 	if (platform->driver->compr_ops && platform->driver->compr_ops->open) {
1102a99ef0fSLiam Girdwood 		ret = platform->driver->compr_ops->open(cstream);
1112a99ef0fSLiam Girdwood 		if (ret < 0) {
112f4333203SLars-Peter Clausen 			pr_err("compress asoc: can't open platform %s\n",
113f4333203SLars-Peter Clausen 				platform->component.name);
1142e622ae4SVinod Koul 			goto plat_err;
1152a99ef0fSLiam Girdwood 		}
1162a99ef0fSLiam Girdwood 	}
1172a99ef0fSLiam Girdwood 
1182a99ef0fSLiam Girdwood 	if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->startup) {
1192a99ef0fSLiam Girdwood 		ret = fe->dai_link->compr_ops->startup(cstream);
1202a99ef0fSLiam Girdwood 		if (ret < 0) {
1212a99ef0fSLiam Girdwood 			pr_err("compress asoc: %s startup failed\n", fe->dai_link->name);
1222a99ef0fSLiam Girdwood 			goto machine_err;
1232a99ef0fSLiam Girdwood 		}
1242a99ef0fSLiam Girdwood 	}
1252a99ef0fSLiam Girdwood 
1262a99ef0fSLiam Girdwood 	fe->dpcm[stream].runtime = fe_substream->runtime;
1272a99ef0fSLiam Girdwood 
1288f70e515SQiao Zhou 	ret = dpcm_path_get(fe, stream, &list);
1292e4ec1c0SQiao Zhou 	if (ret < 0)
1308f70e515SQiao Zhou 		goto fe_err;
1312e4ec1c0SQiao Zhou 	else if (ret == 0)
1322a99ef0fSLiam Girdwood 		dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
1332a99ef0fSLiam Girdwood 			fe->dai_link->name, stream ? "capture" : "playback");
1342a99ef0fSLiam Girdwood 
1352a99ef0fSLiam Girdwood 	/* calculate valid and active FE <-> BE dpcms */
1362a99ef0fSLiam Girdwood 	dpcm_process_paths(fe, stream, &list, 1);
1372a99ef0fSLiam Girdwood 
1382a99ef0fSLiam Girdwood 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
1392a99ef0fSLiam Girdwood 
1402a99ef0fSLiam Girdwood 	ret = dpcm_be_dai_startup(fe, stream);
1412a99ef0fSLiam Girdwood 	if (ret < 0) {
1422a99ef0fSLiam Girdwood 		/* clean up all links */
1432a99ef0fSLiam Girdwood 		list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
1442a99ef0fSLiam Girdwood 			dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
1452a99ef0fSLiam Girdwood 
1462a99ef0fSLiam Girdwood 		dpcm_be_disconnect(fe, stream);
1472a99ef0fSLiam Girdwood 		fe->dpcm[stream].runtime = NULL;
148b0f12c61SCharles Keepax 		goto path_err;
1492a99ef0fSLiam Girdwood 	}
1502a99ef0fSLiam Girdwood 
1512a99ef0fSLiam Girdwood 	dpcm_clear_pending_state(fe, stream);
1522a99ef0fSLiam Girdwood 	dpcm_path_put(&list);
1532a99ef0fSLiam Girdwood 
1542a99ef0fSLiam Girdwood 	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
1552a99ef0fSLiam Girdwood 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
1562a99ef0fSLiam Girdwood 
15724894b76SLars-Peter Clausen 	snd_soc_runtime_activate(fe, stream);
1582a99ef0fSLiam Girdwood 
1592a99ef0fSLiam Girdwood 	mutex_unlock(&fe->card->mutex);
1602a99ef0fSLiam Girdwood 
1612a99ef0fSLiam Girdwood 	return 0;
1622a99ef0fSLiam Girdwood 
163b0f12c61SCharles Keepax path_err:
164b0f12c61SCharles Keepax 	dpcm_path_put(&list);
1652a99ef0fSLiam Girdwood fe_err:
1662a99ef0fSLiam Girdwood 	if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
1672a99ef0fSLiam Girdwood 		fe->dai_link->compr_ops->shutdown(cstream);
1682a99ef0fSLiam Girdwood machine_err:
1692a99ef0fSLiam Girdwood 	if (platform->driver->compr_ops && platform->driver->compr_ops->free)
1702a99ef0fSLiam Girdwood 		platform->driver->compr_ops->free(cstream);
1712e622ae4SVinod Koul plat_err:
1722e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
1732e622ae4SVinod Koul 		cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
1742a99ef0fSLiam Girdwood out:
1752a99ef0fSLiam Girdwood 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
1762a99ef0fSLiam Girdwood 	mutex_unlock(&fe->card->mutex);
1772a99ef0fSLiam Girdwood 	return ret;
1782a99ef0fSLiam Girdwood }
1792a99ef0fSLiam Girdwood 
180202c8f70SCharles Keepax /*
181202c8f70SCharles Keepax  * Power down the audio subsystem pmdown_time msecs after close is called.
182202c8f70SCharles Keepax  * This is to ensure there are no pops or clicks in between any music tracks
183202c8f70SCharles Keepax  * due to DAPM power cycling.
184202c8f70SCharles Keepax  */
185202c8f70SCharles Keepax static void close_delayed_work(struct work_struct *work)
186202c8f70SCharles Keepax {
187202c8f70SCharles Keepax 	struct snd_soc_pcm_runtime *rtd =
188202c8f70SCharles Keepax 			container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
189202c8f70SCharles Keepax 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
190202c8f70SCharles Keepax 
191202c8f70SCharles Keepax 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
192202c8f70SCharles Keepax 
193202c8f70SCharles Keepax 	dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n",
194202c8f70SCharles Keepax 		 codec_dai->driver->playback.stream_name,
195202c8f70SCharles Keepax 		 codec_dai->playback_active ? "active" : "inactive",
196202c8f70SCharles Keepax 		 rtd->pop_wait ? "yes" : "no");
197202c8f70SCharles Keepax 
198202c8f70SCharles Keepax 	/* are we waiting on this codec DAI stream */
199202c8f70SCharles Keepax 	if (rtd->pop_wait == 1) {
200202c8f70SCharles Keepax 		rtd->pop_wait = 0;
201202c8f70SCharles Keepax 		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
202202c8f70SCharles Keepax 					  SND_SOC_DAPM_STREAM_STOP);
203202c8f70SCharles Keepax 	}
204202c8f70SCharles Keepax 
205202c8f70SCharles Keepax 	mutex_unlock(&rtd->pcm_mutex);
206202c8f70SCharles Keepax }
207202c8f70SCharles Keepax 
2081245b700SNamarta Kohli static int soc_compr_free(struct snd_compr_stream *cstream)
2091245b700SNamarta Kohli {
2101245b700SNamarta Kohli 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
2111245b700SNamarta Kohli 	struct snd_soc_platform *platform = rtd->platform;
2121245b700SNamarta Kohli 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
2131245b700SNamarta Kohli 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
21424894b76SLars-Peter Clausen 	int stream;
2151245b700SNamarta Kohli 
21615e2e619SCharles Keepax 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
21715e2e619SCharles Keepax 
21824894b76SLars-Peter Clausen 	if (cstream->direction == SND_COMPRESS_PLAYBACK)
21924894b76SLars-Peter Clausen 		stream = SNDRV_PCM_STREAM_PLAYBACK;
22024894b76SLars-Peter Clausen 	else
22124894b76SLars-Peter Clausen 		stream = SNDRV_PCM_STREAM_CAPTURE;
22224894b76SLars-Peter Clausen 
22324894b76SLars-Peter Clausen 	snd_soc_runtime_deactivate(rtd, stream);
2241245b700SNamarta Kohli 
225da18396fSMark Brown 	snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
226da18396fSMark Brown 
2271245b700SNamarta Kohli 	if (!cpu_dai->active)
2281245b700SNamarta Kohli 		cpu_dai->rate = 0;
2291245b700SNamarta Kohli 
2301245b700SNamarta Kohli 	if (!codec_dai->active)
2311245b700SNamarta Kohli 		codec_dai->rate = 0;
2321245b700SNamarta Kohli 
2331245b700SNamarta Kohli 
2341245b700SNamarta Kohli 	if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown)
2351245b700SNamarta Kohli 		rtd->dai_link->compr_ops->shutdown(cstream);
2361245b700SNamarta Kohli 
2371245b700SNamarta Kohli 	if (platform->driver->compr_ops && platform->driver->compr_ops->free)
2381245b700SNamarta Kohli 		platform->driver->compr_ops->free(cstream);
2391245b700SNamarta Kohli 
2402e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
2412e622ae4SVinod Koul 		cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
2422e622ae4SVinod Koul 
2431245b700SNamarta Kohli 	if (cstream->direction == SND_COMPRESS_PLAYBACK) {
244208a1589SLars-Peter Clausen 		if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
2451245b700SNamarta Kohli 			snd_soc_dapm_stream_event(rtd,
2461245b700SNamarta Kohli 					SNDRV_PCM_STREAM_PLAYBACK,
2471245b700SNamarta Kohli 					SND_SOC_DAPM_STREAM_STOP);
2488c3d2aa4SCharles Keepax 		} else {
2499bffb1fbSMisael Lopez Cruz 			rtd->pop_wait = 1;
2503d24cfe4SMark Brown 			queue_delayed_work(system_power_efficient_wq,
2513d24cfe4SMark Brown 					   &rtd->delayed_work,
2521245b700SNamarta Kohli 					   msecs_to_jiffies(rtd->pmdown_time));
2538c3d2aa4SCharles Keepax 		}
2541245b700SNamarta Kohli 	} else {
2551245b700SNamarta Kohli 		/* capture streams can be powered down now */
2561245b700SNamarta Kohli 		snd_soc_dapm_stream_event(rtd,
2571245b700SNamarta Kohli 			SNDRV_PCM_STREAM_CAPTURE,
2581245b700SNamarta Kohli 			SND_SOC_DAPM_STREAM_STOP);
2591245b700SNamarta Kohli 	}
2601245b700SNamarta Kohli 
26115e2e619SCharles Keepax 	mutex_unlock(&rtd->pcm_mutex);
2621245b700SNamarta Kohli 	return 0;
2631245b700SNamarta Kohli }
2641245b700SNamarta Kohli 
2652a99ef0fSLiam Girdwood static int soc_compr_free_fe(struct snd_compr_stream *cstream)
2662a99ef0fSLiam Girdwood {
2672a99ef0fSLiam Girdwood 	struct snd_soc_pcm_runtime *fe = cstream->private_data;
2682a99ef0fSLiam Girdwood 	struct snd_soc_platform *platform = fe->platform;
2692e622ae4SVinod Koul 	struct snd_soc_dai *cpu_dai = fe->cpu_dai;
2702a99ef0fSLiam Girdwood 	struct snd_soc_dpcm *dpcm;
2712a99ef0fSLiam Girdwood 	int stream, ret;
2722a99ef0fSLiam Girdwood 
2732a99ef0fSLiam Girdwood 	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2742a99ef0fSLiam Girdwood 
27524894b76SLars-Peter Clausen 	if (cstream->direction == SND_COMPRESS_PLAYBACK)
2762a99ef0fSLiam Girdwood 		stream = SNDRV_PCM_STREAM_PLAYBACK;
27724894b76SLars-Peter Clausen 	else
2782a99ef0fSLiam Girdwood 		stream = SNDRV_PCM_STREAM_CAPTURE;
2792a99ef0fSLiam Girdwood 
28024894b76SLars-Peter Clausen 	snd_soc_runtime_deactivate(fe, stream);
2812a99ef0fSLiam Girdwood 
2822a99ef0fSLiam Girdwood 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
2832a99ef0fSLiam Girdwood 
2842a99ef0fSLiam Girdwood 	ret = dpcm_be_dai_hw_free(fe, stream);
2852a99ef0fSLiam Girdwood 	if (ret < 0)
2862a99ef0fSLiam Girdwood 		dev_err(fe->dev, "compressed hw_free failed %d\n", ret);
2872a99ef0fSLiam Girdwood 
2882a99ef0fSLiam Girdwood 	ret = dpcm_be_dai_shutdown(fe, stream);
2892a99ef0fSLiam Girdwood 
2902a99ef0fSLiam Girdwood 	/* mark FE's links ready to prune */
2912a99ef0fSLiam Girdwood 	list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
2922a99ef0fSLiam Girdwood 		dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
2932a99ef0fSLiam Girdwood 
2942a99ef0fSLiam Girdwood 	dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
2952a99ef0fSLiam Girdwood 
2962a99ef0fSLiam Girdwood 	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
2972a99ef0fSLiam Girdwood 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
2982a99ef0fSLiam Girdwood 
2992a99ef0fSLiam Girdwood 	dpcm_be_disconnect(fe, stream);
3002a99ef0fSLiam Girdwood 
3012a99ef0fSLiam Girdwood 	fe->dpcm[stream].runtime = NULL;
3022a99ef0fSLiam Girdwood 
3032a99ef0fSLiam Girdwood 	if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
3042a99ef0fSLiam Girdwood 		fe->dai_link->compr_ops->shutdown(cstream);
3052a99ef0fSLiam Girdwood 
3062a99ef0fSLiam Girdwood 	if (platform->driver->compr_ops && platform->driver->compr_ops->free)
3072a99ef0fSLiam Girdwood 		platform->driver->compr_ops->free(cstream);
3082a99ef0fSLiam Girdwood 
3092e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
3102e622ae4SVinod Koul 		cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
3112e622ae4SVinod Koul 
3122a99ef0fSLiam Girdwood 	mutex_unlock(&fe->card->mutex);
3132a99ef0fSLiam Girdwood 	return 0;
3142a99ef0fSLiam Girdwood }
3152a99ef0fSLiam Girdwood 
3161245b700SNamarta Kohli static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
3171245b700SNamarta Kohli {
3181245b700SNamarta Kohli 
3191245b700SNamarta Kohli 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
3201245b700SNamarta Kohli 	struct snd_soc_platform *platform = rtd->platform;
3211245b700SNamarta Kohli 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
3222e622ae4SVinod Koul 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
3231245b700SNamarta Kohli 	int ret = 0;
3241245b700SNamarta Kohli 
32515e2e619SCharles Keepax 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
32615e2e619SCharles Keepax 
3271245b700SNamarta Kohli 	if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
3281245b700SNamarta Kohli 		ret = platform->driver->compr_ops->trigger(cstream, cmd);
3291245b700SNamarta Kohli 		if (ret < 0)
33015e2e619SCharles Keepax 			goto out;
3311245b700SNamarta Kohli 	}
3321245b700SNamarta Kohli 
3332e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger)
3342e622ae4SVinod Koul 		cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai);
3352e622ae4SVinod Koul 
3362e622ae4SVinod Koul 
337e38b9b74SMark Brown 	switch (cmd) {
338e38b9b74SMark Brown 	case SNDRV_PCM_TRIGGER_START:
339da18396fSMark Brown 		snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction);
340e38b9b74SMark Brown 		break;
341e38b9b74SMark Brown 	case SNDRV_PCM_TRIGGER_STOP:
342da18396fSMark Brown 		snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
343e38b9b74SMark Brown 		break;
344e38b9b74SMark Brown 	}
3451245b700SNamarta Kohli 
34615e2e619SCharles Keepax out:
34715e2e619SCharles Keepax 	mutex_unlock(&rtd->pcm_mutex);
3481245b700SNamarta Kohli 	return ret;
3491245b700SNamarta Kohli }
3501245b700SNamarta Kohli 
3512a99ef0fSLiam Girdwood static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
3522a99ef0fSLiam Girdwood {
3532a99ef0fSLiam Girdwood 	struct snd_soc_pcm_runtime *fe = cstream->private_data;
3542a99ef0fSLiam Girdwood 	struct snd_soc_platform *platform = fe->platform;
3552e622ae4SVinod Koul 	struct snd_soc_dai *cpu_dai = fe->cpu_dai;
3562a99ef0fSLiam Girdwood 	int ret = 0, stream;
3572a99ef0fSLiam Girdwood 
3582a99ef0fSLiam Girdwood 	if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN ||
3592a99ef0fSLiam Girdwood 		cmd == SND_COMPR_TRIGGER_DRAIN) {
3602a99ef0fSLiam Girdwood 
3612a99ef0fSLiam Girdwood 		if (platform->driver->compr_ops &&
3622a99ef0fSLiam Girdwood 		    platform->driver->compr_ops->trigger)
36315b8e94fSDan Carpenter 			return platform->driver->compr_ops->trigger(cstream,
36415b8e94fSDan Carpenter 								    cmd);
3652a99ef0fSLiam Girdwood 	}
3662a99ef0fSLiam Girdwood 
3672a99ef0fSLiam Girdwood 	if (cstream->direction == SND_COMPRESS_PLAYBACK)
3682a99ef0fSLiam Girdwood 		stream = SNDRV_PCM_STREAM_PLAYBACK;
3692a99ef0fSLiam Girdwood 	else
3702a99ef0fSLiam Girdwood 		stream = SNDRV_PCM_STREAM_CAPTURE;
3712a99ef0fSLiam Girdwood 
3722a99ef0fSLiam Girdwood 
3732a99ef0fSLiam Girdwood 	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
3742a99ef0fSLiam Girdwood 
3752e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) {
3762e622ae4SVinod Koul 		ret = cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai);
3772e622ae4SVinod Koul 		if (ret < 0)
3782e622ae4SVinod Koul 			goto out;
3792e622ae4SVinod Koul 	}
3802e622ae4SVinod Koul 
3812a99ef0fSLiam Girdwood 	if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
3822a99ef0fSLiam Girdwood 		ret = platform->driver->compr_ops->trigger(cstream, cmd);
3832a99ef0fSLiam Girdwood 		if (ret < 0)
3842a99ef0fSLiam Girdwood 			goto out;
3852a99ef0fSLiam Girdwood 	}
3862a99ef0fSLiam Girdwood 
3872a99ef0fSLiam Girdwood 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
3882a99ef0fSLiam Girdwood 
3892a99ef0fSLiam Girdwood 	ret = dpcm_be_dai_trigger(fe, stream, cmd);
3902a99ef0fSLiam Girdwood 
3912a99ef0fSLiam Girdwood 	switch (cmd) {
3922a99ef0fSLiam Girdwood 	case SNDRV_PCM_TRIGGER_START:
3932a99ef0fSLiam Girdwood 	case SNDRV_PCM_TRIGGER_RESUME:
3942a99ef0fSLiam Girdwood 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
3952a99ef0fSLiam Girdwood 		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
3962a99ef0fSLiam Girdwood 		break;
3972a99ef0fSLiam Girdwood 	case SNDRV_PCM_TRIGGER_STOP:
3982a99ef0fSLiam Girdwood 	case SNDRV_PCM_TRIGGER_SUSPEND:
3992a99ef0fSLiam Girdwood 		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
4002a99ef0fSLiam Girdwood 		break;
4012a99ef0fSLiam Girdwood 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
4022a99ef0fSLiam Girdwood 		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
4032a99ef0fSLiam Girdwood 		break;
4042a99ef0fSLiam Girdwood 	}
4052a99ef0fSLiam Girdwood 
4062a99ef0fSLiam Girdwood out:
4072a99ef0fSLiam Girdwood 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
4082a99ef0fSLiam Girdwood 	mutex_unlock(&fe->card->mutex);
4092a99ef0fSLiam Girdwood 	return ret;
4102a99ef0fSLiam Girdwood }
4112a99ef0fSLiam Girdwood 
4121245b700SNamarta Kohli static int soc_compr_set_params(struct snd_compr_stream *cstream,
4131245b700SNamarta Kohli 					struct snd_compr_params *params)
4141245b700SNamarta Kohli {
4151245b700SNamarta Kohli 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
4161245b700SNamarta Kohli 	struct snd_soc_platform *platform = rtd->platform;
4172e622ae4SVinod Koul 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
4181245b700SNamarta Kohli 	int ret = 0;
4191245b700SNamarta Kohli 
42015e2e619SCharles Keepax 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
42115e2e619SCharles Keepax 
4221245b700SNamarta Kohli 	/* first we call set_params for the platform driver
4231245b700SNamarta Kohli 	 * this should configure the soc side
4241245b700SNamarta Kohli 	 * if the machine has compressed ops then we call that as well
4251245b700SNamarta Kohli 	 * expectation is that platform and machine will configure everything
4261245b700SNamarta Kohli 	 * for this compress path, like configuring pcm port for codec
4271245b700SNamarta Kohli 	 */
4282e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) {
4292e622ae4SVinod Koul 		ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai);
4302e622ae4SVinod Koul 		if (ret < 0)
4312e622ae4SVinod Koul 			goto err;
4322e622ae4SVinod Koul 	}
4332e622ae4SVinod Koul 
4341245b700SNamarta Kohli 	if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
4351245b700SNamarta Kohli 		ret = platform->driver->compr_ops->set_params(cstream, params);
4361245b700SNamarta Kohli 		if (ret < 0)
437fa40ef20SCharles Keepax 			goto err;
4381245b700SNamarta Kohli 	}
4391245b700SNamarta Kohli 
4401245b700SNamarta Kohli 	if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) {
4411245b700SNamarta Kohli 		ret = rtd->dai_link->compr_ops->set_params(cstream);
4421245b700SNamarta Kohli 		if (ret < 0)
443fa40ef20SCharles Keepax 			goto err;
4441245b700SNamarta Kohli 	}
4451245b700SNamarta Kohli 
4462c071ed7SCharles Keepax 	if (cstream->direction == SND_COMPRESS_PLAYBACK)
4471245b700SNamarta Kohli 		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
4481245b700SNamarta Kohli 					SND_SOC_DAPM_STREAM_START);
4492c071ed7SCharles Keepax 	else
4502c071ed7SCharles Keepax 		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
4512c071ed7SCharles Keepax 					SND_SOC_DAPM_STREAM_START);
4521245b700SNamarta Kohli 
453fa40ef20SCharles Keepax 	/* cancel any delayed stream shutdown that is pending */
454fa40ef20SCharles Keepax 	rtd->pop_wait = 0;
455fa40ef20SCharles Keepax 	mutex_unlock(&rtd->pcm_mutex);
456fa40ef20SCharles Keepax 
457fa40ef20SCharles Keepax 	cancel_delayed_work_sync(&rtd->delayed_work);
458fa40ef20SCharles Keepax 
459fa40ef20SCharles Keepax 	return ret;
460fa40ef20SCharles Keepax 
461fa40ef20SCharles Keepax err:
46215e2e619SCharles Keepax 	mutex_unlock(&rtd->pcm_mutex);
4631245b700SNamarta Kohli 	return ret;
4641245b700SNamarta Kohli }
4651245b700SNamarta Kohli 
4662a99ef0fSLiam Girdwood static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
4672a99ef0fSLiam Girdwood 					struct snd_compr_params *params)
4682a99ef0fSLiam Girdwood {
4692a99ef0fSLiam Girdwood 	struct snd_soc_pcm_runtime *fe = cstream->private_data;
4702a99ef0fSLiam Girdwood 	struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;
4712a99ef0fSLiam Girdwood 	struct snd_soc_platform *platform = fe->platform;
4722e622ae4SVinod Koul 	struct snd_soc_dai *cpu_dai = fe->cpu_dai;
4732a99ef0fSLiam Girdwood 	int ret = 0, stream;
4742a99ef0fSLiam Girdwood 
4752a99ef0fSLiam Girdwood 	if (cstream->direction == SND_COMPRESS_PLAYBACK)
4762a99ef0fSLiam Girdwood 		stream = SNDRV_PCM_STREAM_PLAYBACK;
4772a99ef0fSLiam Girdwood 	else
4782a99ef0fSLiam Girdwood 		stream = SNDRV_PCM_STREAM_CAPTURE;
4792a99ef0fSLiam Girdwood 
4802a99ef0fSLiam Girdwood 	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
4812a99ef0fSLiam Girdwood 
4822e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) {
4832e622ae4SVinod Koul 		ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai);
4842e622ae4SVinod Koul 		if (ret < 0)
4852e622ae4SVinod Koul 			goto out;
4862e622ae4SVinod Koul 	}
4872e622ae4SVinod Koul 
4882a99ef0fSLiam Girdwood 	if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
4892a99ef0fSLiam Girdwood 		ret = platform->driver->compr_ops->set_params(cstream, params);
4902a99ef0fSLiam Girdwood 		if (ret < 0)
4912a99ef0fSLiam Girdwood 			goto out;
4922a99ef0fSLiam Girdwood 	}
4932a99ef0fSLiam Girdwood 
4942a99ef0fSLiam Girdwood 	if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) {
4952a99ef0fSLiam Girdwood 		ret = fe->dai_link->compr_ops->set_params(cstream);
4962a99ef0fSLiam Girdwood 		if (ret < 0)
4972a99ef0fSLiam Girdwood 			goto out;
4982a99ef0fSLiam Girdwood 	}
4992a99ef0fSLiam Girdwood 
5002a99ef0fSLiam Girdwood 	/*
5012a99ef0fSLiam Girdwood 	 * Create an empty hw_params for the BE as the machine driver must
5022a99ef0fSLiam Girdwood 	 * fix this up to match DSP decoder and ASRC configuration.
5032a99ef0fSLiam Girdwood 	 * I.e. machine driver fixup for compressed BE is mandatory.
5042a99ef0fSLiam Girdwood 	 */
5052a99ef0fSLiam Girdwood 	memset(&fe->dpcm[fe_substream->stream].hw_params, 0,
5062a99ef0fSLiam Girdwood 		sizeof(struct snd_pcm_hw_params));
5072a99ef0fSLiam Girdwood 
5082a99ef0fSLiam Girdwood 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
5092a99ef0fSLiam Girdwood 
5102a99ef0fSLiam Girdwood 	ret = dpcm_be_dai_hw_params(fe, stream);
5112a99ef0fSLiam Girdwood 	if (ret < 0)
5122a99ef0fSLiam Girdwood 		goto out;
5132a99ef0fSLiam Girdwood 
5142a99ef0fSLiam Girdwood 	ret = dpcm_be_dai_prepare(fe, stream);
5152a99ef0fSLiam Girdwood 	if (ret < 0)
5162a99ef0fSLiam Girdwood 		goto out;
5172a99ef0fSLiam Girdwood 
5182a99ef0fSLiam Girdwood 	dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
5192a99ef0fSLiam Girdwood 	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
5202a99ef0fSLiam Girdwood 
5212a99ef0fSLiam Girdwood out:
5222a99ef0fSLiam Girdwood 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
5232a99ef0fSLiam Girdwood 	mutex_unlock(&fe->card->mutex);
5242a99ef0fSLiam Girdwood 	return ret;
5252a99ef0fSLiam Girdwood }
5262a99ef0fSLiam Girdwood 
5271245b700SNamarta Kohli static int soc_compr_get_params(struct snd_compr_stream *cstream,
5281245b700SNamarta Kohli 					struct snd_codec *params)
5291245b700SNamarta Kohli {
5301245b700SNamarta Kohli 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
5311245b700SNamarta Kohli 	struct snd_soc_platform *platform = rtd->platform;
5322e622ae4SVinod Koul 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
5331245b700SNamarta Kohli 	int ret = 0;
5341245b700SNamarta Kohli 
53515e2e619SCharles Keepax 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
53615e2e619SCharles Keepax 
5372e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_params) {
5382e622ae4SVinod Koul 		ret = cpu_dai->driver->cops->get_params(cstream, params, cpu_dai);
5392e622ae4SVinod Koul 		if (ret < 0)
5402e622ae4SVinod Koul 			goto err;
5412e622ae4SVinod Koul 	}
5422e622ae4SVinod Koul 
5431245b700SNamarta Kohli 	if (platform->driver->compr_ops && platform->driver->compr_ops->get_params)
5441245b700SNamarta Kohli 		ret = platform->driver->compr_ops->get_params(cstream, params);
5451245b700SNamarta Kohli 
5462e622ae4SVinod Koul err:
54715e2e619SCharles Keepax 	mutex_unlock(&rtd->pcm_mutex);
5481245b700SNamarta Kohli 	return ret;
5491245b700SNamarta Kohli }
5501245b700SNamarta Kohli 
5511245b700SNamarta Kohli static int soc_compr_get_caps(struct snd_compr_stream *cstream,
5521245b700SNamarta Kohli 				struct snd_compr_caps *caps)
5531245b700SNamarta Kohli {
5541245b700SNamarta Kohli 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
5551245b700SNamarta Kohli 	struct snd_soc_platform *platform = rtd->platform;
5561245b700SNamarta Kohli 	int ret = 0;
5571245b700SNamarta Kohli 
55815e2e619SCharles Keepax 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
55915e2e619SCharles Keepax 
5601245b700SNamarta Kohli 	if (platform->driver->compr_ops && platform->driver->compr_ops->get_caps)
5611245b700SNamarta Kohli 		ret = platform->driver->compr_ops->get_caps(cstream, caps);
5621245b700SNamarta Kohli 
56315e2e619SCharles Keepax 	mutex_unlock(&rtd->pcm_mutex);
5641245b700SNamarta Kohli 	return ret;
5651245b700SNamarta Kohli }
5661245b700SNamarta Kohli 
5671245b700SNamarta Kohli static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream,
5681245b700SNamarta Kohli 				struct snd_compr_codec_caps *codec)
5691245b700SNamarta Kohli {
5701245b700SNamarta Kohli 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
5711245b700SNamarta Kohli 	struct snd_soc_platform *platform = rtd->platform;
5721245b700SNamarta Kohli 	int ret = 0;
5731245b700SNamarta Kohli 
57415e2e619SCharles Keepax 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
57515e2e619SCharles Keepax 
5761245b700SNamarta Kohli 	if (platform->driver->compr_ops && platform->driver->compr_ops->get_codec_caps)
5771245b700SNamarta Kohli 		ret = platform->driver->compr_ops->get_codec_caps(cstream, codec);
5781245b700SNamarta Kohli 
57915e2e619SCharles Keepax 	mutex_unlock(&rtd->pcm_mutex);
5801245b700SNamarta Kohli 	return ret;
5811245b700SNamarta Kohli }
5821245b700SNamarta Kohli 
5831245b700SNamarta Kohli static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
5841245b700SNamarta Kohli {
5851245b700SNamarta Kohli 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
5861245b700SNamarta Kohli 	struct snd_soc_platform *platform = rtd->platform;
5872e622ae4SVinod Koul 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
5881245b700SNamarta Kohli 	int ret = 0;
5891245b700SNamarta Kohli 
59015e2e619SCharles Keepax 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
59115e2e619SCharles Keepax 
5922e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->ack) {
5932e622ae4SVinod Koul 		ret = cpu_dai->driver->cops->ack(cstream, bytes, cpu_dai);
5942e622ae4SVinod Koul 		if (ret < 0)
5952e622ae4SVinod Koul 			goto err;
5962e622ae4SVinod Koul 	}
5972e622ae4SVinod Koul 
5981245b700SNamarta Kohli 	if (platform->driver->compr_ops && platform->driver->compr_ops->ack)
5991245b700SNamarta Kohli 		ret = platform->driver->compr_ops->ack(cstream, bytes);
6001245b700SNamarta Kohli 
6012e622ae4SVinod Koul err:
60215e2e619SCharles Keepax 	mutex_unlock(&rtd->pcm_mutex);
6031245b700SNamarta Kohli 	return ret;
6041245b700SNamarta Kohli }
6051245b700SNamarta Kohli 
6061245b700SNamarta Kohli static int soc_compr_pointer(struct snd_compr_stream *cstream,
6071245b700SNamarta Kohli 			struct snd_compr_tstamp *tstamp)
6081245b700SNamarta Kohli {
6091245b700SNamarta Kohli 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
6101245b700SNamarta Kohli 	struct snd_soc_platform *platform = rtd->platform;
6117c9190f7SCharles Keepax 	int ret = 0;
6122e622ae4SVinod Koul 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
6131245b700SNamarta Kohli 
61415e2e619SCharles Keepax 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
61515e2e619SCharles Keepax 
6162e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->pointer)
6172e622ae4SVinod Koul 		cpu_dai->driver->cops->pointer(cstream, tstamp, cpu_dai);
6182e622ae4SVinod Koul 
6191245b700SNamarta Kohli 	if (platform->driver->compr_ops && platform->driver->compr_ops->pointer)
6207c9190f7SCharles Keepax 		ret = platform->driver->compr_ops->pointer(cstream, tstamp);
6211245b700SNamarta Kohli 
62215e2e619SCharles Keepax 	mutex_unlock(&rtd->pcm_mutex);
6237c9190f7SCharles Keepax 	return ret;
6241245b700SNamarta Kohli }
6251245b700SNamarta Kohli 
6261f88eb0fSCharles Keepax static int soc_compr_copy(struct snd_compr_stream *cstream,
6274daf891cSCharles Keepax 			  char __user *buf, size_t count)
6281f88eb0fSCharles Keepax {
6291f88eb0fSCharles Keepax 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
6301f88eb0fSCharles Keepax 	struct snd_soc_platform *platform = rtd->platform;
6311f88eb0fSCharles Keepax 	int ret = 0;
6321f88eb0fSCharles Keepax 
6331f88eb0fSCharles Keepax 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
6341f88eb0fSCharles Keepax 
6351f88eb0fSCharles Keepax 	if (platform->driver->compr_ops && platform->driver->compr_ops->copy)
6361f88eb0fSCharles Keepax 		ret = platform->driver->compr_ops->copy(cstream, buf, count);
6371f88eb0fSCharles Keepax 
6381f88eb0fSCharles Keepax 	mutex_unlock(&rtd->pcm_mutex);
6391f88eb0fSCharles Keepax 	return ret;
6401f88eb0fSCharles Keepax }
6411f88eb0fSCharles Keepax 
64202bd90e8SVinod Koul static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
64336953d98SJeeja KP 				struct snd_compr_metadata *metadata)
64436953d98SJeeja KP {
64536953d98SJeeja KP 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
64636953d98SJeeja KP 	struct snd_soc_platform *platform = rtd->platform;
6472e622ae4SVinod Koul 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
64836953d98SJeeja KP 	int ret = 0;
64936953d98SJeeja KP 
6502e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_metadata) {
6512e622ae4SVinod Koul 		ret = cpu_dai->driver->cops->set_metadata(cstream, metadata, cpu_dai);
6522e622ae4SVinod Koul 		if (ret < 0)
6532e622ae4SVinod Koul 			return ret;
6542e622ae4SVinod Koul 	}
6552e622ae4SVinod Koul 
65636953d98SJeeja KP 	if (platform->driver->compr_ops && platform->driver->compr_ops->set_metadata)
65736953d98SJeeja KP 		ret = platform->driver->compr_ops->set_metadata(cstream, metadata);
65836953d98SJeeja KP 
65936953d98SJeeja KP 	return ret;
66036953d98SJeeja KP }
66136953d98SJeeja KP 
66202bd90e8SVinod Koul static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
66336953d98SJeeja KP 				struct snd_compr_metadata *metadata)
66436953d98SJeeja KP {
66536953d98SJeeja KP 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
66636953d98SJeeja KP 	struct snd_soc_platform *platform = rtd->platform;
6672e622ae4SVinod Koul 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
66836953d98SJeeja KP 	int ret = 0;
66936953d98SJeeja KP 
6702e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_metadata) {
6712e622ae4SVinod Koul 		ret = cpu_dai->driver->cops->get_metadata(cstream, metadata, cpu_dai);
6722e622ae4SVinod Koul 		if (ret < 0)
6732e622ae4SVinod Koul 			return ret;
6742e622ae4SVinod Koul 	}
6752e622ae4SVinod Koul 
67636953d98SJeeja KP 	if (platform->driver->compr_ops && platform->driver->compr_ops->get_metadata)
67736953d98SJeeja KP 		ret = platform->driver->compr_ops->get_metadata(cstream, metadata);
67836953d98SJeeja KP 
67936953d98SJeeja KP 	return ret;
68036953d98SJeeja KP }
6812a99ef0fSLiam Girdwood 
6821245b700SNamarta Kohli /* ASoC Compress operations */
6831245b700SNamarta Kohli static struct snd_compr_ops soc_compr_ops = {
6841245b700SNamarta Kohli 	.open		= soc_compr_open,
6851245b700SNamarta Kohli 	.free		= soc_compr_free,
6861245b700SNamarta Kohli 	.set_params	= soc_compr_set_params,
68702bd90e8SVinod Koul 	.set_metadata   = soc_compr_set_metadata,
68802bd90e8SVinod Koul 	.get_metadata	= soc_compr_get_metadata,
6891245b700SNamarta Kohli 	.get_params	= soc_compr_get_params,
6901245b700SNamarta Kohli 	.trigger	= soc_compr_trigger,
6911245b700SNamarta Kohli 	.pointer	= soc_compr_pointer,
6921245b700SNamarta Kohli 	.ack		= soc_compr_ack,
6931245b700SNamarta Kohli 	.get_caps	= soc_compr_get_caps,
6941245b700SNamarta Kohli 	.get_codec_caps = soc_compr_get_codec_caps
6951245b700SNamarta Kohli };
6961245b700SNamarta Kohli 
6972a99ef0fSLiam Girdwood /* ASoC Dynamic Compress operations */
6982a99ef0fSLiam Girdwood static struct snd_compr_ops soc_compr_dyn_ops = {
6992a99ef0fSLiam Girdwood 	.open		= soc_compr_open_fe,
7002a99ef0fSLiam Girdwood 	.free		= soc_compr_free_fe,
7012a99ef0fSLiam Girdwood 	.set_params	= soc_compr_set_params_fe,
7022a99ef0fSLiam Girdwood 	.get_params	= soc_compr_get_params,
7032a99ef0fSLiam Girdwood 	.set_metadata   = soc_compr_set_metadata,
7042a99ef0fSLiam Girdwood 	.get_metadata	= soc_compr_get_metadata,
7052a99ef0fSLiam Girdwood 	.trigger	= soc_compr_trigger_fe,
7062a99ef0fSLiam Girdwood 	.pointer	= soc_compr_pointer,
7072a99ef0fSLiam Girdwood 	.ack		= soc_compr_ack,
7082a99ef0fSLiam Girdwood 	.get_caps	= soc_compr_get_caps,
7092a99ef0fSLiam Girdwood 	.get_codec_caps = soc_compr_get_codec_caps
7102a99ef0fSLiam Girdwood };
7112a99ef0fSLiam Girdwood 
7126f0c4226SJie Yang /**
7136f0c4226SJie Yang  * snd_soc_new_compress - create a new compress.
7146f0c4226SJie Yang  *
7156f0c4226SJie Yang  * @rtd: The runtime for which we will create compress
7166f0c4226SJie Yang  * @num: the device index number (zero based - shared with normal PCMs)
7176f0c4226SJie Yang  *
7186f0c4226SJie Yang  * Return: 0 for success, else error.
7196f0c4226SJie Yang  */
7206f0c4226SJie Yang int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
7211245b700SNamarta Kohli {
7221245b700SNamarta Kohli 	struct snd_soc_codec *codec = rtd->codec;
7231f88eb0fSCharles Keepax 	struct snd_soc_platform *platform = rtd->platform;
7241245b700SNamarta Kohli 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
7251245b700SNamarta Kohli 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
7261245b700SNamarta Kohli 	struct snd_compr *compr;
7272a99ef0fSLiam Girdwood 	struct snd_pcm *be_pcm;
7281245b700SNamarta Kohli 	char new_name[64];
7291245b700SNamarta Kohli 	int ret = 0, direction = 0;
730a1068045SVinod Koul 	int playback = 0, capture = 0;
7311245b700SNamarta Kohli 
7328151d5e6SBenoit Cousson 	if (rtd->num_codecs > 1) {
7338151d5e6SBenoit Cousson 		dev_err(rtd->card->dev, "Multicodec not supported for compressed stream\n");
7348151d5e6SBenoit Cousson 		return -EINVAL;
7358151d5e6SBenoit Cousson 	}
7368151d5e6SBenoit Cousson 
7371245b700SNamarta Kohli 	/* check client and interface hw capabilities */
7381245b700SNamarta Kohli 	snprintf(new_name, sizeof(new_name), "%s %s-%d",
7391245b700SNamarta Kohli 			rtd->dai_link->stream_name, codec_dai->name, num);
740daa2db59SCharles Keepax 
741daa2db59SCharles Keepax 	if (codec_dai->driver->playback.channels_min)
742a1068045SVinod Koul 		playback = 1;
743a1068045SVinod Koul 	if (codec_dai->driver->capture.channels_min)
744a1068045SVinod Koul 		capture = 1;
745a1068045SVinod Koul 
746a1068045SVinod Koul 	capture = capture && cpu_dai->driver->capture.channels_min;
747a1068045SVinod Koul 	playback = playback && cpu_dai->driver->playback.channels_min;
748a1068045SVinod Koul 
749a1068045SVinod Koul 	/*
750a1068045SVinod Koul 	 * Compress devices are unidirectional so only one of the directions
751a1068045SVinod Koul 	 * should be set, check for that (xor)
752a1068045SVinod Koul 	 */
753a1068045SVinod Koul 	if (playback + capture != 1) {
754a1068045SVinod Koul 		dev_err(rtd->card->dev, "Invalid direction for compress P %d, C %d\n",
755a1068045SVinod Koul 				playback, capture);
756daa2db59SCharles Keepax 		return -EINVAL;
757a1068045SVinod Koul 	}
758a1068045SVinod Koul 
759a1068045SVinod Koul 	if(playback)
760a1068045SVinod Koul 		direction = SND_COMPRESS_PLAYBACK;
761a1068045SVinod Koul 	else
762a1068045SVinod Koul 		direction = SND_COMPRESS_CAPTURE;
763daa2db59SCharles Keepax 
7641245b700SNamarta Kohli 	compr = kzalloc(sizeof(*compr), GFP_KERNEL);
7651245b700SNamarta Kohli 	if (compr == NULL) {
7661245b700SNamarta Kohli 		snd_printk(KERN_ERR "Cannot allocate compr\n");
7671245b700SNamarta Kohli 		return -ENOMEM;
7681245b700SNamarta Kohli 	}
7691245b700SNamarta Kohli 
7701f88eb0fSCharles Keepax 	compr->ops = devm_kzalloc(rtd->card->dev, sizeof(soc_compr_ops),
7711f88eb0fSCharles Keepax 				  GFP_KERNEL);
7721f88eb0fSCharles Keepax 	if (compr->ops == NULL) {
7731f88eb0fSCharles Keepax 		dev_err(rtd->card->dev, "Cannot allocate compressed ops\n");
7741f88eb0fSCharles Keepax 		ret = -ENOMEM;
7751f88eb0fSCharles Keepax 		goto compr_err;
7761f88eb0fSCharles Keepax 	}
7772a99ef0fSLiam Girdwood 
7782a99ef0fSLiam Girdwood 	if (rtd->dai_link->dynamic) {
7792a99ef0fSLiam Girdwood 		snprintf(new_name, sizeof(new_name), "(%s)",
7802a99ef0fSLiam Girdwood 			rtd->dai_link->stream_name);
7812a99ef0fSLiam Girdwood 
7822a99ef0fSLiam Girdwood 		ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
783d3268a40SQais Yousef 				rtd->dai_link->dpcm_playback,
784d3268a40SQais Yousef 				rtd->dai_link->dpcm_capture, &be_pcm);
7852a99ef0fSLiam Girdwood 		if (ret < 0) {
7862a99ef0fSLiam Girdwood 			dev_err(rtd->card->dev, "ASoC: can't create compressed for %s\n",
7872a99ef0fSLiam Girdwood 				rtd->dai_link->name);
7882a99ef0fSLiam Girdwood 			goto compr_err;
7892a99ef0fSLiam Girdwood 		}
7902a99ef0fSLiam Girdwood 
7912a99ef0fSLiam Girdwood 		rtd->pcm = be_pcm;
7922a99ef0fSLiam Girdwood 		rtd->fe_compr = 1;
793d3268a40SQais Yousef 		if (rtd->dai_link->dpcm_playback)
7942a99ef0fSLiam Girdwood 			be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
795d3268a40SQais Yousef 		else if (rtd->dai_link->dpcm_capture)
7962a99ef0fSLiam Girdwood 			be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
7972a99ef0fSLiam Girdwood 		memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops));
7982a99ef0fSLiam Girdwood 	} else
7991f88eb0fSCharles Keepax 		memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));
8001f88eb0fSCharles Keepax 
8011f88eb0fSCharles Keepax 	/* Add copy callback for not memory mapped DSPs */
8021f88eb0fSCharles Keepax 	if (platform->driver->compr_ops && platform->driver->compr_ops->copy)
8031f88eb0fSCharles Keepax 		compr->ops->copy = soc_compr_copy;
8041f88eb0fSCharles Keepax 
8051245b700SNamarta Kohli 	mutex_init(&compr->lock);
806e5241a8cSRichard Fitzgerald 
807e5241a8cSRichard Fitzgerald 	snprintf(new_name, sizeof(new_name), "%s %s-%d",
808e5241a8cSRichard Fitzgerald 		 rtd->dai_link->stream_name,
809e5241a8cSRichard Fitzgerald 		 rtd->codec_dai->name, num);
810e5241a8cSRichard Fitzgerald 
811e5241a8cSRichard Fitzgerald 	ret = snd_compress_new(rtd->card->snd_card, num, direction,
812e5241a8cSRichard Fitzgerald 				new_name, compr);
8131245b700SNamarta Kohli 	if (ret < 0) {
8141245b700SNamarta Kohli 		pr_err("compress asoc: can't create compress for codec %s\n",
815f4333203SLars-Peter Clausen 			codec->component.name);
8161f88eb0fSCharles Keepax 		goto compr_err;
8171245b700SNamarta Kohli 	}
8181245b700SNamarta Kohli 
819202c8f70SCharles Keepax 	/* DAPM dai link stream work */
820202c8f70SCharles Keepax 	INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
821202c8f70SCharles Keepax 
8221245b700SNamarta Kohli 	rtd->compr = compr;
8231245b700SNamarta Kohli 	compr->private_data = rtd;
8241245b700SNamarta Kohli 
8251245b700SNamarta Kohli 	printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name,
8261245b700SNamarta Kohli 		cpu_dai->name);
8271245b700SNamarta Kohli 	return ret;
8281f88eb0fSCharles Keepax 
8291f88eb0fSCharles Keepax compr_err:
8301f88eb0fSCharles Keepax 	kfree(compr);
8311f88eb0fSCharles Keepax 	return ret;
8321245b700SNamarta Kohli }
8336f0c4226SJie Yang EXPORT_SYMBOL_GPL(snd_soc_new_compress);
834