ASoC: sdw_utils: Set snd_soc_dai_link_ch_map.codec_ch_mask for capture

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@opensource.cirrus.com>
Link: https://patch.msgid.link/20260910114500.1586637-5-rf@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Richard Fitzgerald 2026-09-10 12:44:59 +01:00 committed by Mark Brown
parent 6b382bdfe2
commit 290845e151

View File

@ -1565,7 +1565,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;
@ -1575,8 +1575,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;
@ -1586,17 +1587,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;
}