diff options
Diffstat (limited to 'sound/soc/soc-compress.c')
| -rw-r--r-- | sound/soc/soc-compress.c | 194 |
1 files changed, 166 insertions, 28 deletions
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index c1addf49c4f2..736b9c45e59a 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -409,6 +409,37 @@ err: return ret; } +static void dpcm_be_hw_params_prepare(void *data) +{ + struct snd_compr_stream *cstream = data; + struct snd_soc_pcm_runtime *fe = cstream->private_data; + struct snd_soc_pcm_runtime *be = cstream->be; + int stream, ret; + + if (cstream->direction == SND_COMPRESS_PLAYBACK) + stream = SNDRV_PCM_STREAM_PLAYBACK; + else + stream = SNDRV_PCM_STREAM_CAPTURE; + + ret = dpcm_fe_dai_hw_params_be(fe, be, + &fe->dpcm[stream].hw_params, stream); + if (ret < 0) { + fe->err_ops = ret; + return; + } + + ret = dpcm_fe_dai_prepare_be(fe, be, stream); + if (ret < 0) { + fe->err_ops = ret; + return; + } +} + +static void dpcm_be_hw_params_prepare_async(void *data, async_cookie_t cookie) +{ + dpcm_be_hw_params_prepare(data); +} + static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, struct snd_compr_params *params) { @@ -416,7 +447,11 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, struct snd_pcm_substream *fe_substream = fe->pcm->streams[cstream->direction].substream; struct snd_soc_platform *platform = fe->platform; - int ret = 0, stream; + struct snd_soc_pcm_runtime *be_list[DPCM_MAX_BE_USERS]; + struct snd_soc_dpcm *dpcm; + int ret = 0, stream, i, j = 0; + + ASYNC_DOMAIN_EXCLUSIVE(async_domain); if (cstream->direction == SND_COMPRESS_PLAYBACK) stream = SNDRV_PCM_STREAM_PLAYBACK; @@ -425,36 +460,112 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); - if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) { - ret = platform->driver->compr_ops->set_params(cstream, params); + if (!(fe->dai_link->async_ops & ASYNC_DPCM_SND_SOC_HW_PARAMS)) { + /* first we call set_params for the platform driver + * this should configure the soc side + * if the machine has compressed ops then we call that as well + * expectation is that platform and machine will configure + * everything for this compress path, like configuring pcm + * port for codec + */ + if (platform->driver->compr_ops && + platform->driver->compr_ops->set_params) { + ret = platform->driver->compr_ops->set_params(cstream, + params); + if (ret < 0) + goto out; + } + + if (fe->dai_link->compr_ops && + fe->dai_link->compr_ops->set_params) { + ret = fe->dai_link->compr_ops->set_params(cstream); + if (ret < 0) + goto out; + } + + /* + * Create an empty hw_params for the BE as the machine + * driver must fix this up to match DSP decoder and + * ASRC configuration. + * I.e. machine driver fixup for compressed BE is + * mandatory. + */ + memset(&fe->dpcm[fe_substream->stream].hw_params, 0, + sizeof(struct snd_pcm_hw_params)); + + fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; + + ret = dpcm_be_dai_hw_params(fe, stream); if (ret < 0) goto out; - } - if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) { - ret = fe->dai_link->compr_ops->set_params(cstream); + ret = dpcm_be_dai_prepare(fe, stream); if (ret < 0) goto out; - } - - /* - * Create an empty hw_params for the BE as the machine driver must - * fix this up to match DSP decoder and ASRC configuration. - * I.e. machine driver fixup for compressed BE is mandatory. - */ - memset(&fe->dpcm[fe_substream->stream].hw_params, 0, - sizeof(struct snd_pcm_hw_params)); - - fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; - - ret = dpcm_be_dai_hw_params(fe, stream); - if (ret < 0) - goto out; + } else { + /* + * Create an empty hw_params for the BE as the machine + * driver must fix this up to match DSP decoder and + * ASRC configuration. + * I.e. machine driver fixup for compressed BE is + * mandatory. + */ + memset(&fe->dpcm[fe_substream->stream].hw_params, 0, + sizeof(struct snd_pcm_hw_params)); + + fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; + + list_for_each_entry(dpcm, + &fe->dpcm[stream].be_clients, list_be) { + struct snd_soc_pcm_runtime *be = dpcm->be; + + if (be->dai_link->async_ops & + ASYNC_DPCM_SND_SOC_HW_PARAMS) { + cstream->be = be; + async_schedule_domain( + dpcm_be_hw_params_prepare_async, + cstream, &async_domain); + } else { + be_list[j++] = be; + if (j == DPCM_MAX_BE_USERS) { + dev_dbg(fe->dev, + "ASoC: MAX backend users!\n"); + break; + } + } + } + for (i = 0; i < j; i++) { + cstream->be = be_list[i]; + dpcm_be_hw_params_prepare(cstream); + } + /* first we call set_params for the platform driver + * this should configure the soc side + * if the machine has compressed ops then we call that as well + * expectation is that platform and machine will configure + * everything this compress path, like configuring pcm port + * for codec + */ + if (platform->driver->compr_ops && + platform->driver->compr_ops->set_params) { + ret = platform->driver->compr_ops->set_params(cstream, + params); + if (ret < 0) + goto exit; + } - ret = dpcm_be_dai_prepare(fe, stream); - if (ret < 0) - goto out; + dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START); + if (fe->dai_link->compr_ops && + fe->dai_link->compr_ops->set_params) { + ret = fe->dai_link->compr_ops->set_params(cstream); + if (ret < 0) + goto exit; + } +exit: + async_synchronize_full_domain(&async_domain); + if (fe->err_ops < 0 || ret < 0) + goto out; + } dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START); fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE; @@ -532,14 +643,15 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream, { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; + int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); if (platform->driver->compr_ops && platform->driver->compr_ops->pointer) - platform->driver->compr_ops->pointer(cstream, tstamp); + ret = platform->driver->compr_ops->pointer(cstream, tstamp); mutex_unlock(&rtd->pcm_mutex); - return 0; + return ret; } static int soc_compr_copy(struct snd_compr_stream *cstream, @@ -558,6 +670,22 @@ static int soc_compr_copy(struct snd_compr_stream *cstream, return ret; } +static int sst_compr_set_next_track_param(struct snd_compr_stream *cstream, + union snd_codec_options *codec_options) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_platform *platform = rtd->platform; + int ret = 0; + + if (platform->driver->compr_ops && + platform->driver->compr_ops->set_next_track_param) + ret = platform->driver->compr_ops->set_next_track_param(cstream, + codec_options); + + return ret; +} + + static int soc_compr_set_metadata(struct snd_compr_stream *cstream, struct snd_compr_metadata *metadata) { @@ -590,6 +718,7 @@ static struct snd_compr_ops soc_compr_ops = { .free = soc_compr_free, .set_params = soc_compr_set_params, .set_metadata = soc_compr_set_metadata, + .set_next_track_param = sst_compr_set_next_track_param, .get_metadata = soc_compr_get_metadata, .get_params = soc_compr_get_params, .trigger = soc_compr_trigger, @@ -606,6 +735,7 @@ static struct snd_compr_ops soc_compr_dyn_ops = { .set_params = soc_compr_set_params_fe, .get_params = soc_compr_get_params, .set_metadata = soc_compr_set_metadata, + .set_next_track_param = sst_compr_set_next_track_param, .get_metadata = soc_compr_get_metadata, .trigger = soc_compr_trigger_fe, .pointer = soc_compr_pointer, @@ -721,8 +851,16 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) rtd->compr = compr; compr->private_data = rtd; - printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name, - cpu_dai->name); + if (platform->driver->pcm_new) { + ret = platform->driver->pcm_new(rtd); + if (ret < 0) { + pr_err("asoc: compress pcm constructor failed\n"); + goto compr_err; + } + } + + dev_dbg(rtd->card->dev, "compress asoc: %s <-> %s mapping ok\n", + codec_dai->name, cpu_dai->name); return ret; compr_err: |
