From: Aaron Kling via B4 Relay <devnull+webgeek1234.gmail.com@kernel.org>
To: Liam Girdwood <lgirdwood@gmail.com>,
Mark Brown <broonie@kernel.org>,
Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.com>,
Weidong Wang <wangweidong.a@awinic.com>
Cc: linux-sound@vger.kernel.org, linux-kernel@vger.kernel.org,
Val Packett <val@packett.cool>,
Aaron Kling <webgeek1234@gmail.com>
Subject: [PATCH 6/6] ASoC: codecs: aw88166: make volume control usable
Date: Fri, 25 Sep 2026 02:47:34 -0500 [thread overview]
Message-ID: <20260925-aw88166-cleanup-v1-6-11f74cb5fe28@gmail.com> (raw)
In-Reply-To: <20260925-aw88166-cleanup-v1-0-11f74cb5fe28@gmail.com>
From: Aaron Kling <webgeek1234@gmail.com>
- Invert the value to match userspace expectations (in the hardware,
positive numbers represent negative dB attenuation)
- Provide TLV metadata for the dB scale (and divide the raw values by 2
as the excessive precision used by HW is not representable in TLV)
- Do not unnecessarily reset the volume while switching profiles
- Simplify aw88166_dev_set_volume using regmap_update_bits
- Do not add the initial volume from the profile to the requested volume
as that would throw off the dB mapping (if a lower max limit is
desired, it can be set in the UCM profile in userspace)
With this change, it's actually possible to use this hardware volume
control as PlaybackVolume in an ALSA UCM profile.
Fixes: 94e412c28e61 ("ASoC: codecs: Add aw88166 amplifier driver")
Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
---
sound/soc/codecs/aw88166.c | 47 ++++++++++++++++++++++------------------------
sound/soc/codecs/aw88166.h | 15 ++++++++++++++-
2 files changed, 36 insertions(+), 26 deletions(-)
diff --git a/sound/soc/codecs/aw88166.c b/sound/soc/codecs/aw88166.c
index 6b98864de81a9..3e87be33f4908 100644
--- a/sound/soc/codecs/aw88166.c
+++ b/sound/soc/codecs/aw88166.c
@@ -17,6 +17,7 @@
#include <linux/regmap.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
+#include <sound/tlv.h>
#include "aw88166.h"
#include "aw88395/aw88395_device.h"
@@ -645,26 +646,12 @@ static int aw_dev_dsp_check(struct aw_device *aw_dev)
return ret;
}
-static int aw_dev_set_volume(struct aw_device *aw_dev, unsigned int value)
+static void aw_dev_set_volume(struct aw_device *aw_dev, unsigned int value)
{
- struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
- unsigned int reg_value;
- u16 real_value;
- int ret;
-
- real_value = min((value + vol_desc->init_volume), (unsigned int)AW88166_MUTE_VOL);
-
- ret = regmap_read(aw_dev->regmap, AW88166_SYSCTRL2_REG, ®_value);
- if (ret)
- return ret;
-
- dev_dbg(aw_dev->dev, "value 0x%x , reg:0x%x", value, real_value);
+ unsigned int volume = min(value, (unsigned int)AW88166_MUTE_VOL);
- real_value = (real_value << AW88166_VOL_START_BIT) | (reg_value & AW88166_VOL_MASK);
-
- ret = regmap_write(aw_dev->regmap, AW88166_SYSCTRL2_REG, real_value);
-
- return ret;
+ regmap_update_bits(aw_dev->regmap, AW88166_SYSCTRL2_REG,
+ ~AW88166_VOL_MASK, DB_TO_REG_VAL(volume));
}
static void aw88166_dev_mute(struct aw_device *aw_dev, bool is_mute)
@@ -1548,7 +1535,8 @@ static int aw88166_volume_get(struct snd_kcontrol *kcontrol,
struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec);
struct aw_volume_desc *vol_desc = &aw88166->aw_pa->volume_desc;
- ucontrol->value.integer.value[0] = vol_desc->ctl_volume;
+ ucontrol->value.integer.value[0] =
+ (AW88166_MUTE_VOL - vol_desc->ctl_volume) / 2;
return 0;
}
@@ -1561,12 +1549,13 @@ static int aw88166_volume_set(struct snd_kcontrol *kcontrol,
struct aw_volume_desc *vol_desc = &aw88166->aw_pa->volume_desc;
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- int value;
+ int value = ucontrol->value.integer.value[0];
- value = ucontrol->value.integer.value[0];
if (value < mc->min || value > mc->max)
return -EINVAL;
+ value = AW88166_MUTE_VOL - (value * 2);
+
if (vol_desc->ctl_volume != value) {
vol_desc->ctl_volume = value;
aw_dev_set_volume(aw88166->aw_pa, vol_desc->ctl_volume);
@@ -1691,10 +1680,18 @@ static int aw88166_request_firmware_file(struct aw88166 *aw88166)
return ret;
}
+/*
+ * The field contains 4 bits in units of 6dB + 6 bits in units of 0.125dB
+ * which is too precise for TLV (!) so we have to multiply the scale by 2.
+ *
+ * The range is clamped at -90dB to prevent overflowing the 4-bit part.
+ */
+static const DECLARE_TLV_DB_SCALE(volume_tlv, -9000, 25, 0);
+
static const struct snd_kcontrol_new aw88166_controls[] = {
- SOC_SINGLE_EXT("PCM Playback Volume", AW88166_SYSCTRL2_REG,
- 6, AW88166_MUTE_VOL, 0, aw88166_volume_get,
- aw88166_volume_set),
+ SOC_SINGLE_EXT_TLV("PCM Playback Volume", AW88166_SYSCTRL2_REG,
+ 6, AW88166_CTL_MAX_VOL, 1,
+ aw88166_volume_get, aw88166_volume_set, volume_tlv),
SOC_SINGLE_EXT("Calib", 0, 0, AW88166_CALI_RE_MAX, 0,
aw88166_re_get, aw88166_re_set),
AW88166_PROFILE_EXT("AW88166 Profile Set", aw88166_profile_info,
@@ -1812,7 +1809,7 @@ static int aw88166_init(struct aw88166 *aw88166, struct i2c_client *i2c, struct
aw_dev->channel = AW88166_DEV_DEFAULT_CH;
aw_dev->fw_status = AW88166_DEV_FW_FAILED;
- aw_dev->volume_desc.ctl_volume = AW88166_VOL_DEFAULT_VALUE;
+ aw_dev->volume_desc.ctl_volume = AW88166_CTL_DEFAULT_VOL;
aw88166_parse_channel_dt(aw88166);
diff --git a/sound/soc/codecs/aw88166.h b/sound/soc/codecs/aw88166.h
index b8dbfe0f307c4..c0303340812cf 100644
--- a/sound/soc/codecs/aw88166.h
+++ b/sound/soc/codecs/aw88166.h
@@ -112,6 +112,9 @@
#define AW88166_REG_MAX (0x7E)
#define AW88166_MUTE_VOL (1023)
+#define AW88166_VOL_6DB_START (6)
+
+
#define AW88166_DSP_CFG_ADDR (0x9B00)
#define AW88166_DSP_REG_CFG_ADPZ_RA (0x9B68)
#define AW88166_DSP_FW_ADDR (0x8980)
@@ -590,7 +593,8 @@
#define AW88166_CALI_RE_MAX (15000)
#define AW88166_CALI_RE_MIN (4000)
#define AW88166_VOLUME_STEP_DB (64)
-#define AW88166_VOL_DEFAULT_VALUE (0)
+#define AW88166_CTL_MAX_VOL (AW88166_MUTE_VOL / 2)
+#define AW88166_CTL_DEFAULT_VOL (AW88166_CTL_MAX_VOL / 2)
#define AW88166_DSP_RE_TO_SHOW_RE(re, shift) (((re) * (1000)) >> (shift))
#define AW88166_SHOW_RE_TO_DSP_RE(re, shift) (((re) << shift) / (1000))
@@ -619,6 +623,15 @@
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
+#define AW88166_REG_TO_DB (0x3f)
+
+#define REG_VAL_TO_DB(value) ((((value) >> AW88166_VOL_6DB_START) * \
+ AW88166_VOLUME_STEP_DB) + \
+ ((value) & AW88166_REG_TO_DB))
+#define DB_TO_REG_VAL(value) ((((value) / AW88166_VOLUME_STEP_DB) << \
+ AW88166_VOL_6DB_START) + \
+ ((value) % AW88166_VOLUME_STEP_DB))
+
#define AW88166_PROFILE_EXT(xname, profile_info, profile_get, profile_set) \
{ \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
--
2.54.0
next prev parent reply other threads:[~2026-09-25 7:47 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-25 7:47 [PATCH 0/6] ASoC: codecs: aw88166: fixes and cleanup Aaron Kling via B4 Relay
2026-09-25 7:47 ` [PATCH 1/6] ASoC: codecs: aw88166: support changing sample rate and bit width Aaron Kling via B4 Relay
2026-09-25 14:00 ` Mark Brown
2026-09-25 15:56 ` Aaron Kling
2026-09-25 7:47 ` [PATCH 2/6] ASoC: codecs: aw88166: add TDM support Aaron Kling via B4 Relay
2026-09-25 7:47 ` [PATCH 3/6] ASoC: codecs: aw88166: reduce log spam Aaron Kling via B4 Relay
2026-09-25 7:47 ` [PATCH 4/6] ASoC: codecs: aw88166: remove fade in/out on start/stop Aaron Kling via B4 Relay
2026-09-25 14:11 ` Mark Brown
2026-09-25 15:59 ` Aaron Kling
2026-09-25 16:27 ` Mark Brown
2026-09-25 7:47 ` [PATCH 5/6] ASoC: codecs: aw88166: remove async start Aaron Kling via B4 Relay
2026-09-25 14:12 ` Mark Brown
2026-09-25 15:44 ` Aaron Kling
2026-09-25 16:06 ` Mark Brown
2026-09-25 16:16 ` Aaron Kling
2026-09-25 16:27 ` Mark Brown
2026-09-25 14:35 ` Cezary Rojewski
2026-09-25 15:42 ` Aaron Kling
2026-09-25 7:47 ` Aaron Kling via B4 Relay [this message]
2026-09-25 14:18 ` [PATCH 6/6] ASoC: codecs: aw88166: make volume control usable Mark Brown
2026-09-25 16:05 ` Aaron Kling
2026-09-25 16:18 ` Mark Brown
2026-09-25 16:25 ` Aaron Kling
2026-09-25 16:33 ` Mark Brown
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260925-aw88166-cleanup-v1-6-11f74cb5fe28@gmail.com \
--to=devnull+webgeek1234.gmail.com@kernel.org \
--cc=broonie@kernel.org \
--cc=lgirdwood@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-sound@vger.kernel.org \
--cc=perex@perex.cz \
--cc=tiwai@suse.com \
--cc=val@packett.cool \
--cc=wangweidong.a@awinic.com \
--cc=webgeek1234@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®