[PATCH 2/2] ASoC: codecs: aw88261: use correct registers for AW88258

Val Packett
2026-04-20T21:37:10Z

The AW88258 has a slightly different register map, namely the PLL ones
are different and some extra boost ones are absent. Before the recent
hw_params fix, the PLL CCO_MUX accesses were actually always wrong as
the PLLCTRL1 address (0x54) was from the AW88261 but the CCO_MUX offset
(14) was from the AW88258. With said fix the AW88261 parameters were
always used, making it work on that chip. Make the accesses correct
for the AW88258 as well.

Signed-off-by: Val Packett <val@packett.cool>
---
This one is not tested (don't have the hardware), but since I've noticed
that the CCO_MUX was not even correct for any of the supported chips,
I've decided to try fixing it for the other one as well.

Code style wise this is kind of a really annoying situation but hopefully
this looks okay enough

~val
---
sound/soc/codecs/aw88258.h | 34 ++++++++++++++++++++++++++++++++++
sound/soc/codecs/aw88261.c | 37 ++++++++++++++++++++++++++-----------
2 files changed, 60 insertions(+), 11 deletions(-)
create mode 100644 sound/soc/codecs/aw88258.h

diff --git a/sound/soc/codecs/aw88258.h b/sound/soc/codecs/aw88258.h
new file mode 100644
index 000000000000..7ae177667ae6
--- /dev/null
+++ b/sound/soc/codecs/aw88258.h
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// aw88258.h -- AW88258 ALSA SoC Audio driver
+//
+// Copyright (c) 2023 awinic Technology CO., LTD
+//
+// Author: Jimmy Zhang <zhangjianming@awinic.com>
+// Author: Weidong Wang <wangweidong.a@awinic.com>
+//
+
+#ifndef __AW88258_H__
+#define __AW88258_H__
+
+/* This file contains definitions for registers that differ between
+ * the AW88261 (ID 0x2113) and the AW88258 (ID 0x1852). */
+
+#define AW88258_PLLCTRL1_REG (0x66)
+#define AW88258_PLLCTRL2_REG (0x67)
+#define AW88258_PLLCTRL3_REG (0x68)
+
+#define AW88258_CCO_MUX_START_BIT (14)
+#define AW88258_CCO_MUX_BITS_LEN (1)
+#define AW88258_CCO_MUX_MASK \
+ (~(((1<<AW88258_CCO_MUX_BITS_LEN)-1) << AW88258_CCO_MUX_START_BIT))
+
+#define AW88258_CCO_MUX_DIVIDED (0)
+#define AW88258_CCO_MUX_DIVIDED_VALUE \
+ (AW88258_CCO_MUX_DIVIDED << AW88258_CCO_MUX_START_BIT)
+
+#define AW88258_CCO_MUX_BYPASS (1)
+#define AW88258_CCO_MUX_BYPASS_VALUE \
+ (AW88258_CCO_MUX_BYPASS << AW88258_CCO_MUX_START_BIT)
+
+#endif
diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c
index 3c7d3e3865eb..172f38a4921c 100644
--- a/sound/soc/codecs/aw88261.c
+++ b/sound/soc/codecs/aw88261.c
@@ -14,6 +14,7 @@
#include <linux/regulator/consumer.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
+#include "aw88258.h"
#include "aw88261.h"
#include "aw88395/aw88395_data_type.h"
#include "aw88395/aw88395_device.h"
@@ -179,37 +180,36 @@ static int aw88261_dev_check_pll(struct aw_device *aw_dev)
static int aw88261_dev_configure_syspll(struct aw88261 *aw88261)
{
struct aw_device *aw_dev = aw88261->aw_pa;
- uint32_t sr_value, fs_value, cco_mux_value, bck_value;
+ uint32_t sr_value, fs_value, bck_value;
+ bool bypass_divider = false;
int ret;

switch (aw88261->sample_rate) {
case 8000:
sr_value = AW88261_I2SSR_8KHZ_VALUE;
- cco_mux_value = AW88261_CCO_MUX_DIVIDED_VALUE;
break;
case 16000:
sr_value = AW88261_I2SSR_16KHZ_VALUE;
- cco_mux_value = AW88261_CCO_MUX_DIVIDED_VALUE;
break;
case 32000:
sr_value = AW88261_I2SSR_32KHZ_VALUE;
- cco_mux_value = AW88261_CCO_MUX_DIVIDED_VALUE;
+ bypass_divider = true;
break;
case 44100:
sr_value = AW88261_I2SSR_44P1KHZ_VALUE;
- cco_mux_value = AW88261_CCO_MUX_BYPASS_VALUE;
+ bypass_divider = true;
break;
case 48000:
sr_value = AW88261_I2SSR_48KHZ_VALUE;
- cco_mux_value = AW88261_CCO_MUX_BYPASS_VALUE;
+ bypass_divider = true;
break;
case 96000:
sr_value = AW88261_I2SSR_96KHZ_VALUE;
- cco_mux_value = AW88261_CCO_MUX_BYPASS_VALUE;
+ bypass_divider = true;
break;
case 192000:
sr_value = AW88261_I2SSR_192KHZ_VALUE;
- cco_mux_value = AW88261_CCO_MUX_BYPASS_VALUE;
+ bypass_divider = true;
break;
default:
dev_err(aw_dev->dev, "unsupported sample rate %d\n",
@@ -241,8 +241,21 @@ static int aw88261_dev_configure_syspll(struct aw88261 *aw88261)
}

/* PLL divider must be used for 8/16/32 kHz modes */
- ret = regmap_update_bits(aw_dev->regmap, AW88261_PLLCTRL1_REG,
- ~AW88261_CCO_MUX_MASK, cco_mux_value);
+ switch (aw_dev->chip_id) {
+ case AW88261_CHIP_ID:
+ ret = regmap_update_bits(aw_dev->regmap, AW88261_PLLCTRL1_REG,
+ ~AW88261_CCO_MUX_MASK, bypass_divider ?
+ AW88261_CCO_MUX_BYPASS_VALUE : AW88261_CCO_MUX_DIVIDED);
+ break;
+ case AW88258_CHIP_ID:
+ ret = regmap_update_bits(aw_dev->regmap, AW88258_PLLCTRL1_REG,
+ ~AW88258_CCO_MUX_MASK, bypass_divider ?
+ AW88258_CCO_MUX_BYPASS_VALUE : AW88258_CCO_MUX_DIVIDED);
+ break;
+ default:
+ WARN_ONCE(1, "missing PLL regs for chip %x", aw_dev->chip_id);
+ return -ENXIO;
+ }
if (ret)
return ret;

@@ -306,7 +319,9 @@ static void aw88261_dev_uls_hmute(struct aw_device *aw_dev, bool uls_hmute)

static void aw88261_reg_force_set(struct aw88261 *aw88261)
{
- if (aw88261->frcset_en == AW88261_FRCSET_ENABLE) {
+ if (aw88261->aw_pa->chip_id == AW88258_CHIP_ID) {
+ dev_dbg(aw88261->aw_pa->dev, "force_set not supported on aw88258");
+ } else if (aw88261->frcset_en == AW88261_FRCSET_ENABLE) {
/* set FORCE_PWM */
regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL3_REG,
AW88261_FORCE_PWM_MASK, AW88261_FORCE_PWM_FORCEMINUS_PWM_VALUE);
--
2.53.0