[PATCH 4/5] ASoC: sdw_utils: Set snd_soc_dai_link_ch_map.codec_ch_mask for capture
From: Richard Fitzgerald
Date: Thu Sep 10 2026 - 07:49:53 EST
In asoc_sdw_hw_params() set the codec_ch_mask member of struct
snd_soc_dai_link_ch_map for capture streams. ASoC will then pass the
correct number of channels to each codec hw_params(). This prevents
trying to enable more channels on the codec DP than have been allocated
bitslots in the SoundWire frame, which would cause bus clash errors.
In theory codec_ch_mask could also be set for playback streams, but for
those the CPU is the only sender so there is no risk of bus clash.
For playback streams codec_ch_mask is set to 0 to preserve the existing
behavior and avoid introducing bugs.
Signed-off-by: Richard Fitzgerald <rf@xxxxxxxxxxxxxxxxxxxxx>
---
sound/soc/sdw_utils/soc_sdw_utils.c | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c
index cab1578b893d..778ba6531434 100644
--- a/sound/soc/sdw_utils/soc_sdw_utils.c
+++ b/sound/soc/sdw_utils/soc_sdw_utils.c
@@ -1731,7 +1731,7 @@ int asoc_sdw_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai_link_ch_map *ch_maps;
int ch = params_channels(params);
- unsigned int ch_mask;
+ unsigned int cpu_ch_mask, codec_ch_mask;
int num_codecs;
int step;
int i;
@@ -1741,8 +1741,9 @@ int asoc_sdw_hw_params(struct snd_pcm_substream *substream,
/* Identical data will be sent to all codecs in playback */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- ch_mask = GENMASK(ch - 1, 0);
+ cpu_ch_mask = GENMASK(ch - 1, 0);
step = 0;
+ codec_ch_mask = 0;
} else {
num_codecs = rtd->dai_link->num_codecs;
@@ -1752,17 +1753,24 @@ int asoc_sdw_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- ch_mask = GENMASK(ch / num_codecs - 1, 0);
- step = hweight_long(ch_mask);
+ cpu_ch_mask = GENMASK(ch / num_codecs - 1, 0);
+ step = hweight_long(cpu_ch_mask);
+ codec_ch_mask = cpu_ch_mask;
}
/*
* The captured data will be combined from each cpu DAI if the dai
* link has more than one codec DAIs. Set codec channel mask and
* ASoC will set the corresponding channel numbers for each cpu dai.
+ *
+ * sdw_stream_add_slave() assigns different payload offsets to each
+ * codec in a capture stream, so that the same channels on each
+ * codec map to different channels on the CPU.
*/
- for_each_link_ch_maps(rtd->dai_link, i, ch_maps)
- ch_maps->cpu_ch_mask = ch_mask << (i * step);
+ for_each_link_ch_maps(rtd->dai_link, i, ch_maps) {
+ ch_maps->cpu_ch_mask = cpu_ch_mask << (i * step);
+ ch_maps->codec_ch_mask = codec_ch_mask;
+ }
return 0;
}
--
2.47.3