diff options
author | PC Liao <pc.liao@mediatek.com> | 2015-12-11 06:33:51 +0300 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-12-13 01:58:32 +0300 |
commit | 906c7d690c3b80e4321178c083db8c14afb56bf8 (patch) | |
tree | 443e2cc9c0dced923178bdfac26de652801706ab | |
parent | 95f444dc9371a3910179a9621c8b94f0f60f5f04 (diff) | |
download | linux-906c7d690c3b80e4321178c083db8c14afb56bf8.tar.xz |
ASoC: dpcm: Apply symmetry for DPCM
DPCM does not fully support symmetry attributes. soc_pcm_apply_symmetry()
is skipped in soc_pcm_open() for DPCM, without being applied elsewhere.
So HW parameters cannot be correctly limited, and user space can do
playback/capture at different rates while HW actually does not support it.
soc_pcm_params_symmetry() will return error and the second stream stops.
This patch adds soc_pcm_apply_symmetry() for FE, BE, and codec DAIs
in DPCM path that was skipped in soc_pcm_open().
Signed-off-by: PC Liao <pc.liao@mediatek.com>
Signed-off-by: Koro Chen <koro.chen@mediatek.com>
Acked-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | sound/soc/soc-pcm.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index c48232211c56..37de8af91f13 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1616,6 +1616,56 @@ static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe, snd_pcm_stream_unlock_irq(substream); } +static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, + int stream) +{ + struct snd_soc_dpcm *dpcm; + struct snd_soc_pcm_runtime *fe = fe_substream->private_data; + struct snd_soc_dai *fe_cpu_dai = fe->cpu_dai; + int err; + + /* apply symmetry for FE */ + if (soc_pcm_has_symmetry(fe_substream)) + fe_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; + + /* Symmetry only applies if we've got an active stream. */ + if (fe_cpu_dai->active) { + err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai); + if (err < 0) + return err; + } + + /* apply symmetry for BE */ + list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + struct snd_soc_pcm_runtime *be = dpcm->be; + struct snd_pcm_substream *be_substream = + snd_soc_dpcm_get_substream(be, stream); + struct snd_soc_pcm_runtime *rtd = be_substream->private_data; + int i; + + if (soc_pcm_has_symmetry(be_substream)) + be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; + + /* Symmetry only applies if we've got an active stream. */ + if (rtd->cpu_dai->active) { + err = soc_pcm_apply_symmetry(be_substream, rtd->cpu_dai); + if (err < 0) + return err; + } + + for (i = 0; i < rtd->num_codecs; i++) { + if (rtd->codec_dais[i]->active) { + err = soc_pcm_apply_symmetry(be_substream, + rtd->codec_dais[i]); + if (err < 0) + return err; + } + } + } + + return 0; +} + static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream) { struct snd_soc_pcm_runtime *fe = fe_substream->private_data; @@ -1644,6 +1694,13 @@ static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream) dpcm_set_fe_runtime(fe_substream); snd_pcm_limit_hw_rates(runtime); + ret = dpcm_apply_symmetry(fe_substream, stream); + if (ret < 0) { + dev_err(fe->dev, "ASoC: failed to apply dpcm symmetry %d\n", + ret); + goto unwind; + } + dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); return 0; |