Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 906c7d69 authored by PC Liao's avatar PC Liao Committed by Mark Brown
Browse files

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: default avatarPC Liao <pc.liao@mediatek.com>
Signed-off-by: default avatarKoro Chen <koro.chen@mediatek.com>
Acked-by: default avatarLiam Girdwood <liam.r.girdwood@linux.intel.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 95f444dc
Loading
Loading
Loading
Loading
+57 −0
Original line number Diff line number Diff line
@@ -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;