xref: /openbmc/linux/sound/soc/soc-compress.c (revision 1c531230)
1b3ed4c86SKuninori Morimoto // SPDX-License-Identifier: GPL-2.0+
2b3ed4c86SKuninori Morimoto //
3b3ed4c86SKuninori Morimoto // soc-compress.c  --  ALSA SoC Compress
4b3ed4c86SKuninori Morimoto //
5b3ed4c86SKuninori Morimoto // Copyright (C) 2012 Intel Corp.
6b3ed4c86SKuninori Morimoto //
7b3ed4c86SKuninori Morimoto // Authors: Namarta Kohli <namartax.kohli@intel.com>
8b3ed4c86SKuninori Morimoto //          Ramesh Babu K V <ramesh.babu@linux.intel.com>
9b3ed4c86SKuninori Morimoto //          Vinod Koul <vinod.koul@linux.intel.com>
101245b700SNamarta Kohli 
111245b700SNamarta Kohli #include <linux/kernel.h>
121245b700SNamarta Kohli #include <linux/init.h>
131245b700SNamarta Kohli #include <linux/delay.h>
141245b700SNamarta Kohli #include <linux/slab.h>
151245b700SNamarta Kohli #include <linux/workqueue.h>
161245b700SNamarta Kohli #include <sound/core.h>
171245b700SNamarta Kohli #include <sound/compress_params.h>
181245b700SNamarta Kohli #include <sound/compress_driver.h>
191245b700SNamarta Kohli #include <sound/soc.h>
201245b700SNamarta Kohli #include <sound/initval.h>
212a99ef0fSLiam Girdwood #include <sound/soc-dpcm.h>
224137f4b6SCezary Rojewski #include <linux/pm_runtime.h>
231245b700SNamarta Kohli 
241e57b828SCharles Keepax static int soc_compr_components_open(struct snd_compr_stream *cstream,
251e57b828SCharles Keepax 				     struct snd_soc_component **last)
261245b700SNamarta Kohli {
271245b700SNamarta Kohli 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
289e7e3738SKuninori Morimoto 	struct snd_soc_component *component;
29613fb500SKuninori Morimoto 	int i, ret;
301e57b828SCharles Keepax 
31613fb500SKuninori Morimoto 	for_each_rtd_components(rtd, i, component) {
321e57b828SCharles Keepax 		if (!component->driver->compr_ops ||
331e57b828SCharles Keepax 		    !component->driver->compr_ops->open)
341e57b828SCharles Keepax 			continue;
351e57b828SCharles Keepax 
361e57b828SCharles Keepax 		ret = component->driver->compr_ops->open(cstream);
371e57b828SCharles Keepax 		if (ret < 0) {
381e57b828SCharles Keepax 			dev_err(component->dev,
391e57b828SCharles Keepax 				"Compress ASoC: can't open platform %s: %d\n",
401e57b828SCharles Keepax 				component->name, ret);
411e57b828SCharles Keepax 
421e57b828SCharles Keepax 			*last = component;
431e57b828SCharles Keepax 			return ret;
441e57b828SCharles Keepax 		}
451e57b828SCharles Keepax 	}
461e57b828SCharles Keepax 
471e57b828SCharles Keepax 	*last = NULL;
481e57b828SCharles Keepax 	return 0;
491e57b828SCharles Keepax }
501e57b828SCharles Keepax 
511e57b828SCharles Keepax static int soc_compr_components_free(struct snd_compr_stream *cstream,
521e57b828SCharles Keepax 				     struct snd_soc_component *last)
531e57b828SCharles Keepax {
541e57b828SCharles Keepax 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
551e57b828SCharles Keepax 	struct snd_soc_component *component;
56613fb500SKuninori Morimoto 	int i;
571e57b828SCharles Keepax 
58613fb500SKuninori Morimoto 	for_each_rtd_components(rtd, i, component) {
591e57b828SCharles Keepax 		if (component == last)
601e57b828SCharles Keepax 			break;
611e57b828SCharles Keepax 
621e57b828SCharles Keepax 		if (!component->driver->compr_ops ||
631e57b828SCharles Keepax 		    !component->driver->compr_ops->free)
641e57b828SCharles Keepax 			continue;
651e57b828SCharles Keepax 
661e57b828SCharles Keepax 		component->driver->compr_ops->free(cstream);
671e57b828SCharles Keepax 	}
681e57b828SCharles Keepax 
691e57b828SCharles Keepax 	return 0;
701e57b828SCharles Keepax }
711e57b828SCharles Keepax 
721e57b828SCharles Keepax static int soc_compr_open(struct snd_compr_stream *cstream)
731e57b828SCharles Keepax {
741e57b828SCharles Keepax 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
754137f4b6SCezary Rojewski 	struct snd_soc_component *component, *save = NULL;
762e622ae4SVinod Koul 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
77613fb500SKuninori Morimoto 	int ret, i;
781245b700SNamarta Kohli 
79613fb500SKuninori Morimoto 	for_each_rtd_components(rtd, i, component) {
804137f4b6SCezary Rojewski 		ret = pm_runtime_get_sync(component->dev);
814137f4b6SCezary Rojewski 		if (ret < 0 && ret != -EACCES) {
824137f4b6SCezary Rojewski 			pm_runtime_put_noidle(component->dev);
834137f4b6SCezary Rojewski 			save = component;
844137f4b6SCezary Rojewski 			goto pm_err;
854137f4b6SCezary Rojewski 		}
864137f4b6SCezary Rojewski 	}
874137f4b6SCezary Rojewski 
8872b745e3SPeter Ujfalusi 	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
8915e2e619SCharles Keepax 
902e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) {
912e622ae4SVinod Koul 		ret = cpu_dai->driver->cops->startup(cstream, cpu_dai);
922e622ae4SVinod Koul 		if (ret < 0) {
93141dfc9eSCharles Keepax 			dev_err(cpu_dai->dev,
94141dfc9eSCharles Keepax 				"Compress ASoC: can't open interface %s: %d\n",
952e622ae4SVinod Koul 				cpu_dai->name, ret);
962e622ae4SVinod Koul 			goto out;
972e622ae4SVinod Koul 		}
982e622ae4SVinod Koul 	}
992e622ae4SVinod Koul 
1001e57b828SCharles Keepax 	ret = soc_compr_components_open(cstream, &component);
1011e57b828SCharles Keepax 	if (ret < 0)
1029e7e3738SKuninori Morimoto 		goto machine_err;
1039e7e3738SKuninori Morimoto 
1041245b700SNamarta Kohli 	if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->startup) {
1051245b700SNamarta Kohli 		ret = rtd->dai_link->compr_ops->startup(cstream);
1061245b700SNamarta Kohli 		if (ret < 0) {
107141dfc9eSCharles Keepax 			dev_err(rtd->dev,
108141dfc9eSCharles Keepax 				"Compress ASoC: %s startup failed: %d\n",
109141dfc9eSCharles Keepax 				rtd->dai_link->name, ret);
1101245b700SNamarta Kohli 			goto machine_err;
1111245b700SNamarta Kohli 		}
1121245b700SNamarta Kohli 	}
1131245b700SNamarta Kohli 
11424894b76SLars-Peter Clausen 	snd_soc_runtime_activate(rtd, cstream->direction);
1151245b700SNamarta Kohli 
11672b745e3SPeter Ujfalusi 	mutex_unlock(&rtd->card->pcm_mutex);
11715e2e619SCharles Keepax 
1181245b700SNamarta Kohli 	return 0;
1191245b700SNamarta Kohli 
1201245b700SNamarta Kohli machine_err:
1211e57b828SCharles Keepax 	soc_compr_components_free(cstream, component);
1229e7e3738SKuninori Morimoto 
1232e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
1242e622ae4SVinod Koul 		cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
1251245b700SNamarta Kohli out:
12672b745e3SPeter Ujfalusi 	mutex_unlock(&rtd->card->pcm_mutex);
1274137f4b6SCezary Rojewski pm_err:
128613fb500SKuninori Morimoto 	for_each_rtd_components(rtd, i, component) {
1294137f4b6SCezary Rojewski 		if (component == save)
1304137f4b6SCezary Rojewski 			break;
1314137f4b6SCezary Rojewski 		pm_runtime_mark_last_busy(component->dev);
1324137f4b6SCezary Rojewski 		pm_runtime_put_autosuspend(component->dev);
1334137f4b6SCezary Rojewski 	}
1344137f4b6SCezary Rojewski 
1351245b700SNamarta Kohli 	return ret;
1361245b700SNamarta Kohli }
1371245b700SNamarta Kohli 
1382a99ef0fSLiam Girdwood static int soc_compr_open_fe(struct snd_compr_stream *cstream)
1392a99ef0fSLiam Girdwood {
1402a99ef0fSLiam Girdwood 	struct snd_soc_pcm_runtime *fe = cstream->private_data;
14101b8cedfSSatish Babu Patakokila 	struct snd_pcm_substream *fe_substream =
14201b8cedfSSatish Babu Patakokila 		 fe->pcm->streams[cstream->direction].substream;
1439e7e3738SKuninori Morimoto 	struct snd_soc_component *component;
1442e622ae4SVinod Koul 	struct snd_soc_dai *cpu_dai = fe->cpu_dai;
1452a99ef0fSLiam Girdwood 	struct snd_soc_dpcm *dpcm;
1462a99ef0fSLiam Girdwood 	struct snd_soc_dapm_widget_list *list;
1472a99ef0fSLiam Girdwood 	int stream;
148572e6c8dSCharles Keepax 	int ret;
1492a99ef0fSLiam Girdwood 
1502a99ef0fSLiam Girdwood 	if (cstream->direction == SND_COMPRESS_PLAYBACK)
1512a99ef0fSLiam Girdwood 		stream = SNDRV_PCM_STREAM_PLAYBACK;
1522a99ef0fSLiam Girdwood 	else
1532a99ef0fSLiam Girdwood 		stream = SNDRV_PCM_STREAM_CAPTURE;
1542a99ef0fSLiam Girdwood 
1552a99ef0fSLiam Girdwood 	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
1560b0722e1SSrinivas Kandagatla 	fe->dpcm[stream].runtime = fe_substream->runtime;
1570b0722e1SSrinivas Kandagatla 
1580b0722e1SSrinivas Kandagatla 	ret = dpcm_path_get(fe, stream, &list);
1590b0722e1SSrinivas Kandagatla 	if (ret < 0)
1600b0722e1SSrinivas Kandagatla 		goto be_err;
1610b0722e1SSrinivas Kandagatla 	else if (ret == 0)
1620b0722e1SSrinivas Kandagatla 		dev_dbg(fe->dev, "Compress ASoC: %s no valid %s route\n",
1630b0722e1SSrinivas Kandagatla 			fe->dai_link->name, stream ? "capture" : "playback");
1640b0722e1SSrinivas Kandagatla 	/* calculate valid and active FE <-> BE dpcms */
1650b0722e1SSrinivas Kandagatla 	dpcm_process_paths(fe, stream, &list, 1);
1660b0722e1SSrinivas Kandagatla 	fe->dpcm[stream].runtime = fe_substream->runtime;
1670b0722e1SSrinivas Kandagatla 
1680b0722e1SSrinivas Kandagatla 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
1690b0722e1SSrinivas Kandagatla 
1700b0722e1SSrinivas Kandagatla 	ret = dpcm_be_dai_startup(fe, stream);
1710b0722e1SSrinivas Kandagatla 	if (ret < 0) {
1720b0722e1SSrinivas Kandagatla 		/* clean up all links */
1738d6258a4SKuninori Morimoto 		for_each_dpcm_be(fe, stream, dpcm)
1740b0722e1SSrinivas Kandagatla 			dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
1750b0722e1SSrinivas Kandagatla 
1760b0722e1SSrinivas Kandagatla 		dpcm_be_disconnect(fe, stream);
1770b0722e1SSrinivas Kandagatla 		fe->dpcm[stream].runtime = NULL;
1780b0722e1SSrinivas Kandagatla 		goto out;
1790b0722e1SSrinivas Kandagatla 	}
1802a99ef0fSLiam Girdwood 
1812e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) {
1822e622ae4SVinod Koul 		ret = cpu_dai->driver->cops->startup(cstream, cpu_dai);
1832e622ae4SVinod Koul 		if (ret < 0) {
184141dfc9eSCharles Keepax 			dev_err(cpu_dai->dev,
185141dfc9eSCharles Keepax 				"Compress ASoC: can't open interface %s: %d\n",
1862e622ae4SVinod Koul 				cpu_dai->name, ret);
1872e622ae4SVinod Koul 			goto out;
1882e622ae4SVinod Koul 		}
1892e622ae4SVinod Koul 	}
1902e622ae4SVinod Koul 
1911e57b828SCharles Keepax 	ret = soc_compr_components_open(cstream, &component);
1921e57b828SCharles Keepax 	if (ret < 0)
1930b0722e1SSrinivas Kandagatla 		goto open_err;
1949e7e3738SKuninori Morimoto 
1952a99ef0fSLiam Girdwood 	if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->startup) {
1962a99ef0fSLiam Girdwood 		ret = fe->dai_link->compr_ops->startup(cstream);
1972a99ef0fSLiam Girdwood 		if (ret < 0) {
198141dfc9eSCharles Keepax 			pr_err("Compress ASoC: %s startup failed: %d\n",
199141dfc9eSCharles Keepax 			       fe->dai_link->name, ret);
2002a99ef0fSLiam Girdwood 			goto machine_err;
2012a99ef0fSLiam Girdwood 		}
2022a99ef0fSLiam Girdwood 	}
2032a99ef0fSLiam Girdwood 
2042a99ef0fSLiam Girdwood 	dpcm_clear_pending_state(fe, stream);
2052a99ef0fSLiam Girdwood 	dpcm_path_put(&list);
2062a99ef0fSLiam Girdwood 
2072a99ef0fSLiam Girdwood 	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
2082a99ef0fSLiam Girdwood 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
2092a99ef0fSLiam Girdwood 
21024894b76SLars-Peter Clausen 	snd_soc_runtime_activate(fe, stream);
2112a99ef0fSLiam Girdwood 
2122a99ef0fSLiam Girdwood 	mutex_unlock(&fe->card->mutex);
2132a99ef0fSLiam Girdwood 
2142a99ef0fSLiam Girdwood 	return 0;
2152a99ef0fSLiam Girdwood 
2162a99ef0fSLiam Girdwood machine_err:
2171e57b828SCharles Keepax 	soc_compr_components_free(cstream, component);
2180b0722e1SSrinivas Kandagatla open_err:
2192e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
2202e622ae4SVinod Koul 		cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
2212a99ef0fSLiam Girdwood out:
2220b0722e1SSrinivas Kandagatla 	dpcm_path_put(&list);
2230b0722e1SSrinivas Kandagatla be_err:
2242a99ef0fSLiam Girdwood 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
2252a99ef0fSLiam Girdwood 	mutex_unlock(&fe->card->mutex);
2262a99ef0fSLiam Girdwood 	return ret;
2272a99ef0fSLiam Girdwood }
2282a99ef0fSLiam Girdwood 
2291245b700SNamarta Kohli static int soc_compr_free(struct snd_compr_stream *cstream)
2301245b700SNamarta Kohli {
2311245b700SNamarta Kohli 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
2324137f4b6SCezary Rojewski 	struct snd_soc_component *component;
2331245b700SNamarta Kohli 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
2341245b700SNamarta Kohli 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
235613fb500SKuninori Morimoto 	int stream, i;
2361245b700SNamarta Kohli 
23772b745e3SPeter Ujfalusi 	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
23815e2e619SCharles Keepax 
23924894b76SLars-Peter Clausen 	if (cstream->direction == SND_COMPRESS_PLAYBACK)
24024894b76SLars-Peter Clausen 		stream = SNDRV_PCM_STREAM_PLAYBACK;
24124894b76SLars-Peter Clausen 	else
24224894b76SLars-Peter Clausen 		stream = SNDRV_PCM_STREAM_CAPTURE;
24324894b76SLars-Peter Clausen 
24424894b76SLars-Peter Clausen 	snd_soc_runtime_deactivate(rtd, stream);
2451245b700SNamarta Kohli 
246da18396fSMark Brown 	snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
247da18396fSMark Brown 
2481245b700SNamarta Kohli 	if (!cpu_dai->active)
2491245b700SNamarta Kohli 		cpu_dai->rate = 0;
2501245b700SNamarta Kohli 
2511245b700SNamarta Kohli 	if (!codec_dai->active)
2521245b700SNamarta Kohli 		codec_dai->rate = 0;
2531245b700SNamarta Kohli 
2541245b700SNamarta Kohli 	if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown)
2551245b700SNamarta Kohli 		rtd->dai_link->compr_ops->shutdown(cstream);
2561245b700SNamarta Kohli 
2571e57b828SCharles Keepax 	soc_compr_components_free(cstream, NULL);
2589e7e3738SKuninori Morimoto 
2592e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
2602e622ae4SVinod Koul 		cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
2612e622ae4SVinod Koul 
2623f4cf797SKuninori Morimoto 	snd_soc_dapm_stream_stop(rtd, stream);
2631245b700SNamarta Kohli 
26472b745e3SPeter Ujfalusi 	mutex_unlock(&rtd->card->pcm_mutex);
2654137f4b6SCezary Rojewski 
266613fb500SKuninori Morimoto 	for_each_rtd_components(rtd, i, component) {
2674137f4b6SCezary Rojewski 		pm_runtime_mark_last_busy(component->dev);
2684137f4b6SCezary Rojewski 		pm_runtime_put_autosuspend(component->dev);
2694137f4b6SCezary Rojewski 	}
2704137f4b6SCezary Rojewski 
2711245b700SNamarta Kohli 	return 0;
2721245b700SNamarta Kohli }
2731245b700SNamarta Kohli 
2742a99ef0fSLiam Girdwood static int soc_compr_free_fe(struct snd_compr_stream *cstream)
2752a99ef0fSLiam Girdwood {
2762a99ef0fSLiam Girdwood 	struct snd_soc_pcm_runtime *fe = cstream->private_data;
2772e622ae4SVinod Koul 	struct snd_soc_dai *cpu_dai = fe->cpu_dai;
2782a99ef0fSLiam Girdwood 	struct snd_soc_dpcm *dpcm;
2792a99ef0fSLiam Girdwood 	int stream, ret;
2802a99ef0fSLiam Girdwood 
2812a99ef0fSLiam Girdwood 	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
2822a99ef0fSLiam Girdwood 
28324894b76SLars-Peter Clausen 	if (cstream->direction == SND_COMPRESS_PLAYBACK)
2842a99ef0fSLiam Girdwood 		stream = SNDRV_PCM_STREAM_PLAYBACK;
28524894b76SLars-Peter Clausen 	else
2862a99ef0fSLiam Girdwood 		stream = SNDRV_PCM_STREAM_CAPTURE;
2872a99ef0fSLiam Girdwood 
28824894b76SLars-Peter Clausen 	snd_soc_runtime_deactivate(fe, stream);
2892a99ef0fSLiam Girdwood 
2902a99ef0fSLiam Girdwood 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
2912a99ef0fSLiam Girdwood 
2922a99ef0fSLiam Girdwood 	ret = dpcm_be_dai_hw_free(fe, stream);
2932a99ef0fSLiam Girdwood 	if (ret < 0)
294141dfc9eSCharles Keepax 		dev_err(fe->dev, "Compressed ASoC: hw_free failed: %d\n", ret);
2952a99ef0fSLiam Girdwood 
2962a99ef0fSLiam Girdwood 	ret = dpcm_be_dai_shutdown(fe, stream);
2972a99ef0fSLiam Girdwood 
2982a99ef0fSLiam Girdwood 	/* mark FE's links ready to prune */
2998d6258a4SKuninori Morimoto 	for_each_dpcm_be(fe, stream, dpcm)
3002a99ef0fSLiam Girdwood 		dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
3012a99ef0fSLiam Girdwood 
3021c531230SKuninori Morimoto 	dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
3032a99ef0fSLiam Girdwood 
3042a99ef0fSLiam Girdwood 	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
3052a99ef0fSLiam Girdwood 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
3062a99ef0fSLiam Girdwood 
3072a99ef0fSLiam Girdwood 	dpcm_be_disconnect(fe, stream);
3082a99ef0fSLiam Girdwood 
3092a99ef0fSLiam Girdwood 	fe->dpcm[stream].runtime = NULL;
3102a99ef0fSLiam Girdwood 
3112a99ef0fSLiam Girdwood 	if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
3122a99ef0fSLiam Girdwood 		fe->dai_link->compr_ops->shutdown(cstream);
3132a99ef0fSLiam Girdwood 
3141e57b828SCharles Keepax 	soc_compr_components_free(cstream, NULL);
3159e7e3738SKuninori Morimoto 
3162e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
3172e622ae4SVinod Koul 		cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
3182e622ae4SVinod Koul 
3192a99ef0fSLiam Girdwood 	mutex_unlock(&fe->card->mutex);
3202a99ef0fSLiam Girdwood 	return 0;
3212a99ef0fSLiam Girdwood }
3222a99ef0fSLiam Girdwood 
3234ef0ecb8SCharles Keepax static int soc_compr_components_trigger(struct snd_compr_stream *cstream,
3244ef0ecb8SCharles Keepax 					int cmd)
3251245b700SNamarta Kohli {
3261245b700SNamarta Kohli 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
3279e7e3738SKuninori Morimoto 	struct snd_soc_component *component;
328613fb500SKuninori Morimoto 	int i, ret;
32915e2e619SCharles Keepax 
330613fb500SKuninori Morimoto 	for_each_rtd_components(rtd, i, component) {
3319e7e3738SKuninori Morimoto 		if (!component->driver->compr_ops ||
3329e7e3738SKuninori Morimoto 		    !component->driver->compr_ops->trigger)
3339e7e3738SKuninori Morimoto 			continue;
3349e7e3738SKuninori Morimoto 
33552cadf1fSCharles Keepax 		ret = component->driver->compr_ops->trigger(cstream, cmd);
3369e7e3738SKuninori Morimoto 		if (ret < 0)
3374ef0ecb8SCharles Keepax 			return ret;
33852cadf1fSCharles Keepax 	}
3399e7e3738SKuninori Morimoto 
3404ef0ecb8SCharles Keepax 	return 0;
3414ef0ecb8SCharles Keepax }
3424ef0ecb8SCharles Keepax 
3434ef0ecb8SCharles Keepax static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
3444ef0ecb8SCharles Keepax {
3454ef0ecb8SCharles Keepax 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
3464ef0ecb8SCharles Keepax 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
3474ef0ecb8SCharles Keepax 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
3484ef0ecb8SCharles Keepax 	int ret;
3494ef0ecb8SCharles Keepax 
35072b745e3SPeter Ujfalusi 	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
3514ef0ecb8SCharles Keepax 
3524ef0ecb8SCharles Keepax 	ret = soc_compr_components_trigger(cstream, cmd);
3534ef0ecb8SCharles Keepax 	if (ret < 0)
3544ef0ecb8SCharles Keepax 		goto out;
3554ef0ecb8SCharles Keepax 
3562e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger)
3572e622ae4SVinod Koul 		cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai);
3582e622ae4SVinod Koul 
359e38b9b74SMark Brown 	switch (cmd) {
360e38b9b74SMark Brown 	case SNDRV_PCM_TRIGGER_START:
361da18396fSMark Brown 		snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction);
362e38b9b74SMark Brown 		break;
363e38b9b74SMark Brown 	case SNDRV_PCM_TRIGGER_STOP:
364da18396fSMark Brown 		snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
365e38b9b74SMark Brown 		break;
366e38b9b74SMark Brown 	}
3671245b700SNamarta Kohli 
36815e2e619SCharles Keepax out:
36972b745e3SPeter Ujfalusi 	mutex_unlock(&rtd->card->pcm_mutex);
3701245b700SNamarta Kohli 	return ret;
3711245b700SNamarta Kohli }
3721245b700SNamarta Kohli 
3732a99ef0fSLiam Girdwood static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
3742a99ef0fSLiam Girdwood {
3752a99ef0fSLiam Girdwood 	struct snd_soc_pcm_runtime *fe = cstream->private_data;
3762e622ae4SVinod Koul 	struct snd_soc_dai *cpu_dai = fe->cpu_dai;
37752cadf1fSCharles Keepax 	int ret, stream;
3782a99ef0fSLiam Girdwood 
3792a99ef0fSLiam Girdwood 	if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN ||
3804ef0ecb8SCharles Keepax 	    cmd == SND_COMPR_TRIGGER_DRAIN)
3814ef0ecb8SCharles Keepax 		return soc_compr_components_trigger(cstream, cmd);
3822a99ef0fSLiam Girdwood 
3832a99ef0fSLiam Girdwood 	if (cstream->direction == SND_COMPRESS_PLAYBACK)
3842a99ef0fSLiam Girdwood 		stream = SNDRV_PCM_STREAM_PLAYBACK;
3852a99ef0fSLiam Girdwood 	else
3862a99ef0fSLiam Girdwood 		stream = SNDRV_PCM_STREAM_CAPTURE;
3872a99ef0fSLiam Girdwood 
3882a99ef0fSLiam Girdwood 	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
3892a99ef0fSLiam Girdwood 
3902e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) {
3912e622ae4SVinod Koul 		ret = cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai);
3922e622ae4SVinod Koul 		if (ret < 0)
3932e622ae4SVinod Koul 			goto out;
3942e622ae4SVinod Koul 	}
3952e622ae4SVinod Koul 
3964ef0ecb8SCharles Keepax 	ret = soc_compr_components_trigger(cstream, cmd);
3979e7e3738SKuninori Morimoto 	if (ret < 0)
3989e7e3738SKuninori Morimoto 		goto out;
3999e7e3738SKuninori Morimoto 
4002a99ef0fSLiam Girdwood 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
4012a99ef0fSLiam Girdwood 
4022a99ef0fSLiam Girdwood 	ret = dpcm_be_dai_trigger(fe, stream, cmd);
4032a99ef0fSLiam Girdwood 
4042a99ef0fSLiam Girdwood 	switch (cmd) {
4052a99ef0fSLiam Girdwood 	case SNDRV_PCM_TRIGGER_START:
4062a99ef0fSLiam Girdwood 	case SNDRV_PCM_TRIGGER_RESUME:
4072a99ef0fSLiam Girdwood 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
4082a99ef0fSLiam Girdwood 		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
4092a99ef0fSLiam Girdwood 		break;
4102a99ef0fSLiam Girdwood 	case SNDRV_PCM_TRIGGER_STOP:
4112a99ef0fSLiam Girdwood 	case SNDRV_PCM_TRIGGER_SUSPEND:
4122a99ef0fSLiam Girdwood 		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
4132a99ef0fSLiam Girdwood 		break;
4142a99ef0fSLiam Girdwood 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
4152a99ef0fSLiam Girdwood 		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
4162a99ef0fSLiam Girdwood 		break;
4172a99ef0fSLiam Girdwood 	}
4182a99ef0fSLiam Girdwood 
4192a99ef0fSLiam Girdwood out:
4202a99ef0fSLiam Girdwood 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
4212a99ef0fSLiam Girdwood 	mutex_unlock(&fe->card->mutex);
4222a99ef0fSLiam Girdwood 	return ret;
4232a99ef0fSLiam Girdwood }
4242a99ef0fSLiam Girdwood 
4254ef0ecb8SCharles Keepax static int soc_compr_components_set_params(struct snd_compr_stream *cstream,
4261245b700SNamarta Kohli 					   struct snd_compr_params *params)
4271245b700SNamarta Kohli {
4281245b700SNamarta Kohli 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
4299e7e3738SKuninori Morimoto 	struct snd_soc_component *component;
430613fb500SKuninori Morimoto 	int i, ret;
4314ef0ecb8SCharles Keepax 
432613fb500SKuninori Morimoto 	for_each_rtd_components(rtd, i, component) {
4334ef0ecb8SCharles Keepax 		if (!component->driver->compr_ops ||
4344ef0ecb8SCharles Keepax 		    !component->driver->compr_ops->set_params)
4354ef0ecb8SCharles Keepax 			continue;
4364ef0ecb8SCharles Keepax 
4374ef0ecb8SCharles Keepax 		ret = component->driver->compr_ops->set_params(cstream, params);
4384ef0ecb8SCharles Keepax 		if (ret < 0)
4394ef0ecb8SCharles Keepax 			return ret;
4404ef0ecb8SCharles Keepax 	}
4414ef0ecb8SCharles Keepax 
4424ef0ecb8SCharles Keepax 	return 0;
4434ef0ecb8SCharles Keepax }
4444ef0ecb8SCharles Keepax 
4454ef0ecb8SCharles Keepax static int soc_compr_set_params(struct snd_compr_stream *cstream,
4464ef0ecb8SCharles Keepax 				struct snd_compr_params *params)
4474ef0ecb8SCharles Keepax {
4484ef0ecb8SCharles Keepax 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
4492e622ae4SVinod Koul 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
45052cadf1fSCharles Keepax 	int ret;
4511245b700SNamarta Kohli 
45272b745e3SPeter Ujfalusi 	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
45315e2e619SCharles Keepax 
454ef050becSCharles Keepax 	/*
455ef050becSCharles Keepax 	 * First we call set_params for the CPU DAI, then the component
456ef050becSCharles Keepax 	 * driver this should configure the SoC side. If the machine has
457ef050becSCharles Keepax 	 * compressed ops then we call that as well. The expectation is
458ef050becSCharles Keepax 	 * that these callbacks will configure everything for this compress
459ef050becSCharles Keepax 	 * path, like configuring a PCM port for a CODEC.
4601245b700SNamarta Kohli 	 */
4612e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) {
4622e622ae4SVinod Koul 		ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai);
4632e622ae4SVinod Koul 		if (ret < 0)
4642e622ae4SVinod Koul 			goto err;
4652e622ae4SVinod Koul 	}
4662e622ae4SVinod Koul 
4674ef0ecb8SCharles Keepax 	ret = soc_compr_components_set_params(cstream, params);
4689e7e3738SKuninori Morimoto 	if (ret < 0)
4699e7e3738SKuninori Morimoto 		goto err;
4709e7e3738SKuninori Morimoto 
4711245b700SNamarta Kohli 	if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) {
4721245b700SNamarta Kohli 		ret = rtd->dai_link->compr_ops->set_params(cstream);
4731245b700SNamarta Kohli 		if (ret < 0)
474fa40ef20SCharles Keepax 			goto err;
4751245b700SNamarta Kohli 	}
4761245b700SNamarta Kohli 
4772c071ed7SCharles Keepax 	if (cstream->direction == SND_COMPRESS_PLAYBACK)
4781245b700SNamarta Kohli 		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
4791245b700SNamarta Kohli 					  SND_SOC_DAPM_STREAM_START);
4802c071ed7SCharles Keepax 	else
4812c071ed7SCharles Keepax 		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
4822c071ed7SCharles Keepax 					  SND_SOC_DAPM_STREAM_START);
4831245b700SNamarta Kohli 
484fa40ef20SCharles Keepax 	/* cancel any delayed stream shutdown that is pending */
485fa40ef20SCharles Keepax 	rtd->pop_wait = 0;
48672b745e3SPeter Ujfalusi 	mutex_unlock(&rtd->card->pcm_mutex);
487fa40ef20SCharles Keepax 
488fa40ef20SCharles Keepax 	cancel_delayed_work_sync(&rtd->delayed_work);
489fa40ef20SCharles Keepax 
49052cadf1fSCharles Keepax 	return 0;
491fa40ef20SCharles Keepax 
492fa40ef20SCharles Keepax err:
49372b745e3SPeter Ujfalusi 	mutex_unlock(&rtd->card->pcm_mutex);
4941245b700SNamarta Kohli 	return ret;
4951245b700SNamarta Kohli }
4961245b700SNamarta Kohli 
4972a99ef0fSLiam Girdwood static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
4982a99ef0fSLiam Girdwood 				   struct snd_compr_params *params)
4992a99ef0fSLiam Girdwood {
5002a99ef0fSLiam Girdwood 	struct snd_soc_pcm_runtime *fe = cstream->private_data;
50101b8cedfSSatish Babu Patakokila 	struct snd_pcm_substream *fe_substream =
50201b8cedfSSatish Babu Patakokila 		 fe->pcm->streams[cstream->direction].substream;
5032e622ae4SVinod Koul 	struct snd_soc_dai *cpu_dai = fe->cpu_dai;
50452cadf1fSCharles Keepax 	int ret, stream;
5052a99ef0fSLiam Girdwood 
5062a99ef0fSLiam Girdwood 	if (cstream->direction == SND_COMPRESS_PLAYBACK)
5072a99ef0fSLiam Girdwood 		stream = SNDRV_PCM_STREAM_PLAYBACK;
5082a99ef0fSLiam Girdwood 	else
5092a99ef0fSLiam Girdwood 		stream = SNDRV_PCM_STREAM_CAPTURE;
5102a99ef0fSLiam Girdwood 
5112a99ef0fSLiam Girdwood 	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
5122a99ef0fSLiam Girdwood 
5130b0722e1SSrinivas Kandagatla 	/*
5140b0722e1SSrinivas Kandagatla 	 * Create an empty hw_params for the BE as the machine driver must
5150b0722e1SSrinivas Kandagatla 	 * fix this up to match DSP decoder and ASRC configuration.
5160b0722e1SSrinivas Kandagatla 	 * I.e. machine driver fixup for compressed BE is mandatory.
5170b0722e1SSrinivas Kandagatla 	 */
5180b0722e1SSrinivas Kandagatla 	memset(&fe->dpcm[fe_substream->stream].hw_params, 0,
5190b0722e1SSrinivas Kandagatla 		sizeof(struct snd_pcm_hw_params));
5200b0722e1SSrinivas Kandagatla 
5210b0722e1SSrinivas Kandagatla 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
5220b0722e1SSrinivas Kandagatla 
5230b0722e1SSrinivas Kandagatla 	ret = dpcm_be_dai_hw_params(fe, stream);
5240b0722e1SSrinivas Kandagatla 	if (ret < 0)
5250b0722e1SSrinivas Kandagatla 		goto out;
5260b0722e1SSrinivas Kandagatla 
5270b0722e1SSrinivas Kandagatla 	ret = dpcm_be_dai_prepare(fe, stream);
5280b0722e1SSrinivas Kandagatla 	if (ret < 0)
5290b0722e1SSrinivas Kandagatla 		goto out;
5300b0722e1SSrinivas Kandagatla 
5312e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) {
5322e622ae4SVinod Koul 		ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai);
5332e622ae4SVinod Koul 		if (ret < 0)
5342e622ae4SVinod Koul 			goto out;
5352e622ae4SVinod Koul 	}
5362e622ae4SVinod Koul 
5374ef0ecb8SCharles Keepax 	ret = soc_compr_components_set_params(cstream, params);
5389e7e3738SKuninori Morimoto 	if (ret < 0)
5399e7e3738SKuninori Morimoto 		goto out;
5409e7e3738SKuninori Morimoto 
5412a99ef0fSLiam Girdwood 	if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) {
5422a99ef0fSLiam Girdwood 		ret = fe->dai_link->compr_ops->set_params(cstream);
5432a99ef0fSLiam Girdwood 		if (ret < 0)
5442a99ef0fSLiam Girdwood 			goto out;
5452a99ef0fSLiam Girdwood 	}
5462a99ef0fSLiam Girdwood 
5472a99ef0fSLiam Girdwood 	dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
5482a99ef0fSLiam Girdwood 	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
5492a99ef0fSLiam Girdwood 
5502a99ef0fSLiam Girdwood out:
5512a99ef0fSLiam Girdwood 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
5522a99ef0fSLiam Girdwood 	mutex_unlock(&fe->card->mutex);
5532a99ef0fSLiam Girdwood 	return ret;
5542a99ef0fSLiam Girdwood }
5552a99ef0fSLiam Girdwood 
5561245b700SNamarta Kohli static int soc_compr_get_params(struct snd_compr_stream *cstream,
5571245b700SNamarta Kohli 				struct snd_codec *params)
5581245b700SNamarta Kohli {
5591245b700SNamarta Kohli 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
5609e7e3738SKuninori Morimoto 	struct snd_soc_component *component;
5612e622ae4SVinod Koul 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
562613fb500SKuninori Morimoto 	int i, ret = 0;
5631245b700SNamarta Kohli 
56472b745e3SPeter Ujfalusi 	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
56515e2e619SCharles Keepax 
5662e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_params) {
5672e622ae4SVinod Koul 		ret = cpu_dai->driver->cops->get_params(cstream, params, cpu_dai);
5682e622ae4SVinod Koul 		if (ret < 0)
5692e622ae4SVinod Koul 			goto err;
5702e622ae4SVinod Koul 	}
5712e622ae4SVinod Koul 
572613fb500SKuninori Morimoto 	for_each_rtd_components(rtd, i, component) {
5739e7e3738SKuninori Morimoto 		if (!component->driver->compr_ops ||
5749e7e3738SKuninori Morimoto 		    !component->driver->compr_ops->get_params)
5759e7e3738SKuninori Morimoto 			continue;
5769e7e3738SKuninori Morimoto 
57752cadf1fSCharles Keepax 		ret = component->driver->compr_ops->get_params(cstream, params);
57852cadf1fSCharles Keepax 		break;
5799e7e3738SKuninori Morimoto 	}
5801245b700SNamarta Kohli 
5812e622ae4SVinod Koul err:
58272b745e3SPeter Ujfalusi 	mutex_unlock(&rtd->card->pcm_mutex);
5831245b700SNamarta Kohli 	return ret;
5841245b700SNamarta Kohli }
5851245b700SNamarta Kohli 
5861245b700SNamarta Kohli static int soc_compr_get_caps(struct snd_compr_stream *cstream,
5871245b700SNamarta Kohli 			      struct snd_compr_caps *caps)
5881245b700SNamarta Kohli {
5891245b700SNamarta Kohli 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
5909e7e3738SKuninori Morimoto 	struct snd_soc_component *component;
591613fb500SKuninori Morimoto 	int i, ret = 0;
5921245b700SNamarta Kohli 
59372b745e3SPeter Ujfalusi 	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
59415e2e619SCharles Keepax 
595613fb500SKuninori Morimoto 	for_each_rtd_components(rtd, i, component) {
5969e7e3738SKuninori Morimoto 		if (!component->driver->compr_ops ||
5979e7e3738SKuninori Morimoto 		    !component->driver->compr_ops->get_caps)
5989e7e3738SKuninori Morimoto 			continue;
5999e7e3738SKuninori Morimoto 
60052cadf1fSCharles Keepax 		ret = component->driver->compr_ops->get_caps(cstream, caps);
60152cadf1fSCharles Keepax 		break;
6029e7e3738SKuninori Morimoto 	}
6039e7e3738SKuninori Morimoto 
60472b745e3SPeter Ujfalusi 	mutex_unlock(&rtd->card->pcm_mutex);
6051245b700SNamarta Kohli 	return ret;
6061245b700SNamarta Kohli }
6071245b700SNamarta Kohli 
6081245b700SNamarta Kohli static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream,
6091245b700SNamarta Kohli 				    struct snd_compr_codec_caps *codec)
6101245b700SNamarta Kohli {
6111245b700SNamarta Kohli 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
6129e7e3738SKuninori Morimoto 	struct snd_soc_component *component;
613613fb500SKuninori Morimoto 	int i, ret = 0;
6141245b700SNamarta Kohli 
61572b745e3SPeter Ujfalusi 	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
61615e2e619SCharles Keepax 
617613fb500SKuninori Morimoto 	for_each_rtd_components(rtd, i, component) {
6189e7e3738SKuninori Morimoto 		if (!component->driver->compr_ops ||
6199e7e3738SKuninori Morimoto 		    !component->driver->compr_ops->get_codec_caps)
6209e7e3738SKuninori Morimoto 			continue;
6219e7e3738SKuninori Morimoto 
62252cadf1fSCharles Keepax 		ret = component->driver->compr_ops->get_codec_caps(cstream,
62352cadf1fSCharles Keepax 								   codec);
62452cadf1fSCharles Keepax 		break;
6259e7e3738SKuninori Morimoto 	}
6269e7e3738SKuninori Morimoto 
62772b745e3SPeter Ujfalusi 	mutex_unlock(&rtd->card->pcm_mutex);
6281245b700SNamarta Kohli 	return ret;
6291245b700SNamarta Kohli }
6301245b700SNamarta Kohli 
6311245b700SNamarta Kohli static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
6321245b700SNamarta Kohli {
6331245b700SNamarta Kohli 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
6349e7e3738SKuninori Morimoto 	struct snd_soc_component *component;
6352e622ae4SVinod Koul 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
636613fb500SKuninori Morimoto 	int i, ret = 0;
6371245b700SNamarta Kohli 
63872b745e3SPeter Ujfalusi 	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
63915e2e619SCharles Keepax 
6402e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->ack) {
6412e622ae4SVinod Koul 		ret = cpu_dai->driver->cops->ack(cstream, bytes, cpu_dai);
6422e622ae4SVinod Koul 		if (ret < 0)
6432e622ae4SVinod Koul 			goto err;
6442e622ae4SVinod Koul 	}
6452e622ae4SVinod Koul 
646613fb500SKuninori Morimoto 	for_each_rtd_components(rtd, i, component) {
6479e7e3738SKuninori Morimoto 		if (!component->driver->compr_ops ||
6489e7e3738SKuninori Morimoto 		    !component->driver->compr_ops->ack)
6499e7e3738SKuninori Morimoto 			continue;
6509e7e3738SKuninori Morimoto 
65152cadf1fSCharles Keepax 		ret = component->driver->compr_ops->ack(cstream, bytes);
65252cadf1fSCharles Keepax 		if (ret < 0)
65352cadf1fSCharles Keepax 			goto err;
6549e7e3738SKuninori Morimoto 	}
6551245b700SNamarta Kohli 
6562e622ae4SVinod Koul err:
65772b745e3SPeter Ujfalusi 	mutex_unlock(&rtd->card->pcm_mutex);
6581245b700SNamarta Kohli 	return ret;
6591245b700SNamarta Kohli }
6601245b700SNamarta Kohli 
6611245b700SNamarta Kohli static int soc_compr_pointer(struct snd_compr_stream *cstream,
6621245b700SNamarta Kohli 			     struct snd_compr_tstamp *tstamp)
6631245b700SNamarta Kohli {
6641245b700SNamarta Kohli 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
6659e7e3738SKuninori Morimoto 	struct snd_soc_component *component;
666613fb500SKuninori Morimoto 	int i, ret = 0;
6672e622ae4SVinod Koul 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
6681245b700SNamarta Kohli 
66972b745e3SPeter Ujfalusi 	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
67015e2e619SCharles Keepax 
6712e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->pointer)
6722e622ae4SVinod Koul 		cpu_dai->driver->cops->pointer(cstream, tstamp, cpu_dai);
6732e622ae4SVinod Koul 
674613fb500SKuninori Morimoto 	for_each_rtd_components(rtd, i, component) {
6759e7e3738SKuninori Morimoto 		if (!component->driver->compr_ops ||
6769e7e3738SKuninori Morimoto 		    !component->driver->compr_ops->pointer)
6779e7e3738SKuninori Morimoto 			continue;
6789e7e3738SKuninori Morimoto 
67952cadf1fSCharles Keepax 		ret = component->driver->compr_ops->pointer(cstream, tstamp);
68052cadf1fSCharles Keepax 		break;
6819e7e3738SKuninori Morimoto 	}
6829e7e3738SKuninori Morimoto 
68372b745e3SPeter Ujfalusi 	mutex_unlock(&rtd->card->pcm_mutex);
6847c9190f7SCharles Keepax 	return ret;
6851245b700SNamarta Kohli }
6861245b700SNamarta Kohli 
6871f88eb0fSCharles Keepax static int soc_compr_copy(struct snd_compr_stream *cstream,
6884daf891cSCharles Keepax 			  char __user *buf, size_t count)
6891f88eb0fSCharles Keepax {
6901f88eb0fSCharles Keepax 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
6919e7e3738SKuninori Morimoto 	struct snd_soc_component *component;
692613fb500SKuninori Morimoto 	int i, ret = 0;
6931f88eb0fSCharles Keepax 
69472b745e3SPeter Ujfalusi 	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
6951f88eb0fSCharles Keepax 
696613fb500SKuninori Morimoto 	for_each_rtd_components(rtd, i, component) {
6979e7e3738SKuninori Morimoto 		if (!component->driver->compr_ops ||
6989e7e3738SKuninori Morimoto 		    !component->driver->compr_ops->copy)
6999e7e3738SKuninori Morimoto 			continue;
7009e7e3738SKuninori Morimoto 
701290df4d3SCharles Keepax 		ret = component->driver->compr_ops->copy(cstream, buf, count);
702290df4d3SCharles Keepax 		break;
7039e7e3738SKuninori Morimoto 	}
704290df4d3SCharles Keepax 
70572b745e3SPeter Ujfalusi 	mutex_unlock(&rtd->card->pcm_mutex);
7061f88eb0fSCharles Keepax 	return ret;
7071f88eb0fSCharles Keepax }
7081f88eb0fSCharles Keepax 
70902bd90e8SVinod Koul static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
71036953d98SJeeja KP 				  struct snd_compr_metadata *metadata)
71136953d98SJeeja KP {
71236953d98SJeeja KP 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
7139e7e3738SKuninori Morimoto 	struct snd_soc_component *component;
7142e622ae4SVinod Koul 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
715613fb500SKuninori Morimoto 	int i, ret;
71636953d98SJeeja KP 
7172e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_metadata) {
7182e622ae4SVinod Koul 		ret = cpu_dai->driver->cops->set_metadata(cstream, metadata, cpu_dai);
7192e622ae4SVinod Koul 		if (ret < 0)
7202e622ae4SVinod Koul 			return ret;
7212e622ae4SVinod Koul 	}
7222e622ae4SVinod Koul 
723613fb500SKuninori Morimoto 	for_each_rtd_components(rtd, i, component) {
7249e7e3738SKuninori Morimoto 		if (!component->driver->compr_ops ||
7259e7e3738SKuninori Morimoto 		    !component->driver->compr_ops->set_metadata)
7269e7e3738SKuninori Morimoto 			continue;
7279e7e3738SKuninori Morimoto 
72852cadf1fSCharles Keepax 		ret = component->driver->compr_ops->set_metadata(cstream,
72952cadf1fSCharles Keepax 								 metadata);
73052cadf1fSCharles Keepax 		if (ret < 0)
73152cadf1fSCharles Keepax 			return ret;
7329e7e3738SKuninori Morimoto 	}
73336953d98SJeeja KP 
73452cadf1fSCharles Keepax 	return 0;
73536953d98SJeeja KP }
73636953d98SJeeja KP 
73702bd90e8SVinod Koul static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
73836953d98SJeeja KP 				  struct snd_compr_metadata *metadata)
73936953d98SJeeja KP {
74036953d98SJeeja KP 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
7419e7e3738SKuninori Morimoto 	struct snd_soc_component *component;
7422e622ae4SVinod Koul 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
743613fb500SKuninori Morimoto 	int i, ret;
74436953d98SJeeja KP 
7452e622ae4SVinod Koul 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_metadata) {
7462e622ae4SVinod Koul 		ret = cpu_dai->driver->cops->get_metadata(cstream, metadata, cpu_dai);
7472e622ae4SVinod Koul 		if (ret < 0)
7482e622ae4SVinod Koul 			return ret;
7492e622ae4SVinod Koul 	}
7502e622ae4SVinod Koul 
751613fb500SKuninori Morimoto 	for_each_rtd_components(rtd, i, component) {
7529e7e3738SKuninori Morimoto 		if (!component->driver->compr_ops ||
7539e7e3738SKuninori Morimoto 		    !component->driver->compr_ops->get_metadata)
7549e7e3738SKuninori Morimoto 			continue;
7559e7e3738SKuninori Morimoto 
75652cadf1fSCharles Keepax 		return component->driver->compr_ops->get_metadata(cstream,
75752cadf1fSCharles Keepax 								  metadata);
7589e7e3738SKuninori Morimoto 	}
75936953d98SJeeja KP 
76052cadf1fSCharles Keepax 	return 0;
76136953d98SJeeja KP }
7622a99ef0fSLiam Girdwood 
7631245b700SNamarta Kohli /* ASoC Compress operations */
7641245b700SNamarta Kohli static struct snd_compr_ops soc_compr_ops = {
7651245b700SNamarta Kohli 	.open		= soc_compr_open,
7661245b700SNamarta Kohli 	.free		= soc_compr_free,
7671245b700SNamarta Kohli 	.set_params	= soc_compr_set_params,
76802bd90e8SVinod Koul 	.set_metadata   = soc_compr_set_metadata,
76902bd90e8SVinod Koul 	.get_metadata	= soc_compr_get_metadata,
7701245b700SNamarta Kohli 	.get_params	= soc_compr_get_params,
7711245b700SNamarta Kohli 	.trigger	= soc_compr_trigger,
7721245b700SNamarta Kohli 	.pointer	= soc_compr_pointer,
7731245b700SNamarta Kohli 	.ack		= soc_compr_ack,
7741245b700SNamarta Kohli 	.get_caps	= soc_compr_get_caps,
7751245b700SNamarta Kohli 	.get_codec_caps = soc_compr_get_codec_caps
7761245b700SNamarta Kohli };
7771245b700SNamarta Kohli 
7782a99ef0fSLiam Girdwood /* ASoC Dynamic Compress operations */
7792a99ef0fSLiam Girdwood static struct snd_compr_ops soc_compr_dyn_ops = {
7802a99ef0fSLiam Girdwood 	.open		= soc_compr_open_fe,
7812a99ef0fSLiam Girdwood 	.free		= soc_compr_free_fe,
7822a99ef0fSLiam Girdwood 	.set_params	= soc_compr_set_params_fe,
7832a99ef0fSLiam Girdwood 	.get_params	= soc_compr_get_params,
7842a99ef0fSLiam Girdwood 	.set_metadata   = soc_compr_set_metadata,
7852a99ef0fSLiam Girdwood 	.get_metadata	= soc_compr_get_metadata,
7862a99ef0fSLiam Girdwood 	.trigger	= soc_compr_trigger_fe,
7872a99ef0fSLiam Girdwood 	.pointer	= soc_compr_pointer,
7882a99ef0fSLiam Girdwood 	.ack		= soc_compr_ack,
7892a99ef0fSLiam Girdwood 	.get_caps	= soc_compr_get_caps,
7902a99ef0fSLiam Girdwood 	.get_codec_caps = soc_compr_get_codec_caps
7912a99ef0fSLiam Girdwood };
7922a99ef0fSLiam Girdwood 
7936f0c4226SJie Yang /**
7946f0c4226SJie Yang  * snd_soc_new_compress - create a new compress.
7956f0c4226SJie Yang  *
7966f0c4226SJie Yang  * @rtd: The runtime for which we will create compress
7976f0c4226SJie Yang  * @num: the device index number (zero based - shared with normal PCMs)
7986f0c4226SJie Yang  *
7996f0c4226SJie Yang  * Return: 0 for success, else error.
8006f0c4226SJie Yang  */
8016f0c4226SJie Yang int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
8021245b700SNamarta Kohli {
8039e7e3738SKuninori Morimoto 	struct snd_soc_component *component;
8041245b700SNamarta Kohli 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
8051245b700SNamarta Kohli 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
8061245b700SNamarta Kohli 	struct snd_compr *compr;
8072a99ef0fSLiam Girdwood 	struct snd_pcm *be_pcm;
8081245b700SNamarta Kohli 	char new_name[64];
8091245b700SNamarta Kohli 	int ret = 0, direction = 0;
810a1068045SVinod Koul 	int playback = 0, capture = 0;
811613fb500SKuninori Morimoto 	int i;
8121245b700SNamarta Kohli 
8138151d5e6SBenoit Cousson 	if (rtd->num_codecs > 1) {
814141dfc9eSCharles Keepax 		dev_err(rtd->card->dev,
815141dfc9eSCharles Keepax 			"Compress ASoC: Multicodec not supported\n");
8168151d5e6SBenoit Cousson 		return -EINVAL;
8178151d5e6SBenoit Cousson 	}
8188151d5e6SBenoit Cousson 
8191245b700SNamarta Kohli 	/* check client and interface hw capabilities */
820467fece8SKuninori Morimoto 	if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
821467fece8SKuninori Morimoto 	    snd_soc_dai_stream_valid(cpu_dai,   SNDRV_PCM_STREAM_PLAYBACK))
822a1068045SVinod Koul 		playback = 1;
823467fece8SKuninori Morimoto 	if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
824467fece8SKuninori Morimoto 	    snd_soc_dai_stream_valid(cpu_dai,   SNDRV_PCM_STREAM_CAPTURE))
825a1068045SVinod Koul 		capture = 1;
826a1068045SVinod Koul 
827a1068045SVinod Koul 	/*
828a1068045SVinod Koul 	 * Compress devices are unidirectional so only one of the directions
829a1068045SVinod Koul 	 * should be set, check for that (xor)
830a1068045SVinod Koul 	 */
831a1068045SVinod Koul 	if (playback + capture != 1) {
832141dfc9eSCharles Keepax 		dev_err(rtd->card->dev,
833141dfc9eSCharles Keepax 			"Compress ASoC: Invalid direction for P %d, C %d\n",
834a1068045SVinod Koul 			playback, capture);
835daa2db59SCharles Keepax 		return -EINVAL;
836a1068045SVinod Koul 	}
837a1068045SVinod Koul 
838a1068045SVinod Koul 	if (playback)
839a1068045SVinod Koul 		direction = SND_COMPRESS_PLAYBACK;
840a1068045SVinod Koul 	else
841a1068045SVinod Koul 		direction = SND_COMPRESS_CAPTURE;
842daa2db59SCharles Keepax 
84309f448a4SAmadeusz Sławiński 	compr = devm_kzalloc(rtd->card->dev, sizeof(*compr), GFP_KERNEL);
8447a0cf42eSMarkus Elfring 	if (!compr)
8451245b700SNamarta Kohli 		return -ENOMEM;
8461245b700SNamarta Kohli 
8471f88eb0fSCharles Keepax 	compr->ops = devm_kzalloc(rtd->card->dev, sizeof(soc_compr_ops),
8481f88eb0fSCharles Keepax 				  GFP_KERNEL);
84909f448a4SAmadeusz Sławiński 	if (!compr->ops)
85009f448a4SAmadeusz Sławiński 		return -ENOMEM;
8512a99ef0fSLiam Girdwood 
8522a99ef0fSLiam Girdwood 	if (rtd->dai_link->dynamic) {
8532a99ef0fSLiam Girdwood 		snprintf(new_name, sizeof(new_name), "(%s)",
8542a99ef0fSLiam Girdwood 			rtd->dai_link->stream_name);
8552a99ef0fSLiam Girdwood 
8562a99ef0fSLiam Girdwood 		ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
857d3268a40SQais Yousef 				rtd->dai_link->dpcm_playback,
858d3268a40SQais Yousef 				rtd->dai_link->dpcm_capture, &be_pcm);
8592a99ef0fSLiam Girdwood 		if (ret < 0) {
860141dfc9eSCharles Keepax 			dev_err(rtd->card->dev,
861141dfc9eSCharles Keepax 				"Compress ASoC: can't create compressed for %s: %d\n",
862141dfc9eSCharles Keepax 				rtd->dai_link->name, ret);
86309f448a4SAmadeusz Sławiński 			return ret;
8642a99ef0fSLiam Girdwood 		}
8652a99ef0fSLiam Girdwood 
8662a99ef0fSLiam Girdwood 		rtd->pcm = be_pcm;
8672a99ef0fSLiam Girdwood 		rtd->fe_compr = 1;
868d3268a40SQais Yousef 		if (rtd->dai_link->dpcm_playback)
8692a99ef0fSLiam Girdwood 			be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
870d3268a40SQais Yousef 		else if (rtd->dai_link->dpcm_capture)
8712a99ef0fSLiam Girdwood 			be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
8722a99ef0fSLiam Girdwood 		memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops));
873aeb6fa0fSPeng Donglin 	} else {
874aeb6fa0fSPeng Donglin 		snprintf(new_name, sizeof(new_name), "%s %s-%d",
875aeb6fa0fSPeng Donglin 			rtd->dai_link->stream_name, codec_dai->name, num);
876aeb6fa0fSPeng Donglin 
8771f88eb0fSCharles Keepax 		memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));
878aeb6fa0fSPeng Donglin 	}
8791f88eb0fSCharles Keepax 
880613fb500SKuninori Morimoto 	for_each_rtd_components(rtd, i, component) {
8819e7e3738SKuninori Morimoto 		if (!component->driver->compr_ops ||
8829e7e3738SKuninori Morimoto 		    !component->driver->compr_ops->copy)
8839e7e3738SKuninori Morimoto 			continue;
8849e7e3738SKuninori Morimoto 
8859e7e3738SKuninori Morimoto 		compr->ops->copy = soc_compr_copy;
886ca76db6cSCharles Keepax 		break;
8879e7e3738SKuninori Morimoto 	}
8889e7e3738SKuninori Morimoto 
8891245b700SNamarta Kohli 	mutex_init(&compr->lock);
890e5241a8cSRichard Fitzgerald 	ret = snd_compress_new(rtd->card->snd_card, num, direction,
891e5241a8cSRichard Fitzgerald 				new_name, compr);
8921245b700SNamarta Kohli 	if (ret < 0) {
893e5acfc7dSKuninori Morimoto 		component = rtd->codec_dai->component;
894141dfc9eSCharles Keepax 		dev_err(component->dev,
895141dfc9eSCharles Keepax 			"Compress ASoC: can't create compress for codec %s: %d\n",
896141dfc9eSCharles Keepax 			component->name, ret);
89709f448a4SAmadeusz Sławiński 		return ret;
8981245b700SNamarta Kohli 	}
8991245b700SNamarta Kohli 
900202c8f70SCharles Keepax 	/* DAPM dai link stream work */
90183f94a2eSKuninori Morimoto 	rtd->close_delayed_work_func = snd_soc_close_delayed_work;
902202c8f70SCharles Keepax 
9031245b700SNamarta Kohli 	rtd->compr = compr;
9041245b700SNamarta Kohli 	compr->private_data = rtd;
9051245b700SNamarta Kohli 
906141dfc9eSCharles Keepax 	dev_info(rtd->card->dev, "Compress ASoC: %s <-> %s mapping ok\n",
907141dfc9eSCharles Keepax 		 codec_dai->name, cpu_dai->name);
9081f88eb0fSCharles Keepax 
90909f448a4SAmadeusz Sławiński 	return 0;
9101245b700SNamarta Kohli }
9116f0c4226SJie Yang EXPORT_SYMBOL_GPL(snd_soc_new_compress);
912