From: Jack Yu jack.yu@realtek.com
[ Upstream commit ff21a6ec0f27c126db0a86d96751bd6e5d1d9874 ]
Fix the boost gain calculation error in rt721_sdca_set_gain_get. This patch is specific for "FU33 Boost Volume".
Signed-off-by: Jack Yu jack.yu@realtek.com Link: https://patch.msgid.link/1b18fcde41c64d6fa85451d523c0434a@realtek.com Signed-off-by: Mark Brown broonie@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org ---
**YES**
This commit should be backported to stable kernel trees. Here's my extensive analysis:
## Bug Analysis
The commit fixes a calculation error in the `rt721_sdca_set_gain_get()` function, specifically for FU33 Boost Volume controls. Looking at the code changes:
1. **The bug**: When `mc->shift == 1` (FU33 boost gain), the original code incorrectly falls through to the ADC/DAC gain calculation path (lines 444-449 in the original): ```c if (mc->shift == 8) /* boost gain */ ctl_l = read_l / tendB; else { // This path was incorrectly used for FU33 boost (shift == 1) if (adc_vol_flag) ctl_l = mc->max - (((0x1e00 - read_l) & 0xffff) / interval_offset); else ctl_l = mc->max - (((0 - read_l) & 0xffff) / interval_offset); } ```
2. **The fix**: Adds a specific case for `mc->shift == 1` with proper FU33 boost gain calculation: ```c else if (mc->shift == 1) { /* FU33 boost gain */ if (read_l == 0x8000 || read_l == 0xfe00) ctl_l = 0; else ctl_l = read_l / tendA + 1; // Uses tendA (0x200) instead of tendB } ```
## Backport Justification
1. **User-facing bug**: This causes incorrect volume levels to be reported to userspace for FU33 boost controls, affecting audio applications and user experience.
2. **Small and contained**: The fix only adds ~15 lines of code in a single function, with no changes to data structures or APIs.
3. **Low regression risk**: The change only affects the specific case where `mc->shift == 1`, leaving all other code paths unchanged.
4. **Similar to accepted backports**: This follows the pattern of similar commits #1 and #2 in the reference set: - "ASoC: rt5682: Fix the boost volume at the beginning of playback" (backported) - "ASoC: rt5645: fix the shift bit of IN1 boost" (backported)
Both were small, targeted fixes for boost gain calculation errors and were accepted for stable.
5. **Clear fix for clear bug**: The commit message and code clearly show this is fixing an incorrect calculation, not adding features or making architectural changes.
The commit meets all criteria for stable backporting: it fixes a real bug, is minimal in scope, has low risk of regression, and follows established patterns for similar codec driver fixes.
sound/soc/codecs/rt721-sdca.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-)
diff --git a/sound/soc/codecs/rt721-sdca.c b/sound/soc/codecs/rt721-sdca.c index 1c9f32e405cf9..ba080957e9336 100644 --- a/sound/soc/codecs/rt721-sdca.c +++ b/sound/soc/codecs/rt721-sdca.c @@ -430,6 +430,7 @@ static int rt721_sdca_set_gain_get(struct snd_kcontrol *kcontrol, unsigned int read_l, read_r, ctl_l = 0, ctl_r = 0; unsigned int adc_vol_flag = 0; const unsigned int interval_offset = 0xc0; + const unsigned int tendA = 0x200; const unsigned int tendB = 0xa00;
if (strstr(ucontrol->id.name, "FU1E Capture Volume") || @@ -439,9 +440,16 @@ static int rt721_sdca_set_gain_get(struct snd_kcontrol *kcontrol, regmap_read(rt721->mbq_regmap, mc->reg, &read_l); regmap_read(rt721->mbq_regmap, mc->rreg, &read_r);
- if (mc->shift == 8) /* boost gain */ + if (mc->shift == 8) { + /* boost gain */ ctl_l = read_l / tendB; - else { + } else if (mc->shift == 1) { + /* FU33 boost gain */ + if (read_l == 0x8000 || read_l == 0xfe00) + ctl_l = 0; + else + ctl_l = read_l / tendA + 1; + } else { if (adc_vol_flag) ctl_l = mc->max - (((0x1e00 - read_l) & 0xffff) / interval_offset); else @@ -449,9 +457,16 @@ static int rt721_sdca_set_gain_get(struct snd_kcontrol *kcontrol, }
if (read_l != read_r) { - if (mc->shift == 8) /* boost gain */ + if (mc->shift == 8) { + /* boost gain */ ctl_r = read_r / tendB; - else { /* ADC/DAC gain */ + } else if (mc->shift == 1) { + /* FU33 boost gain */ + if (read_r == 0x8000 || read_r == 0xfe00) + ctl_r = 0; + else + ctl_r = read_r / tendA + 1; + } else { /* ADC/DAC gain */ if (adc_vol_flag) ctl_r = mc->max - (((0x1e00 - read_r) & 0xffff) / interval_offset); else