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> 229ab711cbSKuninori Morimoto #include <sound/soc-link.h> 234137f4b6SCezary Rojewski #include <linux/pm_runtime.h> 241245b700SNamarta Kohli 25*453d32c2SKuninori Morimoto static int soc_compr_clean(struct snd_compr_stream *cstream, int rollback) 2615a7b8c1SKuninori Morimoto { 2715a7b8c1SKuninori Morimoto struct snd_soc_pcm_runtime *rtd = cstream->private_data; 2815a7b8c1SKuninori Morimoto struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 2915a7b8c1SKuninori Morimoto struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 3015a7b8c1SKuninori Morimoto int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */ 3115a7b8c1SKuninori Morimoto 3215a7b8c1SKuninori Morimoto mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); 3315a7b8c1SKuninori Morimoto 34*453d32c2SKuninori Morimoto if (!rollback) 3515a7b8c1SKuninori Morimoto snd_soc_runtime_deactivate(rtd, stream); 3615a7b8c1SKuninori Morimoto 3715a7b8c1SKuninori Morimoto snd_soc_dai_digital_mute(codec_dai, 1, stream); 3815a7b8c1SKuninori Morimoto 3915a7b8c1SKuninori Morimoto if (!snd_soc_dai_active(cpu_dai)) 4015a7b8c1SKuninori Morimoto cpu_dai->rate = 0; 4115a7b8c1SKuninori Morimoto 4215a7b8c1SKuninori Morimoto if (!snd_soc_dai_active(codec_dai)) 4315a7b8c1SKuninori Morimoto codec_dai->rate = 0; 4415a7b8c1SKuninori Morimoto 45*453d32c2SKuninori Morimoto snd_soc_link_compr_shutdown(cstream, rollback); 4615a7b8c1SKuninori Morimoto 47*453d32c2SKuninori Morimoto snd_soc_component_compr_free(cstream, rollback); 4815a7b8c1SKuninori Morimoto 49*453d32c2SKuninori Morimoto snd_soc_dai_compr_shutdown(cpu_dai, cstream, rollback); 5015a7b8c1SKuninori Morimoto 51*453d32c2SKuninori Morimoto if (!rollback) 5215a7b8c1SKuninori Morimoto snd_soc_dapm_stream_stop(rtd, stream); 5315a7b8c1SKuninori Morimoto 5415a7b8c1SKuninori Morimoto mutex_unlock(&rtd->card->pcm_mutex); 5515a7b8c1SKuninori Morimoto 56*453d32c2SKuninori Morimoto snd_soc_pcm_component_pm_runtime_put(rtd, cstream, rollback); 5715a7b8c1SKuninori Morimoto 5815a7b8c1SKuninori Morimoto return 0; 5915a7b8c1SKuninori Morimoto } 6015a7b8c1SKuninori Morimoto 61*453d32c2SKuninori Morimoto static int soc_compr_free(struct snd_compr_stream *cstream) 62*453d32c2SKuninori Morimoto { 63*453d32c2SKuninori Morimoto return soc_compr_clean(cstream, 0); 64*453d32c2SKuninori Morimoto } 65*453d32c2SKuninori Morimoto 661e57b828SCharles Keepax static int soc_compr_open(struct snd_compr_stream *cstream) 671e57b828SCharles Keepax { 681e57b828SCharles Keepax struct snd_soc_pcm_runtime *rtd = cstream->private_data; 69c2233a26SKuninori Morimoto struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 707428d8c8SKuninori Morimoto int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */ 71939a5cfbSKuninori Morimoto int ret; 721245b700SNamarta Kohli 73939a5cfbSKuninori Morimoto ret = snd_soc_pcm_component_pm_runtime_get(rtd, cstream); 74939a5cfbSKuninori Morimoto if (ret < 0) 75*453d32c2SKuninori Morimoto goto err_no_lock; 764137f4b6SCezary Rojewski 7772b745e3SPeter Ujfalusi mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); 7815e2e619SCharles Keepax 79b5ae4cceSKuninori Morimoto ret = snd_soc_dai_compr_startup(cpu_dai, cstream); 80b5ae4cceSKuninori Morimoto if (ret < 0) 81*453d32c2SKuninori Morimoto goto err; 822e622ae4SVinod Koul 83f94ba9acSKuninori Morimoto ret = snd_soc_component_compr_open(cstream); 841e57b828SCharles Keepax if (ret < 0) 85*453d32c2SKuninori Morimoto goto err; 869e7e3738SKuninori Morimoto 879ab711cbSKuninori Morimoto ret = snd_soc_link_compr_startup(cstream); 889ab711cbSKuninori Morimoto if (ret < 0) 89*453d32c2SKuninori Morimoto goto err; 901245b700SNamarta Kohli 91eb84959aSKuninori Morimoto snd_soc_runtime_activate(rtd, stream); 92*453d32c2SKuninori Morimoto err: 9372b745e3SPeter Ujfalusi mutex_unlock(&rtd->card->pcm_mutex); 94*453d32c2SKuninori Morimoto err_no_lock: 95*453d32c2SKuninori Morimoto if (ret < 0) 96*453d32c2SKuninori Morimoto soc_compr_clean(cstream, 1); 974137f4b6SCezary Rojewski 981245b700SNamarta Kohli return ret; 991245b700SNamarta Kohli } 1001245b700SNamarta Kohli 1012a99ef0fSLiam Girdwood static int soc_compr_open_fe(struct snd_compr_stream *cstream) 1022a99ef0fSLiam Girdwood { 1032a99ef0fSLiam Girdwood struct snd_soc_pcm_runtime *fe = cstream->private_data; 10401b8cedfSSatish Babu Patakokila struct snd_pcm_substream *fe_substream = 10501b8cedfSSatish Babu Patakokila fe->pcm->streams[cstream->direction].substream; 106c2233a26SKuninori Morimoto struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0); 1072a99ef0fSLiam Girdwood struct snd_soc_dpcm *dpcm; 1082a99ef0fSLiam Girdwood struct snd_soc_dapm_widget_list *list; 1097428d8c8SKuninori Morimoto int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */ 110572e6c8dSCharles Keepax int ret; 1112a99ef0fSLiam Girdwood 1122a99ef0fSLiam Girdwood mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); 1130b0722e1SSrinivas Kandagatla fe->dpcm[stream].runtime = fe_substream->runtime; 1140b0722e1SSrinivas Kandagatla 1150b0722e1SSrinivas Kandagatla ret = dpcm_path_get(fe, stream, &list); 1160b0722e1SSrinivas Kandagatla if (ret < 0) 1170b0722e1SSrinivas Kandagatla goto be_err; 1180b0722e1SSrinivas Kandagatla else if (ret == 0) 1190b0722e1SSrinivas Kandagatla dev_dbg(fe->dev, "Compress ASoC: %s no valid %s route\n", 1200b0722e1SSrinivas Kandagatla fe->dai_link->name, stream ? "capture" : "playback"); 1210b0722e1SSrinivas Kandagatla /* calculate valid and active FE <-> BE dpcms */ 1220b0722e1SSrinivas Kandagatla dpcm_process_paths(fe, stream, &list, 1); 1230b0722e1SSrinivas Kandagatla fe->dpcm[stream].runtime = fe_substream->runtime; 1240b0722e1SSrinivas Kandagatla 1250b0722e1SSrinivas Kandagatla fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; 1260b0722e1SSrinivas Kandagatla 1270b0722e1SSrinivas Kandagatla ret = dpcm_be_dai_startup(fe, stream); 1280b0722e1SSrinivas Kandagatla if (ret < 0) { 1290b0722e1SSrinivas Kandagatla /* clean up all links */ 1308d6258a4SKuninori Morimoto for_each_dpcm_be(fe, stream, dpcm) 1310b0722e1SSrinivas Kandagatla dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; 1320b0722e1SSrinivas Kandagatla 1330b0722e1SSrinivas Kandagatla dpcm_be_disconnect(fe, stream); 1340b0722e1SSrinivas Kandagatla fe->dpcm[stream].runtime = NULL; 1350b0722e1SSrinivas Kandagatla goto out; 1360b0722e1SSrinivas Kandagatla } 1372a99ef0fSLiam Girdwood 138b5ae4cceSKuninori Morimoto ret = snd_soc_dai_compr_startup(cpu_dai, cstream); 139b5ae4cceSKuninori Morimoto if (ret < 0) 1402e622ae4SVinod Koul goto out; 1412e622ae4SVinod Koul 142f94ba9acSKuninori Morimoto ret = snd_soc_component_compr_open(cstream); 1431e57b828SCharles Keepax if (ret < 0) 1440b0722e1SSrinivas Kandagatla goto open_err; 1459e7e3738SKuninori Morimoto 1469ab711cbSKuninori Morimoto ret = snd_soc_link_compr_startup(cstream); 1479ab711cbSKuninori Morimoto if (ret < 0) 1482a99ef0fSLiam Girdwood goto machine_err; 1492a99ef0fSLiam Girdwood 1502a99ef0fSLiam Girdwood dpcm_clear_pending_state(fe, stream); 1512a99ef0fSLiam Girdwood dpcm_path_put(&list); 1522a99ef0fSLiam Girdwood 1532a99ef0fSLiam Girdwood fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN; 1542a99ef0fSLiam Girdwood fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; 1552a99ef0fSLiam Girdwood 15624894b76SLars-Peter Clausen snd_soc_runtime_activate(fe, stream); 1572a99ef0fSLiam Girdwood 1582a99ef0fSLiam Girdwood mutex_unlock(&fe->card->mutex); 1592a99ef0fSLiam Girdwood 1602a99ef0fSLiam Girdwood return 0; 1612a99ef0fSLiam Girdwood 1622a99ef0fSLiam Girdwood machine_err: 163f94ba9acSKuninori Morimoto snd_soc_component_compr_free(cstream, 1); 1640b0722e1SSrinivas Kandagatla open_err: 1651e6a93cfSKuninori Morimoto snd_soc_dai_compr_shutdown(cpu_dai, cstream, 1); 1662a99ef0fSLiam Girdwood out: 1670b0722e1SSrinivas Kandagatla dpcm_path_put(&list); 1680b0722e1SSrinivas Kandagatla be_err: 1692a99ef0fSLiam Girdwood fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; 1702a99ef0fSLiam Girdwood mutex_unlock(&fe->card->mutex); 1712a99ef0fSLiam Girdwood return ret; 1722a99ef0fSLiam Girdwood } 1732a99ef0fSLiam Girdwood 1742a99ef0fSLiam Girdwood static int soc_compr_free_fe(struct snd_compr_stream *cstream) 1752a99ef0fSLiam Girdwood { 1762a99ef0fSLiam Girdwood struct snd_soc_pcm_runtime *fe = cstream->private_data; 177c2233a26SKuninori Morimoto struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0); 1782a99ef0fSLiam Girdwood struct snd_soc_dpcm *dpcm; 1797428d8c8SKuninori Morimoto int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */ 1807428d8c8SKuninori Morimoto int ret; 1812a99ef0fSLiam Girdwood 1822a99ef0fSLiam Girdwood mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); 1832a99ef0fSLiam Girdwood 18424894b76SLars-Peter Clausen snd_soc_runtime_deactivate(fe, stream); 1852a99ef0fSLiam Girdwood 1862a99ef0fSLiam Girdwood fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; 1872a99ef0fSLiam Girdwood 1882a99ef0fSLiam Girdwood ret = dpcm_be_dai_hw_free(fe, stream); 1892a99ef0fSLiam Girdwood if (ret < 0) 190141dfc9eSCharles Keepax dev_err(fe->dev, "Compressed ASoC: hw_free failed: %d\n", ret); 1912a99ef0fSLiam Girdwood 1922a99ef0fSLiam Girdwood ret = dpcm_be_dai_shutdown(fe, stream); 1932a99ef0fSLiam Girdwood 1942a99ef0fSLiam Girdwood /* mark FE's links ready to prune */ 1958d6258a4SKuninori Morimoto for_each_dpcm_be(fe, stream, dpcm) 1962a99ef0fSLiam Girdwood dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; 1972a99ef0fSLiam Girdwood 1981c531230SKuninori Morimoto dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP); 1992a99ef0fSLiam Girdwood 2002a99ef0fSLiam Girdwood fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; 2012a99ef0fSLiam Girdwood fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; 2022a99ef0fSLiam Girdwood 2032a99ef0fSLiam Girdwood dpcm_be_disconnect(fe, stream); 2042a99ef0fSLiam Girdwood 2052a99ef0fSLiam Girdwood fe->dpcm[stream].runtime = NULL; 2062a99ef0fSLiam Girdwood 207cd7c7d10SKuninori Morimoto snd_soc_link_compr_shutdown(cstream, 0); 2082a99ef0fSLiam Girdwood 209f94ba9acSKuninori Morimoto snd_soc_component_compr_free(cstream, 0); 2109e7e3738SKuninori Morimoto 2111e6a93cfSKuninori Morimoto snd_soc_dai_compr_shutdown(cpu_dai, cstream, 0); 2122e622ae4SVinod Koul 2132a99ef0fSLiam Girdwood mutex_unlock(&fe->card->mutex); 2142a99ef0fSLiam Girdwood return 0; 2152a99ef0fSLiam Girdwood } 2162a99ef0fSLiam Girdwood 2174ef0ecb8SCharles Keepax static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) 2184ef0ecb8SCharles Keepax { 2194ef0ecb8SCharles Keepax struct snd_soc_pcm_runtime *rtd = cstream->private_data; 220c2233a26SKuninori Morimoto struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 221c2233a26SKuninori Morimoto struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 2227428d8c8SKuninori Morimoto int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */ 2234ef0ecb8SCharles Keepax int ret; 2244ef0ecb8SCharles Keepax 22572b745e3SPeter Ujfalusi mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); 2264ef0ecb8SCharles Keepax 22708aee251SKuninori Morimoto ret = snd_soc_component_compr_trigger(cstream, cmd); 2284ef0ecb8SCharles Keepax if (ret < 0) 2294ef0ecb8SCharles Keepax goto out; 2304ef0ecb8SCharles Keepax 231eb08411bSKuninori Morimoto ret = snd_soc_dai_compr_trigger(cpu_dai, cstream, cmd); 232eb08411bSKuninori Morimoto if (ret < 0) 233eb08411bSKuninori Morimoto goto out; 2342e622ae4SVinod Koul 235e38b9b74SMark Brown switch (cmd) { 236e38b9b74SMark Brown case SNDRV_PCM_TRIGGER_START: 237eb84959aSKuninori Morimoto snd_soc_dai_digital_mute(codec_dai, 0, stream); 238e38b9b74SMark Brown break; 239e38b9b74SMark Brown case SNDRV_PCM_TRIGGER_STOP: 240eb84959aSKuninori Morimoto snd_soc_dai_digital_mute(codec_dai, 1, stream); 241e38b9b74SMark Brown break; 242e38b9b74SMark Brown } 2431245b700SNamarta Kohli 24415e2e619SCharles Keepax out: 24572b745e3SPeter Ujfalusi mutex_unlock(&rtd->card->pcm_mutex); 2461245b700SNamarta Kohli return ret; 2471245b700SNamarta Kohli } 2481245b700SNamarta Kohli 2492a99ef0fSLiam Girdwood static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) 2502a99ef0fSLiam Girdwood { 2512a99ef0fSLiam Girdwood struct snd_soc_pcm_runtime *fe = cstream->private_data; 252c2233a26SKuninori Morimoto struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0); 2537428d8c8SKuninori Morimoto int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */ 2547428d8c8SKuninori Morimoto int ret; 2552a99ef0fSLiam Girdwood 2562a99ef0fSLiam Girdwood if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN || 2574ef0ecb8SCharles Keepax cmd == SND_COMPR_TRIGGER_DRAIN) 25808aee251SKuninori Morimoto return snd_soc_component_compr_trigger(cstream, cmd); 2592a99ef0fSLiam Girdwood 2602a99ef0fSLiam Girdwood mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); 2612a99ef0fSLiam Girdwood 262eb08411bSKuninori Morimoto ret = snd_soc_dai_compr_trigger(cpu_dai, cstream, cmd); 2632e622ae4SVinod Koul if (ret < 0) 2642e622ae4SVinod Koul goto out; 2652e622ae4SVinod Koul 26608aee251SKuninori Morimoto ret = snd_soc_component_compr_trigger(cstream, cmd); 2679e7e3738SKuninori Morimoto if (ret < 0) 2689e7e3738SKuninori Morimoto goto out; 2699e7e3738SKuninori Morimoto 2702a99ef0fSLiam Girdwood fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; 2712a99ef0fSLiam Girdwood 2722a99ef0fSLiam Girdwood ret = dpcm_be_dai_trigger(fe, stream, cmd); 2732a99ef0fSLiam Girdwood 2742a99ef0fSLiam Girdwood switch (cmd) { 2752a99ef0fSLiam Girdwood case SNDRV_PCM_TRIGGER_START: 2762a99ef0fSLiam Girdwood case SNDRV_PCM_TRIGGER_RESUME: 2772a99ef0fSLiam Girdwood case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 2782a99ef0fSLiam Girdwood fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START; 2792a99ef0fSLiam Girdwood break; 2802a99ef0fSLiam Girdwood case SNDRV_PCM_TRIGGER_STOP: 2812a99ef0fSLiam Girdwood case SNDRV_PCM_TRIGGER_SUSPEND: 2822a99ef0fSLiam Girdwood fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP; 2832a99ef0fSLiam Girdwood break; 2842a99ef0fSLiam Girdwood case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 2852a99ef0fSLiam Girdwood fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED; 2862a99ef0fSLiam Girdwood break; 2872a99ef0fSLiam Girdwood } 2882a99ef0fSLiam Girdwood 2892a99ef0fSLiam Girdwood out: 2902a99ef0fSLiam Girdwood fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; 2912a99ef0fSLiam Girdwood mutex_unlock(&fe->card->mutex); 2922a99ef0fSLiam Girdwood return ret; 2932a99ef0fSLiam Girdwood } 2942a99ef0fSLiam Girdwood 2954ef0ecb8SCharles Keepax static int soc_compr_set_params(struct snd_compr_stream *cstream, 2964ef0ecb8SCharles Keepax struct snd_compr_params *params) 2974ef0ecb8SCharles Keepax { 2984ef0ecb8SCharles Keepax struct snd_soc_pcm_runtime *rtd = cstream->private_data; 299c2233a26SKuninori Morimoto struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 3007428d8c8SKuninori Morimoto int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */ 30152cadf1fSCharles Keepax int ret; 3021245b700SNamarta Kohli 30372b745e3SPeter Ujfalusi mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); 30415e2e619SCharles Keepax 305ef050becSCharles Keepax /* 306ef050becSCharles Keepax * First we call set_params for the CPU DAI, then the component 307ef050becSCharles Keepax * driver this should configure the SoC side. If the machine has 308ef050becSCharles Keepax * compressed ops then we call that as well. The expectation is 309ef050becSCharles Keepax * that these callbacks will configure everything for this compress 310ef050becSCharles Keepax * path, like configuring a PCM port for a CODEC. 3111245b700SNamarta Kohli */ 3128dfedafbSKuninori Morimoto ret = snd_soc_dai_compr_set_params(cpu_dai, cstream, params); 3132e622ae4SVinod Koul if (ret < 0) 3142e622ae4SVinod Koul goto err; 3152e622ae4SVinod Koul 316ff08cf80SKuninori Morimoto ret = snd_soc_component_compr_set_params(cstream, params); 3179e7e3738SKuninori Morimoto if (ret < 0) 3189e7e3738SKuninori Morimoto goto err; 3199e7e3738SKuninori Morimoto 320eab810f3SKuninori Morimoto ret = snd_soc_link_compr_set_params(cstream); 3211245b700SNamarta Kohli if (ret < 0) 322fa40ef20SCharles Keepax goto err; 3231245b700SNamarta Kohli 3247428d8c8SKuninori Morimoto snd_soc_dapm_stream_event(rtd, stream, SND_SOC_DAPM_STREAM_START); 3251245b700SNamarta Kohli 326fa40ef20SCharles Keepax /* cancel any delayed stream shutdown that is pending */ 327fa40ef20SCharles Keepax rtd->pop_wait = 0; 32872b745e3SPeter Ujfalusi mutex_unlock(&rtd->card->pcm_mutex); 329fa40ef20SCharles Keepax 330fa40ef20SCharles Keepax cancel_delayed_work_sync(&rtd->delayed_work); 331fa40ef20SCharles Keepax 33252cadf1fSCharles Keepax return 0; 333fa40ef20SCharles Keepax 334fa40ef20SCharles Keepax err: 33572b745e3SPeter Ujfalusi mutex_unlock(&rtd->card->pcm_mutex); 3361245b700SNamarta Kohli return ret; 3371245b700SNamarta Kohli } 3381245b700SNamarta Kohli 3392a99ef0fSLiam Girdwood static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, 3402a99ef0fSLiam Girdwood struct snd_compr_params *params) 3412a99ef0fSLiam Girdwood { 3422a99ef0fSLiam Girdwood struct snd_soc_pcm_runtime *fe = cstream->private_data; 34301b8cedfSSatish Babu Patakokila struct snd_pcm_substream *fe_substream = 34401b8cedfSSatish Babu Patakokila fe->pcm->streams[cstream->direction].substream; 345c2233a26SKuninori Morimoto struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0); 3467428d8c8SKuninori Morimoto int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */ 3477428d8c8SKuninori Morimoto int ret; 3482a99ef0fSLiam Girdwood 3492a99ef0fSLiam Girdwood mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); 3502a99ef0fSLiam Girdwood 3510b0722e1SSrinivas Kandagatla /* 3520b0722e1SSrinivas Kandagatla * Create an empty hw_params for the BE as the machine driver must 3530b0722e1SSrinivas Kandagatla * fix this up to match DSP decoder and ASRC configuration. 3540b0722e1SSrinivas Kandagatla * I.e. machine driver fixup for compressed BE is mandatory. 3550b0722e1SSrinivas Kandagatla */ 3560b0722e1SSrinivas Kandagatla memset(&fe->dpcm[fe_substream->stream].hw_params, 0, 3570b0722e1SSrinivas Kandagatla sizeof(struct snd_pcm_hw_params)); 3580b0722e1SSrinivas Kandagatla 3590b0722e1SSrinivas Kandagatla fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; 3600b0722e1SSrinivas Kandagatla 3610b0722e1SSrinivas Kandagatla ret = dpcm_be_dai_hw_params(fe, stream); 3620b0722e1SSrinivas Kandagatla if (ret < 0) 3630b0722e1SSrinivas Kandagatla goto out; 3640b0722e1SSrinivas Kandagatla 3650b0722e1SSrinivas Kandagatla ret = dpcm_be_dai_prepare(fe, stream); 3660b0722e1SSrinivas Kandagatla if (ret < 0) 3670b0722e1SSrinivas Kandagatla goto out; 3680b0722e1SSrinivas Kandagatla 3698dfedafbSKuninori Morimoto ret = snd_soc_dai_compr_set_params(cpu_dai, cstream, params); 3702e622ae4SVinod Koul if (ret < 0) 3712e622ae4SVinod Koul goto out; 3722e622ae4SVinod Koul 373ff08cf80SKuninori Morimoto ret = snd_soc_component_compr_set_params(cstream, params); 3749e7e3738SKuninori Morimoto if (ret < 0) 3759e7e3738SKuninori Morimoto goto out; 3769e7e3738SKuninori Morimoto 377eab810f3SKuninori Morimoto ret = snd_soc_link_compr_set_params(cstream); 3782a99ef0fSLiam Girdwood if (ret < 0) 3792a99ef0fSLiam Girdwood goto out; 3802a99ef0fSLiam Girdwood 3812a99ef0fSLiam Girdwood dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START); 3822a99ef0fSLiam Girdwood fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE; 3832a99ef0fSLiam Girdwood 3842a99ef0fSLiam Girdwood out: 3852a99ef0fSLiam Girdwood fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; 3862a99ef0fSLiam Girdwood mutex_unlock(&fe->card->mutex); 3872a99ef0fSLiam Girdwood return ret; 3882a99ef0fSLiam Girdwood } 3892a99ef0fSLiam Girdwood 3901245b700SNamarta Kohli static int soc_compr_get_params(struct snd_compr_stream *cstream, 3911245b700SNamarta Kohli struct snd_codec *params) 3921245b700SNamarta Kohli { 3931245b700SNamarta Kohli struct snd_soc_pcm_runtime *rtd = cstream->private_data; 394c2233a26SKuninori Morimoto struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 39577c221ecSKuninori Morimoto int ret = 0; 3961245b700SNamarta Kohli 39772b745e3SPeter Ujfalusi mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); 39815e2e619SCharles Keepax 399adbef543SKuninori Morimoto ret = snd_soc_dai_compr_get_params(cpu_dai, cstream, params); 4002e622ae4SVinod Koul if (ret < 0) 4012e622ae4SVinod Koul goto err; 4022e622ae4SVinod Koul 40377c221ecSKuninori Morimoto ret = snd_soc_component_compr_get_params(cstream, params); 4042e622ae4SVinod Koul err: 40572b745e3SPeter Ujfalusi mutex_unlock(&rtd->card->pcm_mutex); 4061245b700SNamarta Kohli return ret; 4071245b700SNamarta Kohli } 4081245b700SNamarta Kohli 4091245b700SNamarta Kohli static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) 4101245b700SNamarta Kohli { 4111245b700SNamarta Kohli struct snd_soc_pcm_runtime *rtd = cstream->private_data; 412c2233a26SKuninori Morimoto struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 4130506b885SKuninori Morimoto int ret; 4141245b700SNamarta Kohli 41572b745e3SPeter Ujfalusi mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); 41615e2e619SCharles Keepax 41753294353SKuninori Morimoto ret = snd_soc_dai_compr_ack(cpu_dai, cstream, bytes); 4182e622ae4SVinod Koul if (ret < 0) 4192e622ae4SVinod Koul goto err; 4202e622ae4SVinod Koul 4210506b885SKuninori Morimoto ret = snd_soc_component_compr_ack(cstream, bytes); 4222e622ae4SVinod Koul err: 42372b745e3SPeter Ujfalusi mutex_unlock(&rtd->card->pcm_mutex); 4241245b700SNamarta Kohli return ret; 4251245b700SNamarta Kohli } 4261245b700SNamarta Kohli 4271245b700SNamarta Kohli static int soc_compr_pointer(struct snd_compr_stream *cstream, 4281245b700SNamarta Kohli struct snd_compr_tstamp *tstamp) 4291245b700SNamarta Kohli { 4301245b700SNamarta Kohli struct snd_soc_pcm_runtime *rtd = cstream->private_data; 43103ecea64SKuninori Morimoto int ret; 432c2233a26SKuninori Morimoto struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 4331245b700SNamarta Kohli 43472b745e3SPeter Ujfalusi mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); 43515e2e619SCharles Keepax 436ed38cc59SKuninori Morimoto ret = snd_soc_dai_compr_pointer(cpu_dai, cstream, tstamp); 437ed38cc59SKuninori Morimoto if (ret < 0) 438ed38cc59SKuninori Morimoto goto out; 4392e622ae4SVinod Koul 44003ecea64SKuninori Morimoto ret = snd_soc_component_compr_pointer(cstream, tstamp); 441ed38cc59SKuninori Morimoto out: 44272b745e3SPeter Ujfalusi mutex_unlock(&rtd->card->pcm_mutex); 4437c9190f7SCharles Keepax return ret; 4441245b700SNamarta Kohli } 4451245b700SNamarta Kohli 44602bd90e8SVinod Koul static int soc_compr_set_metadata(struct snd_compr_stream *cstream, 44736953d98SJeeja KP struct snd_compr_metadata *metadata) 44836953d98SJeeja KP { 44936953d98SJeeja KP struct snd_soc_pcm_runtime *rtd = cstream->private_data; 450c2233a26SKuninori Morimoto struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 4511b308fb1SKuninori Morimoto int ret; 45236953d98SJeeja KP 45388b3a7dfSKuninori Morimoto ret = snd_soc_dai_compr_set_metadata(cpu_dai, cstream, metadata); 4542e622ae4SVinod Koul if (ret < 0) 4552e622ae4SVinod Koul return ret; 4562e622ae4SVinod Koul 4571b308fb1SKuninori Morimoto return snd_soc_component_compr_set_metadata(cstream, metadata); 45836953d98SJeeja KP } 45936953d98SJeeja KP 46002bd90e8SVinod Koul static int soc_compr_get_metadata(struct snd_compr_stream *cstream, 46136953d98SJeeja KP struct snd_compr_metadata *metadata) 46236953d98SJeeja KP { 46336953d98SJeeja KP struct snd_soc_pcm_runtime *rtd = cstream->private_data; 464c2233a26SKuninori Morimoto struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 465bab78c23SKuninori Morimoto int ret; 46636953d98SJeeja KP 46794d72819SKuninori Morimoto ret = snd_soc_dai_compr_get_metadata(cpu_dai, cstream, metadata); 4682e622ae4SVinod Koul if (ret < 0) 4692e622ae4SVinod Koul return ret; 4702e622ae4SVinod Koul 471bab78c23SKuninori Morimoto return snd_soc_component_compr_get_metadata(cstream, metadata); 47236953d98SJeeja KP } 4732a99ef0fSLiam Girdwood 4741245b700SNamarta Kohli /* ASoC Compress operations */ 4751245b700SNamarta Kohli static struct snd_compr_ops soc_compr_ops = { 4761245b700SNamarta Kohli .open = soc_compr_open, 4771245b700SNamarta Kohli .free = soc_compr_free, 4781245b700SNamarta Kohli .set_params = soc_compr_set_params, 47902bd90e8SVinod Koul .set_metadata = soc_compr_set_metadata, 48002bd90e8SVinod Koul .get_metadata = soc_compr_get_metadata, 4811245b700SNamarta Kohli .get_params = soc_compr_get_params, 4821245b700SNamarta Kohli .trigger = soc_compr_trigger, 4831245b700SNamarta Kohli .pointer = soc_compr_pointer, 4841245b700SNamarta Kohli .ack = soc_compr_ack, 485d67fcb2dSKuninori Morimoto .get_caps = snd_soc_component_compr_get_caps, 4860f6fe097SKuninori Morimoto .get_codec_caps = snd_soc_component_compr_get_codec_caps, 4871245b700SNamarta Kohli }; 4881245b700SNamarta Kohli 4892a99ef0fSLiam Girdwood /* ASoC Dynamic Compress operations */ 4902a99ef0fSLiam Girdwood static struct snd_compr_ops soc_compr_dyn_ops = { 4912a99ef0fSLiam Girdwood .open = soc_compr_open_fe, 4922a99ef0fSLiam Girdwood .free = soc_compr_free_fe, 4932a99ef0fSLiam Girdwood .set_params = soc_compr_set_params_fe, 4942a99ef0fSLiam Girdwood .get_params = soc_compr_get_params, 4952a99ef0fSLiam Girdwood .set_metadata = soc_compr_set_metadata, 4962a99ef0fSLiam Girdwood .get_metadata = soc_compr_get_metadata, 4972a99ef0fSLiam Girdwood .trigger = soc_compr_trigger_fe, 4982a99ef0fSLiam Girdwood .pointer = soc_compr_pointer, 4992a99ef0fSLiam Girdwood .ack = soc_compr_ack, 500d67fcb2dSKuninori Morimoto .get_caps = snd_soc_component_compr_get_caps, 5010f6fe097SKuninori Morimoto .get_codec_caps = snd_soc_component_compr_get_codec_caps, 5022a99ef0fSLiam Girdwood }; 5032a99ef0fSLiam Girdwood 5046f0c4226SJie Yang /** 5056f0c4226SJie Yang * snd_soc_new_compress - create a new compress. 5066f0c4226SJie Yang * 5076f0c4226SJie Yang * @rtd: The runtime for which we will create compress 5086f0c4226SJie Yang * @num: the device index number (zero based - shared with normal PCMs) 5096f0c4226SJie Yang * 5106f0c4226SJie Yang * Return: 0 for success, else error. 5116f0c4226SJie Yang */ 5126f0c4226SJie Yang int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) 5131245b700SNamarta Kohli { 5149e7e3738SKuninori Morimoto struct snd_soc_component *component; 515c2233a26SKuninori Morimoto struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 516c2233a26SKuninori Morimoto struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 5171245b700SNamarta Kohli struct snd_compr *compr; 5182a99ef0fSLiam Girdwood struct snd_pcm *be_pcm; 5191245b700SNamarta Kohli char new_name[64]; 5201245b700SNamarta Kohli int ret = 0, direction = 0; 521a1068045SVinod Koul int playback = 0, capture = 0; 522613fb500SKuninori Morimoto int i; 5231245b700SNamarta Kohli 5247428d8c8SKuninori Morimoto /* 5257428d8c8SKuninori Morimoto * make sure these are same value, 5267428d8c8SKuninori Morimoto * and then use these as equally 5277428d8c8SKuninori Morimoto */ 5287428d8c8SKuninori Morimoto BUILD_BUG_ON((int)SNDRV_PCM_STREAM_PLAYBACK != (int)SND_COMPRESS_PLAYBACK); 5297428d8c8SKuninori Morimoto BUILD_BUG_ON((int)SNDRV_PCM_STREAM_CAPTURE != (int)SND_COMPRESS_CAPTURE); 5307428d8c8SKuninori Morimoto 5316e1276a5SBard Liao if (rtd->num_cpus > 1 || 5326e1276a5SBard Liao rtd->num_codecs > 1) { 533141dfc9eSCharles Keepax dev_err(rtd->card->dev, 5346e1276a5SBard Liao "Compress ASoC: Multi CPU/Codec not supported\n"); 5358151d5e6SBenoit Cousson return -EINVAL; 5368151d5e6SBenoit Cousson } 5378151d5e6SBenoit Cousson 5381245b700SNamarta Kohli /* check client and interface hw capabilities */ 539467fece8SKuninori Morimoto if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) && 540467fece8SKuninori Morimoto snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_PLAYBACK)) 541a1068045SVinod Koul playback = 1; 542467fece8SKuninori Morimoto if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) && 543467fece8SKuninori Morimoto snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_CAPTURE)) 544a1068045SVinod Koul capture = 1; 545a1068045SVinod Koul 546a1068045SVinod Koul /* 547a1068045SVinod Koul * Compress devices are unidirectional so only one of the directions 548a1068045SVinod Koul * should be set, check for that (xor) 549a1068045SVinod Koul */ 550a1068045SVinod Koul if (playback + capture != 1) { 551141dfc9eSCharles Keepax dev_err(rtd->card->dev, 552141dfc9eSCharles Keepax "Compress ASoC: Invalid direction for P %d, C %d\n", 553a1068045SVinod Koul playback, capture); 554daa2db59SCharles Keepax return -EINVAL; 555a1068045SVinod Koul } 556a1068045SVinod Koul 557a1068045SVinod Koul if (playback) 558a1068045SVinod Koul direction = SND_COMPRESS_PLAYBACK; 559a1068045SVinod Koul else 560a1068045SVinod Koul direction = SND_COMPRESS_CAPTURE; 561daa2db59SCharles Keepax 56209f448a4SAmadeusz Sławiński compr = devm_kzalloc(rtd->card->dev, sizeof(*compr), GFP_KERNEL); 5637a0cf42eSMarkus Elfring if (!compr) 5641245b700SNamarta Kohli return -ENOMEM; 5651245b700SNamarta Kohli 5661f88eb0fSCharles Keepax compr->ops = devm_kzalloc(rtd->card->dev, sizeof(soc_compr_ops), 5671f88eb0fSCharles Keepax GFP_KERNEL); 56809f448a4SAmadeusz Sławiński if (!compr->ops) 56909f448a4SAmadeusz Sławiński return -ENOMEM; 5702a99ef0fSLiam Girdwood 5712a99ef0fSLiam Girdwood if (rtd->dai_link->dynamic) { 5722a99ef0fSLiam Girdwood snprintf(new_name, sizeof(new_name), "(%s)", 5732a99ef0fSLiam Girdwood rtd->dai_link->stream_name); 5742a99ef0fSLiam Girdwood 5752a99ef0fSLiam Girdwood ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num, 576d3268a40SQais Yousef rtd->dai_link->dpcm_playback, 577d3268a40SQais Yousef rtd->dai_link->dpcm_capture, &be_pcm); 5782a99ef0fSLiam Girdwood if (ret < 0) { 579141dfc9eSCharles Keepax dev_err(rtd->card->dev, 580141dfc9eSCharles Keepax "Compress ASoC: can't create compressed for %s: %d\n", 581141dfc9eSCharles Keepax rtd->dai_link->name, ret); 58209f448a4SAmadeusz Sławiński return ret; 5832a99ef0fSLiam Girdwood } 5842a99ef0fSLiam Girdwood 5852a99ef0fSLiam Girdwood rtd->pcm = be_pcm; 5862a99ef0fSLiam Girdwood rtd->fe_compr = 1; 587d3268a40SQais Yousef if (rtd->dai_link->dpcm_playback) 5882a99ef0fSLiam Girdwood be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd; 589d3268a40SQais Yousef else if (rtd->dai_link->dpcm_capture) 5902a99ef0fSLiam Girdwood be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd; 5912a99ef0fSLiam Girdwood memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops)); 592aeb6fa0fSPeng Donglin } else { 593aeb6fa0fSPeng Donglin snprintf(new_name, sizeof(new_name), "%s %s-%d", 594aeb6fa0fSPeng Donglin rtd->dai_link->stream_name, codec_dai->name, num); 595aeb6fa0fSPeng Donglin 5961f88eb0fSCharles Keepax memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops)); 597aeb6fa0fSPeng Donglin } 5981f88eb0fSCharles Keepax 599613fb500SKuninori Morimoto for_each_rtd_components(rtd, i, component) { 600c6cb522cSKuninori Morimoto if (!component->driver->compress_ops || 601c6cb522cSKuninori Morimoto !component->driver->compress_ops->copy) 602c6cb522cSKuninori Morimoto continue; 603c6cb522cSKuninori Morimoto 604b5852e66SKuninori Morimoto compr->ops->copy = snd_soc_component_compr_copy; 605c6cb522cSKuninori Morimoto break; 606c6cb522cSKuninori Morimoto } 607c6cb522cSKuninori Morimoto 6081245b700SNamarta Kohli mutex_init(&compr->lock); 609e5241a8cSRichard Fitzgerald ret = snd_compress_new(rtd->card->snd_card, num, direction, 610e5241a8cSRichard Fitzgerald new_name, compr); 6111245b700SNamarta Kohli if (ret < 0) { 612c2233a26SKuninori Morimoto component = asoc_rtd_to_codec(rtd, 0)->component; 613141dfc9eSCharles Keepax dev_err(component->dev, 614141dfc9eSCharles Keepax "Compress ASoC: can't create compress for codec %s: %d\n", 615141dfc9eSCharles Keepax component->name, ret); 61609f448a4SAmadeusz Sławiński return ret; 6171245b700SNamarta Kohli } 6181245b700SNamarta Kohli 619202c8f70SCharles Keepax /* DAPM dai link stream work */ 62083f94a2eSKuninori Morimoto rtd->close_delayed_work_func = snd_soc_close_delayed_work; 621202c8f70SCharles Keepax 6221245b700SNamarta Kohli rtd->compr = compr; 6231245b700SNamarta Kohli compr->private_data = rtd; 6241245b700SNamarta Kohli 6251d5cd525SPierre-Louis Bossart dev_dbg(rtd->card->dev, "Compress ASoC: %s <-> %s mapping ok\n", 626141dfc9eSCharles Keepax codec_dai->name, cpu_dai->name); 6271f88eb0fSCharles Keepax 62809f448a4SAmadeusz Sławiński return 0; 6291245b700SNamarta Kohli } 6306f0c4226SJie Yang EXPORT_SYMBOL_GPL(snd_soc_new_compress); 631