[PATCH] ASoC: tas2783-sdw: split a stereo stream across the two mono amps

Andrey Golovko <[email protected]>
Newsgroups org.kernel.vger.linux-sound,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
From: Antoine Monnet <[email protected]>

A board with two TAS2783 aggregated on one link renders mono: the two
amplifiers are mono parts that each carry one channel of the stereo
stream, but snd_sdw_params_to_config() hands every codec the full
channel mask for playback.  The pair stays in mirror mode, both amps
render the same channel, and the other channel is never reproduced.

Claim a single channel per amplifier instead.  The index comes from the
machine-assigned component name prefix rather than the SoundWire
unique_id, which is board-specific: soc_sdw_ti_amp.c names the
amplifiers tas2783-1..4.

The bit that is set does not choose the side.  sdw_compute_slave_ports()
advances the payload offset by hweight32(ch_mask) and never looks at
which bit it is, so a one-channel mask fixes mono by defeating mirror
mode, and left and right then follow the amplifier's position in the
codec order of the DAI link.  That was measured: inverting the two masks
between the amplifiers does not move the audio.  On the boards this has
been run on the codec order matches the prefix numbering, so the sides
come out as the machine driver names them, but the mapping is not an ABI
promise the bus allocator could honour.

Reported-by: Robin Everaars <[email protected]>
Closes: https://lore.kernel.org/all/[email protected]/
Suggested-by: Robin Everaars <[email protected]>
Signed-off-by: Antoine Monnet <[email protected]>
Tested-by: Andrey Golovko <[email protected]>
Signed-off-by: Andrey Golovko <[email protected]>
---
 sound/soc/codecs/tas2783-sdw.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c
index caf8fe1bf4db..c0c59480064a 100644
--- a/sound/soc/codecs/tas2783-sdw.c
+++ b/sound/soc/codecs/tas2783-sdw.c
@@ -1001,6 +1001,31 @@ static s32 tas_sdw_hw_params(struct snd_pcm_substream *substream,
 	/* SoundWire specific configuration */
 	snd_sdw_params_to_config(substream, params,
 				 &stream_config, &port_config);
+
+	/*
+	 * The two mono amps each render one channel of the stereo stream:
+	 * snd_sdw_params_to_config() hands every codec the full mask for
+	 * playback, which leaves the pair in mirror mode and one channel
+	 * unreproduced.  Claim a single channel instead, keyed off the
+	 * machine-assigned component prefix rather than the SoundWire
+	 * address, which is board-specific: soc_sdw_ti_amp.c names the amps
+	 * tas2783-1..4.
+	 *
+	 * Which side an amp then renders does not follow from the bit that
+	 * is set - sdw_compute_slave_ports() advances the payload offset by
+	 * the popcount of ch_mask and never looks at which bit it is - but
+	 * from the amp's position in the codec order of the DAI link, which
+	 * on these boards matches the prefix numbering.
+	 */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
+	    params_channels(params) == 2 && component->name_prefix) {
+		const char *idx_str = strrchr(component->name_prefix, '-');
+		unsigned long idx;
+
+		if (idx_str && !kstrtoul(idx_str + 1, 10, &idx) && idx)
+			port_config.ch_mask = (idx & 1) ? BIT(0) : BIT(1);
+	}
+
 	/* port 1 for playback */
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		port_config.num = 1;

base-commit: 0c7aeb0f5eceb95b5887bd8e83fef865e5a49a13
-- 
2.53.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.