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