From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8943D46DFE4; Fri, 25 Sep 2026 07:47:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790322451; cv=none; b=KEi2zZcxdcQeuTiSJYXxQgypM86/Q860D4aCV8Tb8zcOAT23OCnMzAryoURpDueKQShnalYj0jVtH40gxn/PTA3tPAhXulrIWpEGLFHU2v094NQDwLeWtdfHzazuwlhwrq367iyAF/+uUe19CoRDErwKlAoH/q6DlvKI4BOyr3U= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790322451; c=relaxed/simple; bh=W2itv7N4NoMQMITjE1kOWQG7W+R7zBTS2xGT8cxHds4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Lh8GWItOT1S1Hy+pa9XyLL9p+izS3+Rh2R/QhyHhNU9cOra5L+Z/WGvOZWR2wgLB/RLsz62ASoommCCH0/E19kKvI6ucbJMy6yV0wq4SZ2jC5pu8IX7+YTvk+6UxnK5PmqYrC0EK9u79HQ/pf/iTayKrPO4sHdWyLh8xklO9+og= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=OsUokemx; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="OsUokemx" Received: by smtp.kernel.org (Postfix) with ESMTPS id 328A2C2BD04; Fri, 25 Sep 2026 07:47:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1790322451; bh=W2itv7N4NoMQMITjE1kOWQG7W+R7zBTS2xGT8cxHds4=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=OsUokemxhIuBYoLs0hIaDAIw7s+hegkolqbQrwNGt+VZWdrvR1PDhn4AspmXeuRMW R2IQeaAEHIrtgRj3ScNMCTMf3cD4bdaQi52wBFy54wUMxmpgftH2mq4M1nN7U/wc0v vEKQZn99iEP9RlfO3mwmUw7fS+/9R+LMKiQhUVB5uJkGAtFOzV190STVCioKnpZY7O aphnVUOLRbRR77I+Be+WQtFPpkvz6Tt1m0VgOS+9ajdugQ+MxiHunyitLwlUxIawAA 9PvnxMeAlMYPLcohnmEnKcwFLBzm0j6fMjMesg5IP5KiZEAXEW4r8h0exLD84CN2On NacF7JUg8BHcw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 20AC1C9832A; Fri, 25 Sep 2026 07:47:31 +0000 (UTC) From: Aaron Kling via B4 Relay Date: Fri, 25 Sep 2026 02:47:34 -0500 Subject: [PATCH 6/6] ASoC: codecs: aw88166: make volume control usable Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20260925-aw88166-cleanup-v1-6-11f74cb5fe28@gmail.com> References: <20260925-aw88166-cleanup-v1-0-11f74cb5fe28@gmail.com> In-Reply-To: <20260925-aw88166-cleanup-v1-0-11f74cb5fe28@gmail.com> To: Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Weidong Wang Cc: linux-sound@vger.kernel.org, linux-kernel@vger.kernel.org, Val Packett , Aaron Kling X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1790322449; l=6241; i=webgeek1234@gmail.com; s=20250217; h=from:subject:message-id; bh=hlFleUeou8JhECaow+haiTbL5j1iHTRlPX7dYMh42WA=; b=8ei86rGmq+NZcEtDxPG8PHDuKVhtWPjchY7VYOZCzjJhD47hY3R5WFh2pvF/6jeoxT45d1lso +6pKmnCIcGGB1HBZEOyROlRvEMB2ordB1euWsSYnMLtxz5Ko+9wh1ev X-Developer-Key: i=webgeek1234@gmail.com; a=ed25519; pk=TQwd6q26txw7bkK7B8qtI/kcAohZc7bHHGSD7domdrU= X-Endpoint-Received: by B4 Relay for webgeek1234@gmail.com/20250217 with auth_id=342 X-Original-From: Aaron Kling Reply-To: webgeek1234@gmail.com From: Aaron Kling - 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 --- 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 #include #include +#include #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