[SRU][R][PATCH 3/7] ASoC: SDCA: Improve mapping of Q7.8 SDCA volumes

Chris Chiu chris.chiu at canonical.com
Tue Mar 17 03:44:34 UTC 2026


From: Charles Keepax <ckeepax at opensource.cirrus.com>

BugLink: https://bugs.launchpad.net/bugs/2143902

SDCA measures volumes in 256ths of a dB, whereas ALSA measures
volumes in 100ths of a dB. Currently the SDCA volume controls are
mapped to ALSA controls by mapping the step size and working out
the number of steps for this mapped step size. Due to quantization
of the step size this means the number of steps in the ALSA
control will rarely match the number of steps in the SDCA control,
leading to skipped values and multiple values that map to the
same volume. This is not a huge problem, the volume is still
increasing and the differences will be small but it is not really
desirable.

It is simpler and more accurate to count the number of steps based on
the SDCA volume levels. This gives a 1-to-1 mapping between control
values and register volumes. The TLV is based on a minimum and maximum
volume so still accurately specifies the volume range.

Tested-by: Richard Fitzgerald <rf at opensource.cirrus.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart at linux.dev>
Signed-off-by: Charles Keepax <ckeepax at opensource.cirrus.com>
Link: https://patch.msgid.link/20260225140118.402695-4-ckeepax@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie at kernel.org>
(cherry picked from commit d4f7d5a9a0f963dc895c18084425ce332a80d3a8)
Signed-off-by: Chris Chiu <chris.chiu at canonical.com>
---
 sound/soc/sdca/sdca_asoc.c |  6 ++----
 sound/soc/soc-ops.c        | 12 ++----------
 2 files changed, 4 insertions(+), 14 deletions(-)

diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c
index 49cbf38b7adb..beee024622a5 100644
--- a/sound/soc/sdca/sdca_asoc.c
+++ b/sound/soc/sdca/sdca_asoc.c
@@ -805,10 +805,8 @@ static int control_limit_kctl(struct device *dev,
 	tlv[2] = (min * 100) >> 8;
 	tlv[3] = (max * 100) >> 8;
 
-	step = (step * 100) >> 8;
-
-	mc->min = ((int)tlv[2] / step);
-	mc->max = ((int)tlv[3] / step);
+	mc->min = min / step;
+	mc->max = max / step;
 	mc->shift = step;
 	mc->sign_bit = 15;
 	mc->sdca_q78 = 1;
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index 624e9269fc25..133a2e6fbd7a 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -120,25 +120,17 @@ static int sdca_soc_q78_reg_to_ctl(struct soc_mixer_control *mc, unsigned int re
 		return -EINVAL;
 
 	val = sign_extend32(val, mc->sign_bit);
-	val = (((val * 100) >> 8) / (int)mc->shift);
-	val -= mc->min;
 
-	return val & mask;
+	return ((val / mc->shift) - mc->min) & mask;
 }
 
 static unsigned int sdca_soc_q78_ctl_to_reg(struct soc_mixer_control *mc, int val,
 					 unsigned int mask, unsigned int shift, int max)
 {
-	unsigned int ret_val;
-	int reg_val;
-
 	if (WARN_ON(!mc->shift))
 		return -EINVAL;
 
-	reg_val = val + mc->min;
-	ret_val = (int)((reg_val * mc->shift) << 8) / 100;
-
-	return ret_val & mask;
+	return ((val + mc->min) * mc->shift) & mask;
 }
 
 static int soc_mixer_reg_to_ctl(struct soc_mixer_control *mc, unsigned int reg_val,
-- 
2.43.0




More information about the kernel-team mailing list