From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
soc_pcm_params_symmetry() checks CPU / Codec symmetry. Unfortunately there was bug on it (= A) which didn't check Codec. But is back by (B).
A: v5.7: commit c840f7698d26 ("ASoC: soc-pcm: Merge for_each_rtd_cpu/codec_dais()") B: v5.12: commit 3a9067211122 ("ASoC: soc-pcm: cleanup soc_pcm_params_symmetry()")
In total, old - v5.6 (= Generation-1):
symmetric_rate : DAI_Link / CPU / Codec symmetric_channels : DAI_Link / CPU / Codec symmetric_sample_bits : DAI_Link / CPU / Codec
v5.7 - v5.11 (= Generation-2): (= because of bug by (A))
symmetric_rate : DAI_Link / CPU symmetric_channels : DAI_Link / CPU / Codec symmetric_sample_bits : DAI_Link / CPU / Codec
v5.12 - (= Generation-3): (= back by (B))
symmetric_rate : DAI_Link / CPU / Codec symmetric_channels : DAI_Link / CPU / Codec symmetric_sample_bits : DAI_Link / CPU / Codec
OTOH, we can use DPCM which is configured by FE / BE. Both FE / BE uses dummy-DAI.
FE: CPU <-> dummy-DAI BE: dummy-DAI <-> Codec
One note is that we can use .be_hw_params_fixup in DPCM case. This means BE settings might be fixuped/updated by FE. This feature is used for example on MIXer case. It can be happen not only for rate, but for channels/sample_bits too.
Because of these reasons, below issue happen on Generation-1 / Generation-3, if...
1) Sound Card used DPCM 2) It exchanges rate to 48kHz by using .be_hw_params_fixup() 3) Codec had symmetric_rate = 1
I didn't confirm, but maybe same things happen if it exchanged channels/sample_bits at Generation-1/2/3 too.
# aplay 44100.wav # aplay 44100.wav => [kernel] be.ak4613-hifi: ASoC: unmatched rate symmetry: snd-soc-dummy-dai:44100 - soc_pcm_params_symmetry:48000 [kernel] be.ak4613-hifi: ASoC: hw_params BE failed -22 [kernel] fe.rsnd-dai.0: ASoC: hw_params BE failed -22 aplay: set_params:1407: Unable to install hw params: ACCESS: RW_INTERLEAVED FORMAT: S16_LE SUBFORMAT: STD SAMPLE_BITS: 16 FRAME_BITS: 32 CHANNELS: 2 RATE: 44100 PERIOD_TIME: (23219 23220) PERIOD_SIZE: 1024 PERIOD_BYTES: 4096 PERIODS: 4 BUFFER_TIME: (92879 92880) BUFFER_SIZE: 4096 BUFFER_BYTES: 16384 TICK_TIME: 0
soc_pcm_params_symmetry() checks by below
if (symmetry) for_each_rtd_cpu_dais(rtd, i, cpu_dai) if (cpu_dai->xxx && cpu_dai->xxx != d.xxx) { dev_err(rtd->dev, "..."); return -EINVAL; }
Because of above reason 3) (= Codec had symmetric_rate = 1) BE can't ignore "if (symmetric)".
At 1st aplay, soc_pcm_params_symmetry() ignores it, because dummy-DAI->rate is 0. After this check, each DAI sets/keep settings.
In above sample case, BE gets 48000 and FE gets 44100, and it happen BE -> FE order. Because DPCM is sharing *same* dummy-DAI, dummy-DAI sets as 48000 by BE, and is overwrote by 44100 by FE.
This settings never be cleaned (= a) after 1st aplay, because dummy-DAI is used from FE/BE, never be last user (b).
static int soc_pcm_hw_clean(...) { ... for_each_rtd_dais(rtd, i, dai) { ... (b) if (snd_soc_dai_active(dai) == 1) (a) soc_pcm_set_dai_params(dai, NULL); ... } ... }
At 2nd aplay, BE gets 48000 but dummy-DAI is keeping 44100, soc_pcm_params_symmetry() checks will fail.
To solve this issue, this patch ignores dummy-DAI at soc_pcm_params_symmetry()
Link: https://lore.kernel.org/r/87a6q0z4xt.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/soc-pcm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 09d63cbbc602..327bb91ee28e 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -394,7 +394,8 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, \ if (symmetry) \ for_each_rtd_cpu_dais(rtd, i, cpu_dai) \ - if (cpu_dai->xxx && cpu_dai->xxx != d.xxx) { \ + if (!snd_soc_dai_is_dummy(cpu_dai) && \ + cpu_dai->xxx && cpu_dai->xxx != d.xxx) { \ dev_err(rtd->dev, "ASoC: unmatched %s symmetry: %s:%d - %s:%d\n", \ #xxx, cpu_dai->name, cpu_dai->xxx, d.name, d.xxx); \ return -EINVAL; \