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