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> 221245b700SNamarta Kohli 231e57b828SCharles Keepax static int soc_compr_components_open(struct snd_compr_stream *cstream, 241e57b828SCharles Keepax struct snd_soc_component **last) 251245b700SNamarta Kohli { 261245b700SNamarta Kohli struct snd_soc_pcm_runtime *rtd = cstream->private_data; 279e7e3738SKuninori Morimoto struct snd_soc_component *component; 289e7e3738SKuninori Morimoto struct snd_soc_rtdcom_list *rtdcom; 291e57b828SCharles Keepax int ret; 301e57b828SCharles Keepax 311e57b828SCharles Keepax for_each_rtdcom(rtd, rtdcom) { 321e57b828SCharles Keepax component = rtdcom->component; 331e57b828SCharles Keepax 341e57b828SCharles Keepax if (!component->driver->compr_ops || 351e57b828SCharles Keepax !component->driver->compr_ops->open) 361e57b828SCharles Keepax continue; 371e57b828SCharles Keepax 381e57b828SCharles Keepax ret = component->driver->compr_ops->open(cstream); 391e57b828SCharles Keepax if (ret < 0) { 401e57b828SCharles Keepax dev_err(component->dev, 411e57b828SCharles Keepax "Compress ASoC: can't open platform %s: %d\n", 421e57b828SCharles Keepax component->name, ret); 431e57b828SCharles Keepax 441e57b828SCharles Keepax *last = component; 451e57b828SCharles Keepax return ret; 461e57b828SCharles Keepax } 471e57b828SCharles Keepax } 481e57b828SCharles Keepax 491e57b828SCharles Keepax *last = NULL; 501e57b828SCharles Keepax return 0; 511e57b828SCharles Keepax } 521e57b828SCharles Keepax 531e57b828SCharles Keepax static int soc_compr_components_free(struct snd_compr_stream *cstream, 541e57b828SCharles Keepax struct snd_soc_component *last) 551e57b828SCharles Keepax { 561e57b828SCharles Keepax struct snd_soc_pcm_runtime *rtd = cstream->private_data; 571e57b828SCharles Keepax struct snd_soc_component *component; 581e57b828SCharles Keepax struct snd_soc_rtdcom_list *rtdcom; 591e57b828SCharles Keepax 601e57b828SCharles Keepax for_each_rtdcom(rtd, rtdcom) { 611e57b828SCharles Keepax component = rtdcom->component; 621e57b828SCharles Keepax 631e57b828SCharles Keepax if (component == last) 641e57b828SCharles Keepax break; 651e57b828SCharles Keepax 661e57b828SCharles Keepax if (!component->driver->compr_ops || 671e57b828SCharles Keepax !component->driver->compr_ops->free) 681e57b828SCharles Keepax continue; 691e57b828SCharles Keepax 701e57b828SCharles Keepax component->driver->compr_ops->free(cstream); 711e57b828SCharles Keepax } 721e57b828SCharles Keepax 731e57b828SCharles Keepax return 0; 741e57b828SCharles Keepax } 751e57b828SCharles Keepax 761e57b828SCharles Keepax static int soc_compr_open(struct snd_compr_stream *cstream) 771e57b828SCharles Keepax { 781e57b828SCharles Keepax struct snd_soc_pcm_runtime *rtd = cstream->private_data; 791e57b828SCharles Keepax struct snd_soc_component *component; 802e622ae4SVinod Koul struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 81572e6c8dSCharles Keepax int ret; 821245b700SNamarta Kohli 8315e2e619SCharles Keepax mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); 8415e2e619SCharles Keepax 852e622ae4SVinod Koul if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) { 862e622ae4SVinod Koul ret = cpu_dai->driver->cops->startup(cstream, cpu_dai); 872e622ae4SVinod Koul if (ret < 0) { 88141dfc9eSCharles Keepax dev_err(cpu_dai->dev, 89141dfc9eSCharles Keepax "Compress ASoC: can't open interface %s: %d\n", 902e622ae4SVinod Koul cpu_dai->name, ret); 912e622ae4SVinod Koul goto out; 922e622ae4SVinod Koul } 932e622ae4SVinod Koul } 942e622ae4SVinod Koul 951e57b828SCharles Keepax ret = soc_compr_components_open(cstream, &component); 961e57b828SCharles Keepax if (ret < 0) 979e7e3738SKuninori Morimoto goto machine_err; 989e7e3738SKuninori Morimoto 991245b700SNamarta Kohli if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->startup) { 1001245b700SNamarta Kohli ret = rtd->dai_link->compr_ops->startup(cstream); 1011245b700SNamarta Kohli if (ret < 0) { 102141dfc9eSCharles Keepax dev_err(rtd->dev, 103141dfc9eSCharles Keepax "Compress ASoC: %s startup failed: %d\n", 104141dfc9eSCharles Keepax rtd->dai_link->name, ret); 1051245b700SNamarta Kohli goto machine_err; 1061245b700SNamarta Kohli } 1071245b700SNamarta Kohli } 1081245b700SNamarta Kohli 10924894b76SLars-Peter Clausen snd_soc_runtime_activate(rtd, cstream->direction); 1101245b700SNamarta Kohli 11115e2e619SCharles Keepax mutex_unlock(&rtd->pcm_mutex); 11215e2e619SCharles Keepax 1131245b700SNamarta Kohli return 0; 1141245b700SNamarta Kohli 1151245b700SNamarta Kohli machine_err: 1161e57b828SCharles Keepax soc_compr_components_free(cstream, component); 1179e7e3738SKuninori Morimoto 1182e622ae4SVinod Koul if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown) 1192e622ae4SVinod Koul cpu_dai->driver->cops->shutdown(cstream, cpu_dai); 1201245b700SNamarta Kohli out: 12115e2e619SCharles Keepax mutex_unlock(&rtd->pcm_mutex); 1221245b700SNamarta Kohli return ret; 1231245b700SNamarta Kohli } 1241245b700SNamarta Kohli 1252a99ef0fSLiam Girdwood static int soc_compr_open_fe(struct snd_compr_stream *cstream) 1262a99ef0fSLiam Girdwood { 1272a99ef0fSLiam Girdwood struct snd_soc_pcm_runtime *fe = cstream->private_data; 12801b8cedfSSatish Babu Patakokila struct snd_pcm_substream *fe_substream = 12901b8cedfSSatish Babu Patakokila fe->pcm->streams[cstream->direction].substream; 1309e7e3738SKuninori Morimoto struct snd_soc_component *component; 1312e622ae4SVinod Koul struct snd_soc_dai *cpu_dai = fe->cpu_dai; 1322a99ef0fSLiam Girdwood struct snd_soc_dpcm *dpcm; 1332a99ef0fSLiam Girdwood struct snd_soc_dapm_widget_list *list; 1342a99ef0fSLiam Girdwood int stream; 135572e6c8dSCharles Keepax int ret; 1362a99ef0fSLiam Girdwood 1372a99ef0fSLiam Girdwood if (cstream->direction == SND_COMPRESS_PLAYBACK) 1382a99ef0fSLiam Girdwood stream = SNDRV_PCM_STREAM_PLAYBACK; 1392a99ef0fSLiam Girdwood else 1402a99ef0fSLiam Girdwood stream = SNDRV_PCM_STREAM_CAPTURE; 1412a99ef0fSLiam Girdwood 1422a99ef0fSLiam Girdwood mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); 1432a99ef0fSLiam Girdwood 1442e622ae4SVinod Koul if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) { 1452e622ae4SVinod Koul ret = cpu_dai->driver->cops->startup(cstream, cpu_dai); 1462e622ae4SVinod Koul if (ret < 0) { 147141dfc9eSCharles Keepax dev_err(cpu_dai->dev, 148141dfc9eSCharles Keepax "Compress ASoC: can't open interface %s: %d\n", 1492e622ae4SVinod Koul cpu_dai->name, ret); 1502e622ae4SVinod Koul goto out; 1512e622ae4SVinod Koul } 1522e622ae4SVinod Koul } 1532e622ae4SVinod Koul 1541e57b828SCharles Keepax ret = soc_compr_components_open(cstream, &component); 1551e57b828SCharles Keepax if (ret < 0) 1569e7e3738SKuninori Morimoto goto machine_err; 1579e7e3738SKuninori Morimoto 1582a99ef0fSLiam Girdwood if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->startup) { 1592a99ef0fSLiam Girdwood ret = fe->dai_link->compr_ops->startup(cstream); 1602a99ef0fSLiam Girdwood if (ret < 0) { 161141dfc9eSCharles Keepax pr_err("Compress ASoC: %s startup failed: %d\n", 162141dfc9eSCharles Keepax fe->dai_link->name, ret); 1632a99ef0fSLiam Girdwood goto machine_err; 1642a99ef0fSLiam Girdwood } 1652a99ef0fSLiam Girdwood } 1662a99ef0fSLiam Girdwood 1672a99ef0fSLiam Girdwood fe->dpcm[stream].runtime = fe_substream->runtime; 1682a99ef0fSLiam Girdwood 1698f70e515SQiao Zhou ret = dpcm_path_get(fe, stream, &list); 1702e4ec1c0SQiao Zhou if (ret < 0) 1718f70e515SQiao Zhou goto fe_err; 1722e4ec1c0SQiao Zhou else if (ret == 0) 173141dfc9eSCharles Keepax dev_dbg(fe->dev, "Compress ASoC: %s no valid %s route\n", 1742a99ef0fSLiam Girdwood fe->dai_link->name, stream ? "capture" : "playback"); 1752a99ef0fSLiam Girdwood 1762a99ef0fSLiam Girdwood /* calculate valid and active FE <-> BE dpcms */ 1772a99ef0fSLiam Girdwood dpcm_process_paths(fe, stream, &list, 1); 1782a99ef0fSLiam Girdwood 1792a99ef0fSLiam Girdwood fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; 1802a99ef0fSLiam Girdwood 1812a99ef0fSLiam Girdwood ret = dpcm_be_dai_startup(fe, stream); 1822a99ef0fSLiam Girdwood if (ret < 0) { 1832a99ef0fSLiam Girdwood /* clean up all links */ 1842a99ef0fSLiam Girdwood list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) 1852a99ef0fSLiam Girdwood dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; 1862a99ef0fSLiam Girdwood 1872a99ef0fSLiam Girdwood dpcm_be_disconnect(fe, stream); 1882a99ef0fSLiam Girdwood fe->dpcm[stream].runtime = NULL; 189b0f12c61SCharles Keepax goto path_err; 1902a99ef0fSLiam Girdwood } 1912a99ef0fSLiam Girdwood 1922a99ef0fSLiam Girdwood dpcm_clear_pending_state(fe, stream); 1932a99ef0fSLiam Girdwood dpcm_path_put(&list); 1942a99ef0fSLiam Girdwood 1952a99ef0fSLiam Girdwood fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN; 1962a99ef0fSLiam Girdwood fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; 1972a99ef0fSLiam Girdwood 19824894b76SLars-Peter Clausen snd_soc_runtime_activate(fe, stream); 1992a99ef0fSLiam Girdwood 2002a99ef0fSLiam Girdwood mutex_unlock(&fe->card->mutex); 2012a99ef0fSLiam Girdwood 2022a99ef0fSLiam Girdwood return 0; 2032a99ef0fSLiam Girdwood 204b0f12c61SCharles Keepax path_err: 205b0f12c61SCharles Keepax dpcm_path_put(&list); 2062a99ef0fSLiam Girdwood fe_err: 2072a99ef0fSLiam Girdwood if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown) 2082a99ef0fSLiam Girdwood fe->dai_link->compr_ops->shutdown(cstream); 2092a99ef0fSLiam Girdwood machine_err: 2101e57b828SCharles Keepax soc_compr_components_free(cstream, component); 2119e7e3738SKuninori Morimoto 2122e622ae4SVinod Koul if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown) 2132e622ae4SVinod Koul cpu_dai->driver->cops->shutdown(cstream, cpu_dai); 2142a99ef0fSLiam Girdwood out: 2152a99ef0fSLiam Girdwood fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; 2162a99ef0fSLiam Girdwood mutex_unlock(&fe->card->mutex); 2172a99ef0fSLiam Girdwood return ret; 2182a99ef0fSLiam Girdwood } 2192a99ef0fSLiam Girdwood 220202c8f70SCharles Keepax /* 221202c8f70SCharles Keepax * Power down the audio subsystem pmdown_time msecs after close is called. 222202c8f70SCharles Keepax * This is to ensure there are no pops or clicks in between any music tracks 223202c8f70SCharles Keepax * due to DAPM power cycling. 224202c8f70SCharles Keepax */ 225202c8f70SCharles Keepax static void close_delayed_work(struct work_struct *work) 226202c8f70SCharles Keepax { 227202c8f70SCharles Keepax struct snd_soc_pcm_runtime *rtd = 228202c8f70SCharles Keepax container_of(work, struct snd_soc_pcm_runtime, delayed_work.work); 229202c8f70SCharles Keepax struct snd_soc_dai *codec_dai = rtd->codec_dai; 230202c8f70SCharles Keepax 231202c8f70SCharles Keepax mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); 232202c8f70SCharles Keepax 233141dfc9eSCharles Keepax dev_dbg(rtd->dev, 234141dfc9eSCharles Keepax "Compress ASoC: pop wq checking: %s status: %s waiting: %s\n", 235202c8f70SCharles Keepax codec_dai->driver->playback.stream_name, 236202c8f70SCharles Keepax codec_dai->playback_active ? "active" : "inactive", 237202c8f70SCharles Keepax rtd->pop_wait ? "yes" : "no"); 238202c8f70SCharles Keepax 239202c8f70SCharles Keepax /* are we waiting on this codec DAI stream */ 240202c8f70SCharles Keepax if (rtd->pop_wait == 1) { 241202c8f70SCharles Keepax rtd->pop_wait = 0; 242202c8f70SCharles Keepax snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, 243202c8f70SCharles Keepax SND_SOC_DAPM_STREAM_STOP); 244202c8f70SCharles Keepax } 245202c8f70SCharles Keepax 246202c8f70SCharles Keepax mutex_unlock(&rtd->pcm_mutex); 247202c8f70SCharles Keepax } 248202c8f70SCharles Keepax 2491245b700SNamarta Kohli static int soc_compr_free(struct snd_compr_stream *cstream) 2501245b700SNamarta Kohli { 2511245b700SNamarta Kohli struct snd_soc_pcm_runtime *rtd = cstream->private_data; 2521245b700SNamarta Kohli struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 2531245b700SNamarta Kohli struct snd_soc_dai *codec_dai = rtd->codec_dai; 25424894b76SLars-Peter Clausen int stream; 2551245b700SNamarta Kohli 25615e2e619SCharles Keepax mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); 25715e2e619SCharles Keepax 25824894b76SLars-Peter Clausen if (cstream->direction == SND_COMPRESS_PLAYBACK) 25924894b76SLars-Peter Clausen stream = SNDRV_PCM_STREAM_PLAYBACK; 26024894b76SLars-Peter Clausen else 26124894b76SLars-Peter Clausen stream = SNDRV_PCM_STREAM_CAPTURE; 26224894b76SLars-Peter Clausen 26324894b76SLars-Peter Clausen snd_soc_runtime_deactivate(rtd, stream); 2641245b700SNamarta Kohli 265da18396fSMark Brown snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction); 266da18396fSMark Brown 2671245b700SNamarta Kohli if (!cpu_dai->active) 2681245b700SNamarta Kohli cpu_dai->rate = 0; 2691245b700SNamarta Kohli 2701245b700SNamarta Kohli if (!codec_dai->active) 2711245b700SNamarta Kohli codec_dai->rate = 0; 2721245b700SNamarta Kohli 2731245b700SNamarta Kohli if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown) 2741245b700SNamarta Kohli rtd->dai_link->compr_ops->shutdown(cstream); 2751245b700SNamarta Kohli 2761e57b828SCharles Keepax soc_compr_components_free(cstream, NULL); 2779e7e3738SKuninori Morimoto 2782e622ae4SVinod Koul if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown) 2792e622ae4SVinod Koul cpu_dai->driver->cops->shutdown(cstream, cpu_dai); 2802e622ae4SVinod Koul 2811245b700SNamarta Kohli if (cstream->direction == SND_COMPRESS_PLAYBACK) { 282208a1589SLars-Peter Clausen if (snd_soc_runtime_ignore_pmdown_time(rtd)) { 2831245b700SNamarta Kohli snd_soc_dapm_stream_event(rtd, 2841245b700SNamarta Kohli SNDRV_PCM_STREAM_PLAYBACK, 2851245b700SNamarta Kohli SND_SOC_DAPM_STREAM_STOP); 2868c3d2aa4SCharles Keepax } else { 2879bffb1fbSMisael Lopez Cruz rtd->pop_wait = 1; 2883d24cfe4SMark Brown queue_delayed_work(system_power_efficient_wq, 2893d24cfe4SMark Brown &rtd->delayed_work, 2901245b700SNamarta Kohli msecs_to_jiffies(rtd->pmdown_time)); 2918c3d2aa4SCharles Keepax } 2921245b700SNamarta Kohli } else { 2931245b700SNamarta Kohli /* capture streams can be powered down now */ 2941245b700SNamarta Kohli snd_soc_dapm_stream_event(rtd, 2951245b700SNamarta Kohli SNDRV_PCM_STREAM_CAPTURE, 2961245b700SNamarta Kohli SND_SOC_DAPM_STREAM_STOP); 2971245b700SNamarta Kohli } 2981245b700SNamarta Kohli 29915e2e619SCharles Keepax mutex_unlock(&rtd->pcm_mutex); 3001245b700SNamarta Kohli return 0; 3011245b700SNamarta Kohli } 3021245b700SNamarta Kohli 3032a99ef0fSLiam Girdwood static int soc_compr_free_fe(struct snd_compr_stream *cstream) 3042a99ef0fSLiam Girdwood { 3052a99ef0fSLiam Girdwood struct snd_soc_pcm_runtime *fe = cstream->private_data; 3062e622ae4SVinod Koul struct snd_soc_dai *cpu_dai = fe->cpu_dai; 3072a99ef0fSLiam Girdwood struct snd_soc_dpcm *dpcm; 3082a99ef0fSLiam Girdwood int stream, ret; 3092a99ef0fSLiam Girdwood 3102a99ef0fSLiam Girdwood mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); 3112a99ef0fSLiam Girdwood 31224894b76SLars-Peter Clausen if (cstream->direction == SND_COMPRESS_PLAYBACK) 3132a99ef0fSLiam Girdwood stream = SNDRV_PCM_STREAM_PLAYBACK; 31424894b76SLars-Peter Clausen else 3152a99ef0fSLiam Girdwood stream = SNDRV_PCM_STREAM_CAPTURE; 3162a99ef0fSLiam Girdwood 31724894b76SLars-Peter Clausen snd_soc_runtime_deactivate(fe, stream); 3182a99ef0fSLiam Girdwood 3192a99ef0fSLiam Girdwood fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; 3202a99ef0fSLiam Girdwood 3212a99ef0fSLiam Girdwood ret = dpcm_be_dai_hw_free(fe, stream); 3222a99ef0fSLiam Girdwood if (ret < 0) 323141dfc9eSCharles Keepax dev_err(fe->dev, "Compressed ASoC: hw_free failed: %d\n", ret); 3242a99ef0fSLiam Girdwood 3252a99ef0fSLiam Girdwood ret = dpcm_be_dai_shutdown(fe, stream); 3262a99ef0fSLiam Girdwood 3272a99ef0fSLiam Girdwood /* mark FE's links ready to prune */ 3282a99ef0fSLiam Girdwood list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) 3292a99ef0fSLiam Girdwood dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; 3302a99ef0fSLiam Girdwood 3312a99ef0fSLiam Girdwood dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP); 3322a99ef0fSLiam Girdwood 3332a99ef0fSLiam Girdwood fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; 3342a99ef0fSLiam Girdwood fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; 3352a99ef0fSLiam Girdwood 3362a99ef0fSLiam Girdwood dpcm_be_disconnect(fe, stream); 3372a99ef0fSLiam Girdwood 3382a99ef0fSLiam Girdwood fe->dpcm[stream].runtime = NULL; 3392a99ef0fSLiam Girdwood 3402a99ef0fSLiam Girdwood if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown) 3412a99ef0fSLiam Girdwood fe->dai_link->compr_ops->shutdown(cstream); 3422a99ef0fSLiam Girdwood 3431e57b828SCharles Keepax soc_compr_components_free(cstream, NULL); 3449e7e3738SKuninori Morimoto 3452e622ae4SVinod Koul if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown) 3462e622ae4SVinod Koul cpu_dai->driver->cops->shutdown(cstream, cpu_dai); 3472e622ae4SVinod Koul 3482a99ef0fSLiam Girdwood mutex_unlock(&fe->card->mutex); 3492a99ef0fSLiam Girdwood return 0; 3502a99ef0fSLiam Girdwood } 3512a99ef0fSLiam Girdwood 3521245b700SNamarta Kohli static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) 3531245b700SNamarta Kohli { 3541245b700SNamarta Kohli 3551245b700SNamarta Kohli struct snd_soc_pcm_runtime *rtd = cstream->private_data; 3569e7e3738SKuninori Morimoto struct snd_soc_component *component; 3579e7e3738SKuninori Morimoto struct snd_soc_rtdcom_list *rtdcom; 3581245b700SNamarta Kohli struct snd_soc_dai *codec_dai = rtd->codec_dai; 3592e622ae4SVinod Koul struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 3609e7e3738SKuninori Morimoto int ret = 0, __ret; 3611245b700SNamarta Kohli 36215e2e619SCharles Keepax mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); 36315e2e619SCharles Keepax 3649e7e3738SKuninori Morimoto for_each_rtdcom(rtd, rtdcom) { 3659e7e3738SKuninori Morimoto component = rtdcom->component; 3669e7e3738SKuninori Morimoto 3679e7e3738SKuninori Morimoto if (!component->driver->compr_ops || 3689e7e3738SKuninori Morimoto !component->driver->compr_ops->trigger) 3699e7e3738SKuninori Morimoto continue; 3709e7e3738SKuninori Morimoto 3719e7e3738SKuninori Morimoto __ret = component->driver->compr_ops->trigger(cstream, cmd); 3729e7e3738SKuninori Morimoto if (__ret < 0) 3739e7e3738SKuninori Morimoto ret = __ret; 3749e7e3738SKuninori Morimoto } 3759e7e3738SKuninori Morimoto if (ret < 0) 3769e7e3738SKuninori Morimoto goto out; 3779e7e3738SKuninori Morimoto 3782e622ae4SVinod Koul if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) 3792e622ae4SVinod Koul cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai); 3802e622ae4SVinod Koul 381e38b9b74SMark Brown switch (cmd) { 382e38b9b74SMark Brown case SNDRV_PCM_TRIGGER_START: 383da18396fSMark Brown snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction); 384e38b9b74SMark Brown break; 385e38b9b74SMark Brown case SNDRV_PCM_TRIGGER_STOP: 386da18396fSMark Brown snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction); 387e38b9b74SMark Brown break; 388e38b9b74SMark Brown } 3891245b700SNamarta Kohli 39015e2e619SCharles Keepax out: 39115e2e619SCharles Keepax mutex_unlock(&rtd->pcm_mutex); 3921245b700SNamarta Kohli return ret; 3931245b700SNamarta Kohli } 3941245b700SNamarta Kohli 3952a99ef0fSLiam Girdwood static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) 3962a99ef0fSLiam Girdwood { 3972a99ef0fSLiam Girdwood struct snd_soc_pcm_runtime *fe = cstream->private_data; 3989e7e3738SKuninori Morimoto struct snd_soc_component *component; 3999e7e3738SKuninori Morimoto struct snd_soc_rtdcom_list *rtdcom; 4002e622ae4SVinod Koul struct snd_soc_dai *cpu_dai = fe->cpu_dai; 4019e7e3738SKuninori Morimoto int ret = 0, __ret, stream; 4022a99ef0fSLiam Girdwood 4032a99ef0fSLiam Girdwood if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN || 4042a99ef0fSLiam Girdwood cmd == SND_COMPR_TRIGGER_DRAIN) { 4052a99ef0fSLiam Girdwood 4069e7e3738SKuninori Morimoto for_each_rtdcom(fe, rtdcom) { 4079e7e3738SKuninori Morimoto component = rtdcom->component; 4089e7e3738SKuninori Morimoto 4099e7e3738SKuninori Morimoto if (!component->driver->compr_ops || 4109e7e3738SKuninori Morimoto !component->driver->compr_ops->trigger) 4119e7e3738SKuninori Morimoto continue; 4129e7e3738SKuninori Morimoto 4139e7e3738SKuninori Morimoto __ret = component->driver->compr_ops->trigger(cstream, cmd); 4149e7e3738SKuninori Morimoto if (__ret < 0) 4159e7e3738SKuninori Morimoto ret = __ret; 4169e7e3738SKuninori Morimoto } 4179e7e3738SKuninori Morimoto return ret; 4182a99ef0fSLiam Girdwood } 4192a99ef0fSLiam Girdwood 4202a99ef0fSLiam Girdwood if (cstream->direction == SND_COMPRESS_PLAYBACK) 4212a99ef0fSLiam Girdwood stream = SNDRV_PCM_STREAM_PLAYBACK; 4222a99ef0fSLiam Girdwood else 4232a99ef0fSLiam Girdwood stream = SNDRV_PCM_STREAM_CAPTURE; 4242a99ef0fSLiam Girdwood 4252a99ef0fSLiam Girdwood mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); 4262a99ef0fSLiam Girdwood 4272e622ae4SVinod Koul if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) { 4282e622ae4SVinod Koul ret = cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai); 4292e622ae4SVinod Koul if (ret < 0) 4302e622ae4SVinod Koul goto out; 4312e622ae4SVinod Koul } 4322e622ae4SVinod Koul 4339e7e3738SKuninori Morimoto for_each_rtdcom(fe, rtdcom) { 4349e7e3738SKuninori Morimoto component = rtdcom->component; 4359e7e3738SKuninori Morimoto 4369e7e3738SKuninori Morimoto if (!component->driver->compr_ops || 4379e7e3738SKuninori Morimoto !component->driver->compr_ops->trigger) 4389e7e3738SKuninori Morimoto continue; 4399e7e3738SKuninori Morimoto 4409e7e3738SKuninori Morimoto __ret = component->driver->compr_ops->trigger(cstream, cmd); 4419e7e3738SKuninori Morimoto if (__ret < 0) 4429e7e3738SKuninori Morimoto ret = __ret; 4439e7e3738SKuninori Morimoto } 4449e7e3738SKuninori Morimoto if (ret < 0) 4459e7e3738SKuninori Morimoto goto out; 4469e7e3738SKuninori Morimoto 4472a99ef0fSLiam Girdwood fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; 4482a99ef0fSLiam Girdwood 4492a99ef0fSLiam Girdwood ret = dpcm_be_dai_trigger(fe, stream, cmd); 4502a99ef0fSLiam Girdwood 4512a99ef0fSLiam Girdwood switch (cmd) { 4522a99ef0fSLiam Girdwood case SNDRV_PCM_TRIGGER_START: 4532a99ef0fSLiam Girdwood case SNDRV_PCM_TRIGGER_RESUME: 4542a99ef0fSLiam Girdwood case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 4552a99ef0fSLiam Girdwood fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START; 4562a99ef0fSLiam Girdwood break; 4572a99ef0fSLiam Girdwood case SNDRV_PCM_TRIGGER_STOP: 4582a99ef0fSLiam Girdwood case SNDRV_PCM_TRIGGER_SUSPEND: 4592a99ef0fSLiam Girdwood fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP; 4602a99ef0fSLiam Girdwood break; 4612a99ef0fSLiam Girdwood case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 4622a99ef0fSLiam Girdwood fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED; 4632a99ef0fSLiam Girdwood break; 4642a99ef0fSLiam Girdwood } 4652a99ef0fSLiam Girdwood 4662a99ef0fSLiam Girdwood out: 4672a99ef0fSLiam Girdwood fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; 4682a99ef0fSLiam Girdwood mutex_unlock(&fe->card->mutex); 4692a99ef0fSLiam Girdwood return ret; 4702a99ef0fSLiam Girdwood } 4712a99ef0fSLiam Girdwood 4721245b700SNamarta Kohli static int soc_compr_set_params(struct snd_compr_stream *cstream, 4731245b700SNamarta Kohli struct snd_compr_params *params) 4741245b700SNamarta Kohli { 4751245b700SNamarta Kohli struct snd_soc_pcm_runtime *rtd = cstream->private_data; 4769e7e3738SKuninori Morimoto struct snd_soc_component *component; 4779e7e3738SKuninori Morimoto struct snd_soc_rtdcom_list *rtdcom; 4782e622ae4SVinod Koul struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 4799e7e3738SKuninori Morimoto int ret = 0, __ret; 4801245b700SNamarta Kohli 48115e2e619SCharles Keepax mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); 48215e2e619SCharles Keepax 483ef050becSCharles Keepax /* 484ef050becSCharles Keepax * First we call set_params for the CPU DAI, then the component 485ef050becSCharles Keepax * driver this should configure the SoC side. If the machine has 486ef050becSCharles Keepax * compressed ops then we call that as well. The expectation is 487ef050becSCharles Keepax * that these callbacks will configure everything for this compress 488ef050becSCharles Keepax * path, like configuring a PCM port for a CODEC. 4891245b700SNamarta Kohli */ 4902e622ae4SVinod Koul if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) { 4912e622ae4SVinod Koul ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai); 4922e622ae4SVinod Koul if (ret < 0) 4932e622ae4SVinod Koul goto err; 4942e622ae4SVinod Koul } 4952e622ae4SVinod Koul 4969e7e3738SKuninori Morimoto for_each_rtdcom(rtd, rtdcom) { 4979e7e3738SKuninori Morimoto component = rtdcom->component; 4989e7e3738SKuninori Morimoto 4999e7e3738SKuninori Morimoto if (!component->driver->compr_ops || 5009e7e3738SKuninori Morimoto !component->driver->compr_ops->set_params) 5019e7e3738SKuninori Morimoto continue; 5029e7e3738SKuninori Morimoto 5039e7e3738SKuninori Morimoto __ret = component->driver->compr_ops->set_params(cstream, params); 5049e7e3738SKuninori Morimoto if (__ret < 0) 5059e7e3738SKuninori Morimoto ret = __ret; 5069e7e3738SKuninori Morimoto } 5079e7e3738SKuninori Morimoto if (ret < 0) 5089e7e3738SKuninori Morimoto goto err; 5099e7e3738SKuninori Morimoto 5101245b700SNamarta Kohli if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) { 5111245b700SNamarta Kohli ret = rtd->dai_link->compr_ops->set_params(cstream); 5121245b700SNamarta Kohli if (ret < 0) 513fa40ef20SCharles Keepax goto err; 5141245b700SNamarta Kohli } 5151245b700SNamarta Kohli 5162c071ed7SCharles Keepax if (cstream->direction == SND_COMPRESS_PLAYBACK) 5171245b700SNamarta Kohli snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, 5181245b700SNamarta Kohli SND_SOC_DAPM_STREAM_START); 5192c071ed7SCharles Keepax else 5202c071ed7SCharles Keepax snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE, 5212c071ed7SCharles Keepax SND_SOC_DAPM_STREAM_START); 5221245b700SNamarta Kohli 523fa40ef20SCharles Keepax /* cancel any delayed stream shutdown that is pending */ 524fa40ef20SCharles Keepax rtd->pop_wait = 0; 525fa40ef20SCharles Keepax mutex_unlock(&rtd->pcm_mutex); 526fa40ef20SCharles Keepax 527fa40ef20SCharles Keepax cancel_delayed_work_sync(&rtd->delayed_work); 528fa40ef20SCharles Keepax 529fa40ef20SCharles Keepax return ret; 530fa40ef20SCharles Keepax 531fa40ef20SCharles Keepax err: 53215e2e619SCharles Keepax mutex_unlock(&rtd->pcm_mutex); 5331245b700SNamarta Kohli return ret; 5341245b700SNamarta Kohli } 5351245b700SNamarta Kohli 5362a99ef0fSLiam Girdwood static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, 5372a99ef0fSLiam Girdwood struct snd_compr_params *params) 5382a99ef0fSLiam Girdwood { 5392a99ef0fSLiam Girdwood struct snd_soc_pcm_runtime *fe = cstream->private_data; 54001b8cedfSSatish Babu Patakokila struct snd_pcm_substream *fe_substream = 54101b8cedfSSatish Babu Patakokila fe->pcm->streams[cstream->direction].substream; 5429e7e3738SKuninori Morimoto struct snd_soc_component *component; 5439e7e3738SKuninori Morimoto struct snd_soc_rtdcom_list *rtdcom; 5442e622ae4SVinod Koul struct snd_soc_dai *cpu_dai = fe->cpu_dai; 5459e7e3738SKuninori Morimoto int ret = 0, __ret, stream; 5462a99ef0fSLiam Girdwood 5472a99ef0fSLiam Girdwood if (cstream->direction == SND_COMPRESS_PLAYBACK) 5482a99ef0fSLiam Girdwood stream = SNDRV_PCM_STREAM_PLAYBACK; 5492a99ef0fSLiam Girdwood else 5502a99ef0fSLiam Girdwood stream = SNDRV_PCM_STREAM_CAPTURE; 5512a99ef0fSLiam Girdwood 5522a99ef0fSLiam Girdwood mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); 5532a99ef0fSLiam Girdwood 5542e622ae4SVinod Koul if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) { 5552e622ae4SVinod Koul ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai); 5562e622ae4SVinod Koul if (ret < 0) 5572e622ae4SVinod Koul goto out; 5582e622ae4SVinod Koul } 5592e622ae4SVinod Koul 5609e7e3738SKuninori Morimoto for_each_rtdcom(fe, rtdcom) { 5619e7e3738SKuninori Morimoto component = rtdcom->component; 5629e7e3738SKuninori Morimoto 5639e7e3738SKuninori Morimoto if (!component->driver->compr_ops || 5649e7e3738SKuninori Morimoto !component->driver->compr_ops->set_params) 5659e7e3738SKuninori Morimoto continue; 5669e7e3738SKuninori Morimoto 5679e7e3738SKuninori Morimoto __ret = component->driver->compr_ops->set_params(cstream, params); 5689e7e3738SKuninori Morimoto if (__ret < 0) 5699e7e3738SKuninori Morimoto ret = __ret; 5709e7e3738SKuninori Morimoto } 5719e7e3738SKuninori Morimoto if (ret < 0) 5729e7e3738SKuninori Morimoto goto out; 5739e7e3738SKuninori Morimoto 5742a99ef0fSLiam Girdwood if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) { 5752a99ef0fSLiam Girdwood ret = fe->dai_link->compr_ops->set_params(cstream); 5762a99ef0fSLiam Girdwood if (ret < 0) 5772a99ef0fSLiam Girdwood goto out; 5782a99ef0fSLiam Girdwood } 5792a99ef0fSLiam Girdwood 5802a99ef0fSLiam Girdwood /* 5812a99ef0fSLiam Girdwood * Create an empty hw_params for the BE as the machine driver must 5822a99ef0fSLiam Girdwood * fix this up to match DSP decoder and ASRC configuration. 5832a99ef0fSLiam Girdwood * I.e. machine driver fixup for compressed BE is mandatory. 5842a99ef0fSLiam Girdwood */ 5852a99ef0fSLiam Girdwood memset(&fe->dpcm[fe_substream->stream].hw_params, 0, 5862a99ef0fSLiam Girdwood sizeof(struct snd_pcm_hw_params)); 5872a99ef0fSLiam Girdwood 5882a99ef0fSLiam Girdwood fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; 5892a99ef0fSLiam Girdwood 5902a99ef0fSLiam Girdwood ret = dpcm_be_dai_hw_params(fe, stream); 5912a99ef0fSLiam Girdwood if (ret < 0) 5922a99ef0fSLiam Girdwood goto out; 5932a99ef0fSLiam Girdwood 5942a99ef0fSLiam Girdwood ret = dpcm_be_dai_prepare(fe, stream); 5952a99ef0fSLiam Girdwood if (ret < 0) 5962a99ef0fSLiam Girdwood goto out; 5972a99ef0fSLiam Girdwood 5982a99ef0fSLiam Girdwood dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START); 5992a99ef0fSLiam Girdwood fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE; 6002a99ef0fSLiam Girdwood 6012a99ef0fSLiam Girdwood out: 6022a99ef0fSLiam Girdwood fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; 6032a99ef0fSLiam Girdwood mutex_unlock(&fe->card->mutex); 6042a99ef0fSLiam Girdwood return ret; 6052a99ef0fSLiam Girdwood } 6062a99ef0fSLiam Girdwood 6071245b700SNamarta Kohli static int soc_compr_get_params(struct snd_compr_stream *cstream, 6081245b700SNamarta Kohli struct snd_codec *params) 6091245b700SNamarta Kohli { 6101245b700SNamarta Kohli struct snd_soc_pcm_runtime *rtd = cstream->private_data; 6119e7e3738SKuninori Morimoto struct snd_soc_component *component; 6129e7e3738SKuninori Morimoto struct snd_soc_rtdcom_list *rtdcom; 6132e622ae4SVinod Koul struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 6149e7e3738SKuninori Morimoto int ret = 0, __ret; 6151245b700SNamarta Kohli 61615e2e619SCharles Keepax mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); 61715e2e619SCharles Keepax 6182e622ae4SVinod Koul if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_params) { 6192e622ae4SVinod Koul ret = cpu_dai->driver->cops->get_params(cstream, params, cpu_dai); 6202e622ae4SVinod Koul if (ret < 0) 6212e622ae4SVinod Koul goto err; 6222e622ae4SVinod Koul } 6232e622ae4SVinod Koul 6249e7e3738SKuninori Morimoto for_each_rtdcom(rtd, rtdcom) { 6259e7e3738SKuninori Morimoto component = rtdcom->component; 6269e7e3738SKuninori Morimoto 6279e7e3738SKuninori Morimoto if (!component->driver->compr_ops || 6289e7e3738SKuninori Morimoto !component->driver->compr_ops->get_params) 6299e7e3738SKuninori Morimoto continue; 6309e7e3738SKuninori Morimoto 6319e7e3738SKuninori Morimoto __ret = component->driver->compr_ops->get_params(cstream, params); 6329e7e3738SKuninori Morimoto if (__ret < 0) 6339e7e3738SKuninori Morimoto ret = __ret; 6349e7e3738SKuninori Morimoto } 6351245b700SNamarta Kohli 6362e622ae4SVinod Koul err: 63715e2e619SCharles Keepax mutex_unlock(&rtd->pcm_mutex); 6381245b700SNamarta Kohli return ret; 6391245b700SNamarta Kohli } 6401245b700SNamarta Kohli 6411245b700SNamarta Kohli static int soc_compr_get_caps(struct snd_compr_stream *cstream, 6421245b700SNamarta Kohli struct snd_compr_caps *caps) 6431245b700SNamarta Kohli { 6441245b700SNamarta Kohli struct snd_soc_pcm_runtime *rtd = cstream->private_data; 6459e7e3738SKuninori Morimoto struct snd_soc_component *component; 6469e7e3738SKuninori Morimoto struct snd_soc_rtdcom_list *rtdcom; 6479e7e3738SKuninori Morimoto int ret = 0, __ret; 6481245b700SNamarta Kohli 64915e2e619SCharles Keepax mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); 65015e2e619SCharles Keepax 6519e7e3738SKuninori Morimoto for_each_rtdcom(rtd, rtdcom) { 6529e7e3738SKuninori Morimoto component = rtdcom->component; 6539e7e3738SKuninori Morimoto 6549e7e3738SKuninori Morimoto if (!component->driver->compr_ops || 6559e7e3738SKuninori Morimoto !component->driver->compr_ops->get_caps) 6569e7e3738SKuninori Morimoto continue; 6579e7e3738SKuninori Morimoto 6589e7e3738SKuninori Morimoto __ret = component->driver->compr_ops->get_caps(cstream, caps); 6599e7e3738SKuninori Morimoto if (__ret < 0) 6609e7e3738SKuninori Morimoto ret = __ret; 6619e7e3738SKuninori Morimoto } 6629e7e3738SKuninori Morimoto 66315e2e619SCharles Keepax mutex_unlock(&rtd->pcm_mutex); 6641245b700SNamarta Kohli return ret; 6651245b700SNamarta Kohli } 6661245b700SNamarta Kohli 6671245b700SNamarta Kohli static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, 6681245b700SNamarta Kohli struct snd_compr_codec_caps *codec) 6691245b700SNamarta Kohli { 6701245b700SNamarta Kohli struct snd_soc_pcm_runtime *rtd = cstream->private_data; 6719e7e3738SKuninori Morimoto struct snd_soc_component *component; 6729e7e3738SKuninori Morimoto struct snd_soc_rtdcom_list *rtdcom; 6739e7e3738SKuninori Morimoto int ret = 0, __ret; 6741245b700SNamarta Kohli 67515e2e619SCharles Keepax mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); 67615e2e619SCharles Keepax 6779e7e3738SKuninori Morimoto for_each_rtdcom(rtd, rtdcom) { 6789e7e3738SKuninori Morimoto component = rtdcom->component; 6799e7e3738SKuninori Morimoto 6809e7e3738SKuninori Morimoto if (!component->driver->compr_ops || 6819e7e3738SKuninori Morimoto !component->driver->compr_ops->get_codec_caps) 6829e7e3738SKuninori Morimoto continue; 6839e7e3738SKuninori Morimoto 6849e7e3738SKuninori Morimoto __ret = component->driver->compr_ops->get_codec_caps(cstream, codec); 6859e7e3738SKuninori Morimoto if (__ret < 0) 6869e7e3738SKuninori Morimoto ret = __ret; 6879e7e3738SKuninori Morimoto } 6889e7e3738SKuninori Morimoto 68915e2e619SCharles Keepax mutex_unlock(&rtd->pcm_mutex); 6901245b700SNamarta Kohli return ret; 6911245b700SNamarta Kohli } 6921245b700SNamarta Kohli 6931245b700SNamarta Kohli static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) 6941245b700SNamarta Kohli { 6951245b700SNamarta Kohli struct snd_soc_pcm_runtime *rtd = cstream->private_data; 6969e7e3738SKuninori Morimoto struct snd_soc_component *component; 6979e7e3738SKuninori Morimoto struct snd_soc_rtdcom_list *rtdcom; 6982e622ae4SVinod Koul struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 6999e7e3738SKuninori Morimoto int ret = 0, __ret; 7001245b700SNamarta Kohli 70115e2e619SCharles Keepax mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); 70215e2e619SCharles Keepax 7032e622ae4SVinod Koul if (cpu_dai->driver->cops && cpu_dai->driver->cops->ack) { 7042e622ae4SVinod Koul ret = cpu_dai->driver->cops->ack(cstream, bytes, cpu_dai); 7052e622ae4SVinod Koul if (ret < 0) 7062e622ae4SVinod Koul goto err; 7072e622ae4SVinod Koul } 7082e622ae4SVinod Koul 7099e7e3738SKuninori Morimoto for_each_rtdcom(rtd, rtdcom) { 7109e7e3738SKuninori Morimoto component = rtdcom->component; 7119e7e3738SKuninori Morimoto 7129e7e3738SKuninori Morimoto if (!component->driver->compr_ops || 7139e7e3738SKuninori Morimoto !component->driver->compr_ops->ack) 7149e7e3738SKuninori Morimoto continue; 7159e7e3738SKuninori Morimoto 7169e7e3738SKuninori Morimoto __ret = component->driver->compr_ops->ack(cstream, bytes); 7179e7e3738SKuninori Morimoto if (__ret < 0) 7189e7e3738SKuninori Morimoto ret = __ret; 7199e7e3738SKuninori Morimoto } 7201245b700SNamarta Kohli 7212e622ae4SVinod Koul err: 72215e2e619SCharles Keepax mutex_unlock(&rtd->pcm_mutex); 7231245b700SNamarta Kohli return ret; 7241245b700SNamarta Kohli } 7251245b700SNamarta Kohli 7261245b700SNamarta Kohli static int soc_compr_pointer(struct snd_compr_stream *cstream, 7271245b700SNamarta Kohli struct snd_compr_tstamp *tstamp) 7281245b700SNamarta Kohli { 7291245b700SNamarta Kohli struct snd_soc_pcm_runtime *rtd = cstream->private_data; 7309e7e3738SKuninori Morimoto struct snd_soc_component *component; 7319e7e3738SKuninori Morimoto struct snd_soc_rtdcom_list *rtdcom; 7329e7e3738SKuninori Morimoto int ret = 0, __ret; 7332e622ae4SVinod Koul struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 7341245b700SNamarta Kohli 73515e2e619SCharles Keepax mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); 73615e2e619SCharles Keepax 7372e622ae4SVinod Koul if (cpu_dai->driver->cops && cpu_dai->driver->cops->pointer) 7382e622ae4SVinod Koul cpu_dai->driver->cops->pointer(cstream, tstamp, cpu_dai); 7392e622ae4SVinod Koul 7409e7e3738SKuninori Morimoto for_each_rtdcom(rtd, rtdcom) { 7419e7e3738SKuninori Morimoto component = rtdcom->component; 7429e7e3738SKuninori Morimoto 7439e7e3738SKuninori Morimoto if (!component->driver->compr_ops || 7449e7e3738SKuninori Morimoto !component->driver->compr_ops->pointer) 7459e7e3738SKuninori Morimoto continue; 7469e7e3738SKuninori Morimoto 7479e7e3738SKuninori Morimoto __ret = component->driver->compr_ops->pointer(cstream, tstamp); 7489e7e3738SKuninori Morimoto if (__ret < 0) 7499e7e3738SKuninori Morimoto ret = __ret; 7509e7e3738SKuninori Morimoto } 7519e7e3738SKuninori Morimoto 75215e2e619SCharles Keepax mutex_unlock(&rtd->pcm_mutex); 7537c9190f7SCharles Keepax return ret; 7541245b700SNamarta Kohli } 7551245b700SNamarta Kohli 7561f88eb0fSCharles Keepax static int soc_compr_copy(struct snd_compr_stream *cstream, 7574daf891cSCharles Keepax char __user *buf, size_t count) 7581f88eb0fSCharles Keepax { 7591f88eb0fSCharles Keepax struct snd_soc_pcm_runtime *rtd = cstream->private_data; 7609e7e3738SKuninori Morimoto struct snd_soc_component *component; 7619e7e3738SKuninori Morimoto struct snd_soc_rtdcom_list *rtdcom; 762290df4d3SCharles Keepax int ret = 0; 7631f88eb0fSCharles Keepax 7641f88eb0fSCharles Keepax mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); 7651f88eb0fSCharles Keepax 7669e7e3738SKuninori Morimoto for_each_rtdcom(rtd, rtdcom) { 7679e7e3738SKuninori Morimoto component = rtdcom->component; 7689e7e3738SKuninori Morimoto 7699e7e3738SKuninori Morimoto if (!component->driver->compr_ops || 7709e7e3738SKuninori Morimoto !component->driver->compr_ops->copy) 7719e7e3738SKuninori Morimoto continue; 7729e7e3738SKuninori Morimoto 773290df4d3SCharles Keepax ret = component->driver->compr_ops->copy(cstream, buf, count); 774290df4d3SCharles Keepax break; 7759e7e3738SKuninori Morimoto } 776290df4d3SCharles Keepax 7771f88eb0fSCharles Keepax mutex_unlock(&rtd->pcm_mutex); 7781f88eb0fSCharles Keepax return ret; 7791f88eb0fSCharles Keepax } 7801f88eb0fSCharles Keepax 78102bd90e8SVinod Koul static int soc_compr_set_metadata(struct snd_compr_stream *cstream, 78236953d98SJeeja KP struct snd_compr_metadata *metadata) 78336953d98SJeeja KP { 78436953d98SJeeja KP struct snd_soc_pcm_runtime *rtd = cstream->private_data; 7859e7e3738SKuninori Morimoto struct snd_soc_component *component; 7869e7e3738SKuninori Morimoto struct snd_soc_rtdcom_list *rtdcom; 7872e622ae4SVinod Koul struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 7889e7e3738SKuninori Morimoto int ret = 0, __ret; 78936953d98SJeeja KP 7902e622ae4SVinod Koul if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_metadata) { 7912e622ae4SVinod Koul ret = cpu_dai->driver->cops->set_metadata(cstream, metadata, cpu_dai); 7922e622ae4SVinod Koul if (ret < 0) 7932e622ae4SVinod Koul return ret; 7942e622ae4SVinod Koul } 7952e622ae4SVinod Koul 7969e7e3738SKuninori Morimoto for_each_rtdcom(rtd, rtdcom) { 7979e7e3738SKuninori Morimoto component = rtdcom->component; 7989e7e3738SKuninori Morimoto 7999e7e3738SKuninori Morimoto if (!component->driver->compr_ops || 8009e7e3738SKuninori Morimoto !component->driver->compr_ops->set_metadata) 8019e7e3738SKuninori Morimoto continue; 8029e7e3738SKuninori Morimoto 8039e7e3738SKuninori Morimoto __ret = component->driver->compr_ops->set_metadata(cstream, metadata); 8049e7e3738SKuninori Morimoto if (__ret < 0) 8059e7e3738SKuninori Morimoto ret = __ret; 8069e7e3738SKuninori Morimoto } 80736953d98SJeeja KP 80836953d98SJeeja KP return ret; 80936953d98SJeeja KP } 81036953d98SJeeja KP 81102bd90e8SVinod Koul static int soc_compr_get_metadata(struct snd_compr_stream *cstream, 81236953d98SJeeja KP struct snd_compr_metadata *metadata) 81336953d98SJeeja KP { 81436953d98SJeeja KP struct snd_soc_pcm_runtime *rtd = cstream->private_data; 8159e7e3738SKuninori Morimoto struct snd_soc_component *component; 8169e7e3738SKuninori Morimoto struct snd_soc_rtdcom_list *rtdcom; 8172e622ae4SVinod Koul struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 8189e7e3738SKuninori Morimoto int ret = 0, __ret; 81936953d98SJeeja KP 8202e622ae4SVinod Koul if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_metadata) { 8212e622ae4SVinod Koul ret = cpu_dai->driver->cops->get_metadata(cstream, metadata, cpu_dai); 8222e622ae4SVinod Koul if (ret < 0) 8232e622ae4SVinod Koul return ret; 8242e622ae4SVinod Koul } 8252e622ae4SVinod Koul 8269e7e3738SKuninori Morimoto for_each_rtdcom(rtd, rtdcom) { 8279e7e3738SKuninori Morimoto component = rtdcom->component; 8289e7e3738SKuninori Morimoto 8299e7e3738SKuninori Morimoto if (!component->driver->compr_ops || 8309e7e3738SKuninori Morimoto !component->driver->compr_ops->get_metadata) 8319e7e3738SKuninori Morimoto continue; 8329e7e3738SKuninori Morimoto 8339e7e3738SKuninori Morimoto __ret = component->driver->compr_ops->get_metadata(cstream, metadata); 8349e7e3738SKuninori Morimoto if (__ret < 0) 8359e7e3738SKuninori Morimoto ret = __ret; 8369e7e3738SKuninori Morimoto } 83736953d98SJeeja KP 83836953d98SJeeja KP return ret; 83936953d98SJeeja KP } 8402a99ef0fSLiam Girdwood 8411245b700SNamarta Kohli /* ASoC Compress operations */ 8421245b700SNamarta Kohli static struct snd_compr_ops soc_compr_ops = { 8431245b700SNamarta Kohli .open = soc_compr_open, 8441245b700SNamarta Kohli .free = soc_compr_free, 8451245b700SNamarta Kohli .set_params = soc_compr_set_params, 84602bd90e8SVinod Koul .set_metadata = soc_compr_set_metadata, 84702bd90e8SVinod Koul .get_metadata = soc_compr_get_metadata, 8481245b700SNamarta Kohli .get_params = soc_compr_get_params, 8491245b700SNamarta Kohli .trigger = soc_compr_trigger, 8501245b700SNamarta Kohli .pointer = soc_compr_pointer, 8511245b700SNamarta Kohli .ack = soc_compr_ack, 8521245b700SNamarta Kohli .get_caps = soc_compr_get_caps, 8531245b700SNamarta Kohli .get_codec_caps = soc_compr_get_codec_caps 8541245b700SNamarta Kohli }; 8551245b700SNamarta Kohli 8562a99ef0fSLiam Girdwood /* ASoC Dynamic Compress operations */ 8572a99ef0fSLiam Girdwood static struct snd_compr_ops soc_compr_dyn_ops = { 8582a99ef0fSLiam Girdwood .open = soc_compr_open_fe, 8592a99ef0fSLiam Girdwood .free = soc_compr_free_fe, 8602a99ef0fSLiam Girdwood .set_params = soc_compr_set_params_fe, 8612a99ef0fSLiam Girdwood .get_params = soc_compr_get_params, 8622a99ef0fSLiam Girdwood .set_metadata = soc_compr_set_metadata, 8632a99ef0fSLiam Girdwood .get_metadata = soc_compr_get_metadata, 8642a99ef0fSLiam Girdwood .trigger = soc_compr_trigger_fe, 8652a99ef0fSLiam Girdwood .pointer = soc_compr_pointer, 8662a99ef0fSLiam Girdwood .ack = soc_compr_ack, 8672a99ef0fSLiam Girdwood .get_caps = soc_compr_get_caps, 8682a99ef0fSLiam Girdwood .get_codec_caps = soc_compr_get_codec_caps 8692a99ef0fSLiam Girdwood }; 8702a99ef0fSLiam Girdwood 8716f0c4226SJie Yang /** 8726f0c4226SJie Yang * snd_soc_new_compress - create a new compress. 8736f0c4226SJie Yang * 8746f0c4226SJie Yang * @rtd: The runtime for which we will create compress 8756f0c4226SJie Yang * @num: the device index number (zero based - shared with normal PCMs) 8766f0c4226SJie Yang * 8776f0c4226SJie Yang * Return: 0 for success, else error. 8786f0c4226SJie Yang */ 8796f0c4226SJie Yang int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) 8801245b700SNamarta Kohli { 8819e7e3738SKuninori Morimoto struct snd_soc_component *component; 8829e7e3738SKuninori Morimoto struct snd_soc_rtdcom_list *rtdcom; 8831245b700SNamarta Kohli struct snd_soc_dai *codec_dai = rtd->codec_dai; 8841245b700SNamarta Kohli struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 8851245b700SNamarta Kohli struct snd_compr *compr; 8862a99ef0fSLiam Girdwood struct snd_pcm *be_pcm; 8871245b700SNamarta Kohli char new_name[64]; 8881245b700SNamarta Kohli int ret = 0, direction = 0; 889a1068045SVinod Koul int playback = 0, capture = 0; 8901245b700SNamarta Kohli 8918151d5e6SBenoit Cousson if (rtd->num_codecs > 1) { 892141dfc9eSCharles Keepax dev_err(rtd->card->dev, 893141dfc9eSCharles Keepax "Compress ASoC: Multicodec not supported\n"); 8948151d5e6SBenoit Cousson return -EINVAL; 8958151d5e6SBenoit Cousson } 8968151d5e6SBenoit Cousson 8971245b700SNamarta Kohli /* check client and interface hw capabilities */ 898daa2db59SCharles Keepax if (codec_dai->driver->playback.channels_min) 899a1068045SVinod Koul playback = 1; 900a1068045SVinod Koul if (codec_dai->driver->capture.channels_min) 901a1068045SVinod Koul capture = 1; 902a1068045SVinod Koul 903a1068045SVinod Koul capture = capture && cpu_dai->driver->capture.channels_min; 904a1068045SVinod Koul playback = playback && cpu_dai->driver->playback.channels_min; 905a1068045SVinod Koul 906a1068045SVinod Koul /* 907a1068045SVinod Koul * Compress devices are unidirectional so only one of the directions 908a1068045SVinod Koul * should be set, check for that (xor) 909a1068045SVinod Koul */ 910a1068045SVinod Koul if (playback + capture != 1) { 911141dfc9eSCharles Keepax dev_err(rtd->card->dev, 912141dfc9eSCharles Keepax "Compress ASoC: Invalid direction for P %d, C %d\n", 913a1068045SVinod Koul playback, capture); 914daa2db59SCharles Keepax return -EINVAL; 915a1068045SVinod Koul } 916a1068045SVinod Koul 917a1068045SVinod Koul if (playback) 918a1068045SVinod Koul direction = SND_COMPRESS_PLAYBACK; 919a1068045SVinod Koul else 920a1068045SVinod Koul direction = SND_COMPRESS_CAPTURE; 921daa2db59SCharles Keepax 9221245b700SNamarta Kohli compr = kzalloc(sizeof(*compr), GFP_KERNEL); 9237a0cf42eSMarkus Elfring if (!compr) 9241245b700SNamarta Kohli return -ENOMEM; 9251245b700SNamarta Kohli 9261f88eb0fSCharles Keepax compr->ops = devm_kzalloc(rtd->card->dev, sizeof(soc_compr_ops), 9271f88eb0fSCharles Keepax GFP_KERNEL); 9287a0cf42eSMarkus Elfring if (!compr->ops) { 9291f88eb0fSCharles Keepax ret = -ENOMEM; 9301f88eb0fSCharles Keepax goto compr_err; 9311f88eb0fSCharles Keepax } 9322a99ef0fSLiam Girdwood 9332a99ef0fSLiam Girdwood if (rtd->dai_link->dynamic) { 9342a99ef0fSLiam Girdwood snprintf(new_name, sizeof(new_name), "(%s)", 9352a99ef0fSLiam Girdwood rtd->dai_link->stream_name); 9362a99ef0fSLiam Girdwood 9372a99ef0fSLiam Girdwood ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num, 938d3268a40SQais Yousef rtd->dai_link->dpcm_playback, 939d3268a40SQais Yousef rtd->dai_link->dpcm_capture, &be_pcm); 9402a99ef0fSLiam Girdwood if (ret < 0) { 941141dfc9eSCharles Keepax dev_err(rtd->card->dev, 942141dfc9eSCharles Keepax "Compress ASoC: can't create compressed for %s: %d\n", 943141dfc9eSCharles Keepax rtd->dai_link->name, ret); 9442a99ef0fSLiam Girdwood goto compr_err; 9452a99ef0fSLiam Girdwood } 9462a99ef0fSLiam Girdwood 9472a99ef0fSLiam Girdwood rtd->pcm = be_pcm; 9482a99ef0fSLiam Girdwood rtd->fe_compr = 1; 949d3268a40SQais Yousef if (rtd->dai_link->dpcm_playback) 9502a99ef0fSLiam Girdwood be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd; 951d3268a40SQais Yousef else if (rtd->dai_link->dpcm_capture) 9522a99ef0fSLiam Girdwood be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd; 9532a99ef0fSLiam Girdwood memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops)); 954aeb6fa0fSPeng Donglin } else { 955aeb6fa0fSPeng Donglin snprintf(new_name, sizeof(new_name), "%s %s-%d", 956aeb6fa0fSPeng Donglin rtd->dai_link->stream_name, codec_dai->name, num); 957aeb6fa0fSPeng Donglin 9581f88eb0fSCharles Keepax memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops)); 959aeb6fa0fSPeng Donglin } 9601f88eb0fSCharles Keepax 9619e7e3738SKuninori Morimoto for_each_rtdcom(rtd, rtdcom) { 9629e7e3738SKuninori Morimoto component = rtdcom->component; 9639e7e3738SKuninori Morimoto 9649e7e3738SKuninori Morimoto if (!component->driver->compr_ops || 9659e7e3738SKuninori Morimoto !component->driver->compr_ops->copy) 9669e7e3738SKuninori Morimoto continue; 9679e7e3738SKuninori Morimoto 9689e7e3738SKuninori Morimoto compr->ops->copy = soc_compr_copy; 969ca76db6cSCharles Keepax break; 9709e7e3738SKuninori Morimoto } 9719e7e3738SKuninori Morimoto 9721245b700SNamarta Kohli mutex_init(&compr->lock); 973e5241a8cSRichard Fitzgerald ret = snd_compress_new(rtd->card->snd_card, num, direction, 974e5241a8cSRichard Fitzgerald new_name, compr); 9751245b700SNamarta Kohli if (ret < 0) { 976e5acfc7dSKuninori Morimoto component = rtd->codec_dai->component; 977141dfc9eSCharles Keepax dev_err(component->dev, 978141dfc9eSCharles Keepax "Compress ASoC: can't create compress for codec %s: %d\n", 979141dfc9eSCharles Keepax component->name, ret); 9801f88eb0fSCharles Keepax goto compr_err; 9811245b700SNamarta Kohli } 9821245b700SNamarta Kohli 983202c8f70SCharles Keepax /* DAPM dai link stream work */ 984202c8f70SCharles Keepax INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); 985202c8f70SCharles Keepax 9861245b700SNamarta Kohli rtd->compr = compr; 9871245b700SNamarta Kohli compr->private_data = rtd; 9881245b700SNamarta Kohli 989141dfc9eSCharles Keepax dev_info(rtd->card->dev, "Compress ASoC: %s <-> %s mapping ok\n", 990141dfc9eSCharles Keepax codec_dai->name, cpu_dai->name); 9911245b700SNamarta Kohli return ret; 9921f88eb0fSCharles Keepax 9931f88eb0fSCharles Keepax compr_err: 9941f88eb0fSCharles Keepax kfree(compr); 9951f88eb0fSCharles Keepax return ret; 9961245b700SNamarta Kohli } 9976f0c4226SJie Yang EXPORT_SYMBOL_GPL(snd_soc_new_compress); 998