summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Fitzgerald <rf@opensource.cirrus.com>2026-09-10 12:44:58 +0100
committerMark Brown <broonie@kernel.org>2026-09-14 00:37:41 +0100
commit6b382bdfe26a2232091bf743e454e6794295783e (patch)
treeb2cbdc7fcce7ea0a1ce37d55ac3fff9f215c593f
parent88b14c0d0bab5c0f3e7c641f274e3c70210c0e36 (diff)
downloadlinux-6b382bdfe26a2232091bf743e454e6794295783e.tar.gz
linux-6b382bdfe26a2232091bf743e454e6794295783e.zip
ASoC: soc-pcm: Apply snd_soc_dai_link_ch_map.codec_ch_mask to codec params
In __soc_pcm_hw_params() if there is a snd_soc_dai_link_ch_map with non-zero codec_ch_mask, use that channel mask to restrict which channels are enabled on the codec. But only if there isn't a TDM mask. It is possible that a snd_soc_dai_link_ch_map could include the same codec multiple times on different CPUs so the for_each_rtd_ch_maps() loop accumulates the channel masks for all entries of that codec. If a TDM mask was also set, it takes priority and is used instead of any possible snd_soc_dai_link_ch_map entries. (They cannot be ANDed together because the bit positions are indicating different things: TDM is a bit for each TDM slot, codec_ch_mask is a bit for each codec channel.) This fixes a problem of incorrect TX channels enabled on the codec when multiple codecs are aggregated on a single capture link. For example: - Two CPUs with six 4-channel codecs. - The machine driver chooses to assign one channel from each codec to one channel on the CPU - But the codec hw_params() would be passed a channel count of 6, which (a) is more channels than the codec has and (b) allows enabling channels that should not be driving the audio bus. Fixes: ac950278b087 ("ASoC: add N cpus to M codecs dai link support") Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com> Link: https://patch.msgid.link/20260910114500.1586637-4-rf@opensource.cirrus.com Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/soc-pcm.c16
1 files changed, 12 insertions, 4 deletions
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index cb64ced21149..3137c091bdb8 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1206,7 +1206,9 @@ static int __soc_pcm_hw_params(struct snd_pcm_substream *substream,
goto out;
for_each_rtd_codec_dais(rtd, i, codec_dai) {
- unsigned int tdm_mask = snd_soc_dai_tdm_mask_get(codec_dai, substream->stream);
+ unsigned int ch_mask = snd_soc_dai_tdm_mask_get(codec_dai, substream->stream);
+ struct snd_soc_dai_link_ch_map *ch_maps;
+ int j;
/*
* Skip CODECs which don't support the current stream type,
@@ -1228,9 +1230,15 @@ static int __soc_pcm_hw_params(struct snd_pcm_substream *substream,
/* copy params for each codec */
tmp_params = *params;
- /* fixup params based on TDM slot masks */
- if (tdm_mask)
- soc_pcm_codec_params_fixup(&tmp_params, tdm_mask);
+ /* fixup params based on TDM or ch_map masks */
+ if (!ch_mask) {
+ for_each_rtd_ch_maps(rtd, j, ch_maps)
+ if (ch_maps->codec == i)
+ ch_mask |= ch_maps->codec_ch_mask;
+ }
+
+ if (ch_mask)
+ soc_pcm_codec_params_fixup(&tmp_params, ch_mask);
ret = snd_soc_dai_hw_params(codec_dai, substream,
&tmp_params);