ASoC: codecs: aw88261: support changing sample rate and bit width

The aw88261 driver only worked with 32-bit 48kHz streams so far due to
the lack of a proper PLL initialization sequence. Fix by selecting all
the necessary PLL settings based on what was passed to us by the
hw_params/set_fmt ops. This replaces the strange downstream routine
that tries two divider modes in sequence.

Fixes: 028a2ae256 ("ASoC: codecs: Add aw88261 amplifier driver")
Tested-by: Luca Weiss <luca.weiss@fairphone.com> # qcm6490-fairphone-fp5
Signed-off-by: Val Packett <val@packett.cool>
Link: https://patch.msgid.link/20260529200550.529719-2-val@packett.cool
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Val Packett 2026-05-29 17:05:08 -03:00 committed by Mark Brown
parent 4549871118
commit 1b92b0673d
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
2 changed files with 299 additions and 64 deletions

View File

@ -13,6 +13,7 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
#include "aw88261.h"
#include "aw88395/aw88395_data_type.h"
#include "aw88395/aw88395_device.h"
@ -158,7 +159,7 @@ static int aw88261_dev_get_iis_status(struct aw_device *aw_dev)
return ret;
}
static int aw88261_dev_check_mode1_pll(struct aw_device *aw_dev)
static int aw88261_dev_check_pll(struct aw_device *aw_dev)
{
int ret, i;
@ -175,71 +176,48 @@ static int aw88261_dev_check_mode1_pll(struct aw_device *aw_dev)
return -EPERM;
}
static int aw88261_dev_check_mode2_pll(struct aw_device *aw_dev)
{
unsigned int reg_val;
int ret, i;
ret = regmap_read(aw_dev->regmap, AW88261_PLLCTRL1_REG, &reg_val);
if (ret)
return ret;
reg_val &= (~AW88261_CCO_MUX_MASK);
if (reg_val == AW88261_CCO_MUX_DIVIDED_VALUE) {
dev_dbg(aw_dev->dev, "CCO_MUX is already divider");
return -EPERM;
}
/* change mode2 */
ret = regmap_update_bits(aw_dev->regmap, AW88261_PLLCTRL1_REG,
~AW88261_CCO_MUX_MASK, AW88261_CCO_MUX_DIVIDED_VALUE);
if (ret)
return ret;
for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) {
ret = aw88261_dev_get_iis_status(aw_dev);
if (ret) {
dev_err(aw_dev->dev, "mode2 iis signal check error");
usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
} else {
break;
}
}
/* change mode1 */
ret = regmap_update_bits(aw_dev->regmap, AW88261_PLLCTRL1_REG,
~AW88261_CCO_MUX_MASK, AW88261_CCO_MUX_BYPASS_VALUE);
if (ret == 0) {
usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) {
ret = aw88261_dev_check_mode1_pll(aw_dev);
if (ret) {
dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error");
usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
} else {
break;
}
}
}
return ret;
}
static int aw88261_dev_check_syspll(struct aw_device *aw_dev)
static int aw88261_dev_configure_syspll(struct aw88261 *aw88261)
{
struct aw_device *aw_dev = aw88261->aw_pa;
int ret;
ret = aw88261_dev_check_mode1_pll(aw_dev);
if (ret) {
dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check");
ret = aw88261_dev_check_mode2_pll(aw_dev);
if (ret) {
dev_err(aw_dev->dev, "mode2 check iis failed");
return ret;
}
}
/* 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, aw88261->cco_mux_value);
if (ret)
return ret;
return ret;
/* The word clock (WCK) defines the beginning of a frame */
ret = regmap_update_bits(aw_dev->regmap, AW88261_I2SCTRL1_REG,
~AW88261_I2SSR_MASK, aw88261->sr_value);
if (ret)
return ret;
/* The bit clock (BCK) defines the length of a frame */
ret = regmap_update_bits(aw_dev->regmap, AW88261_I2SCTRL1_REG,
~AW88261_I2SBCK_MASK, aw88261->bck_value);
if (ret)
return ret;
/* The logical frame size is the width of data for 1 slot */
ret = regmap_update_bits(aw_dev->regmap, AW88261_I2SCTRL1_REG,
~AW88261_I2SFS_MASK, aw88261->fs_value);
if (ret)
return ret;
/* The I2S interface mode (Philips standard, LSB/MSB justified) */
ret = regmap_update_bits(aw_dev->regmap, AW88261_I2SCTRL1_REG,
~AW88261_I2SMD_MASK, aw88261->md_value);
if (ret)
return ret;
/* The polarity of the bit clock (BCK) */
ret = regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
~AW88261_BCKINV_MASK, aw88261->bck_inv_value);
if (ret)
return ret;
return aw88261_dev_check_pll(aw_dev);
}
static int aw88261_dev_check_sysst(struct aw_device *aw_dev)
@ -558,7 +536,7 @@ static int aw88261_dev_start(struct aw88261 *aw88261)
aw88261_dev_pwd(aw_dev, false);
usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
ret = aw88261_dev_check_syspll(aw_dev);
ret = aw88261_dev_configure_syspll(aw88261);
if (ret) {
dev_err(aw_dev->dev, "pll check failed cannot start");
goto pll_check_fail;
@ -712,6 +690,140 @@ static void aw88261_start(struct aw88261 *aw88261, bool sync_start)
AW88261_START_WORK_DELAY_MS);
}
static int aw88261_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_component *component = dai->component;
struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
aw88261->bck_inv_value = AW88261_BCKINV_NOT_INVERT_VALUE;
break;
case SND_SOC_DAIFMT_IB_NF:
aw88261->bck_inv_value = AW88261_BCKINV_INVERTED_VALUE;
break;
default:
dev_err(aw88261->aw_pa->dev, "unsupported invert mode 0x%x\n",
fmt & SND_SOC_DAIFMT_INV_MASK);
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
aw88261->md_value = AW88261_I2SMD_PHILIPS_STANDARD_VALUE;
break;
case SND_SOC_DAIFMT_MSB:
aw88261->md_value = AW88261_I2SMD_MSB_JUSTIFIED_VALUE;
break;
case SND_SOC_DAIFMT_LSB:
aw88261->md_value = AW88261_I2SMD_LSB_JUSTIFIED_VALUE;
break;
default:
dev_err(aw88261->aw_pa->dev, "unsupported DAI format 0x%x\n",
fmt & SND_SOC_DAIFMT_FORMAT_MASK);
return -EINVAL;
}
return 0;
}
static int aw88261_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
return 0;
aw88261->cco_mux_value = AW88261_CCO_MUX_BYPASS_VALUE;
switch (params_rate(params)) {
case 8000:
aw88261->sr_value = AW88261_I2SSR_8KHZ_VALUE;
aw88261->cco_mux_value = AW88261_CCO_MUX_DIVIDED_VALUE;
break;
case 11025:
aw88261->sr_value = AW88261_I2SSR_11P025KHZ_VALUE;
break;
case 12000:
aw88261->sr_value = AW88261_I2SSR_12KHZ_VALUE;
break;
case 16000:
aw88261->sr_value = AW88261_I2SSR_16KHZ_VALUE;
aw88261->cco_mux_value = AW88261_CCO_MUX_DIVIDED_VALUE;
break;
case 22050:
aw88261->sr_value = AW88261_I2SSR_22P05KHZ_VALUE;
break;
case 24000:
aw88261->sr_value = AW88261_I2SSR_24KHZ_VALUE;
break;
case 32000:
aw88261->sr_value = AW88261_I2SSR_32KHZ_VALUE;
aw88261->cco_mux_value = AW88261_CCO_MUX_DIVIDED_VALUE;
break;
case 44100:
aw88261->sr_value = AW88261_I2SSR_44P1KHZ_VALUE;
break;
case 48000:
aw88261->sr_value = AW88261_I2SSR_48KHZ_VALUE;
break;
case 96000:
aw88261->sr_value = AW88261_I2SSR_96KHZ_VALUE;
break;
case 192000:
aw88261->sr_value = AW88261_I2SSR_192KHZ_VALUE;
break;
default:
dev_err(aw88261->aw_pa->dev, "unsupported sample rate %d\n",
params_rate(params));
return -EINVAL;
}
switch (params_width(params)) {
case 16:
aw88261->fs_value = AW88261_I2SFS_16_BITS_VALUE;
break;
case 20:
aw88261->fs_value = AW88261_I2SFS_20_BITS_VALUE;
break;
case 24:
aw88261->fs_value = AW88261_I2SFS_24_BITS_VALUE;
break;
case 32:
aw88261->fs_value = AW88261_I2SFS_32_BITS_VALUE;
break;
default:
dev_err(aw88261->aw_pa->dev, "unsupported bit width %d\n",
params_width(params));
return -EINVAL;
}
switch (params_physical_width(params)) {
case 16:
aw88261->bck_value = AW88261_I2SBCK_32FS_VALUE;
break;
case 24:
aw88261->bck_value = AW88261_I2SBCK_48FS_VALUE;
break;
case 32:
aw88261->bck_value = AW88261_I2SBCK_64FS_VALUE;
break;
default:
dev_err(aw88261->aw_pa->dev, "unsupported physical bit width %d\n",
params_physical_width(params));
return -EINVAL;
}
return 0;
}
static const struct snd_soc_dai_ops aw88261_dai_ops = {
.set_fmt = aw88261_set_fmt,
.hw_params = aw88261_hw_params,
};
static struct snd_soc_dai_driver aw88261_dai[] = {
{
.name = "aw88261-aif",
@ -730,6 +842,7 @@ static struct snd_soc_dai_driver aw88261_dai[] = {
.rates = AW88261_RATES,
.formats = AW88261_FORMATS,
},
.ops = &aw88261_dai_ops,
},
};
@ -1249,6 +1362,14 @@ static int aw88261_i2c_probe(struct i2c_client *i2c)
if (!aw88261)
return -ENOMEM;
/* set defaults */
aw88261->sr_value = AW88261_I2SSR_48KHZ_VALUE;
aw88261->cco_mux_value = AW88261_CCO_MUX_BYPASS_VALUE;
aw88261->fs_value = AW88261_I2SFS_24_BITS_VALUE;
aw88261->bck_value = AW88261_I2SBCK_64FS_VALUE;
aw88261->bck_inv_value = AW88261_BCKINV_NOT_INVERT_VALUE;
aw88261->md_value = AW88261_I2SMD_PHILIPS_STANDARD_VALUE;
mutex_init(&aw88261->lock);
i2c_set_clientdata(i2c, aw88261);

View File

@ -116,6 +116,19 @@
#define AW88261_VCALK_SHIFT (0)
#define AW88261_VCALKL_SHIFT (0)
#define AW88261_BCKINV_START_BIT (4)
#define AW88261_BCKINV_BITS_LEN (1)
#define AW88261_BCKINV_MASK \
(~(((1<<AW88261_BCKINV_BITS_LEN)-1) << AW88261_BCKINV_START_BIT))
#define AW88261_BCKINV_NOT_INVERT (0)
#define AW88261_BCKINV_NOT_INVERT_VALUE \
(AW88261_BCKINV_NOT_INVERT << AW88261_BCKINV_START_BIT)
#define AW88261_BCKINV_INVERTED (1)
#define AW88261_BCKINV_INVERTED_VALUE \
(AW88261_BCKINV_INVERTED << AW88261_BCKINV_START_BIT)
#define AW88261_AMPPD_START_BIT (1)
#define AW88261_AMPPD_BITS_LEN (1)
#define AW88261_AMPPD_MASK \
@ -264,7 +277,98 @@
#define AW88261_I2STXEN_ENABLE_VALUE \
(AW88261_I2STXEN_ENABLE << AW88261_I2STXEN_START_BIT)
#define AW88261_CCO_MUX_START_BIT (14)
#define AW88261_I2SMD_START_BIT (8)
#define AW88261_I2SMD_BITS_LEN (2)
#define AW88261_I2SMD_MASK \
(~(((1<<AW88261_I2SMD_BITS_LEN)-1) << AW88261_I2SMD_START_BIT))
#define AW88261_I2SMD_PHILIPS_STANDARD (0)
#define AW88261_I2SMD_PHILIPS_STANDARD_VALUE \
(AW88261_I2SMD_PHILIPS_STANDARD << AW88261_I2SMD_START_BIT)
#define AW88261_I2SMD_MSB_JUSTIFIED (1)
#define AW88261_I2SMD_MSB_JUSTIFIED_VALUE \
(AW88261_I2SMD_MSB_JUSTIFIED << AW88261_I2SMD_START_BIT)
#define AW88261_I2SMD_LSB_JUSTIFIED (2)
#define AW88261_I2SMD_LSB_JUSTIFIED_VALUE \
(AW88261_I2SMD_LSB_JUSTIFIED << AW88261_I2SMD_START_BIT)
#define AW88261_I2SFS_START_BIT (6)
#define AW88261_I2SFS_BITS_LEN (2)
#define AW88261_I2SFS_MASK \
(~(((1<<AW88261_I2SFS_BITS_LEN)-1)<<AW88261_I2SFS_START_BIT))
#define AW88261_I2SFS_16_BITS (0)
#define AW88261_I2SFS_16_BITS_VALUE \
(AW88261_I2SFS_16_BITS << AW88261_I2SFS_START_BIT)
#define AW88261_I2SFS_20_BITS (1)
#define AW88261_I2SFS_20_BITS_VALUE \
(AW88261_I2SFS_20_BITS << AW88261_I2SFS_START_BIT)
#define AW88261_I2SFS_24_BITS (2)
#define AW88261_I2SFS_24_BITS_VALUE \
(AW88261_I2SFS_24_BITS << AW88261_I2SFS_START_BIT)
#define AW88261_I2SFS_32_BITS (3)
#define AW88261_I2SFS_32_BITS_VALUE \
(AW88261_I2SFS_32_BITS << AW88261_I2SFS_START_BIT)
#define AW88261_I2SBCK_START_BIT (4)
#define AW88261_I2SBCK_BITS_LEN (2)
#define AW88261_I2SBCK_MASK \
(~(((1<<AW88261_I2SBCK_BITS_LEN)-1) << AW88261_I2SBCK_START_BIT))
#define AW88261_I2SBCK_32FS (0)
#define AW88261_I2SBCK_32FS_VALUE \
(AW88261_I2SBCK_32FS << AW88261_I2SBCK_START_BIT)
#define AW88261_I2SBCK_48FS (1)
#define AW88261_I2SBCK_48FS_VALUE \
(AW88261_I2SBCK_48FS << AW88261_I2SBCK_START_BIT)
#define AW88261_I2SBCK_64FS (2)
#define AW88261_I2SBCK_64FS_VALUE \
(AW88261_I2SBCK_64FS << AW88261_I2SBCK_START_BIT)
#define AW88261_I2SSR_START_BIT (0)
#define AW88261_I2SSR_BITS_LEN (4)
#define AW88261_I2SSR_MASK \
(~(((1<<AW88261_I2SSR_BITS_LEN)-1) << AW88261_I2SSR_START_BIT))
#define AW88261_I2SSR_8KHZ (0)
#define AW88261_I2SSR_8KHZ_VALUE \
(AW88261_I2SSR_8KHZ << AW88261_I2SSR_START_BIT)
#define AW88261_I2SSR_11P025KHZ (1)
#define AW88261_I2SSR_11P025KHZ_VALUE \
(AW88261_I2SSR_11P025KHZ << AW88261_I2SSR_START_BIT)
#define AW88261_I2SSR_12KHZ (2)
#define AW88261_I2SSR_12KHZ_VALUE \
(AW88261_I2SSR_12KHZ << AW88261_I2SSR_START_BIT)
#define AW88261_I2SSR_16KHZ (3)
#define AW88261_I2SSR_16KHZ_VALUE \
(AW88261_I2SSR_16KHZ << AW88261_I2SSR_START_BIT)
#define AW88261_I2SSR_22P05KHZ (4)
#define AW88261_I2SSR_22P05KHZ_VALUE \
(AW88261_I2SSR_22P05KHZ << AW88261_I2SSR_START_BIT)
#define AW88261_I2SSR_24KHZ (5)
#define AW88261_I2SSR_24KHZ_VALUE \
(AW88261_I2SSR_24KHZ << AW88261_I2SSR_START_BIT)
#define AW88261_I2SSR_32KHZ (6)
#define AW88261_I2SSR_32KHZ_VALUE \
(AW88261_I2SSR_32KHZ << AW88261_I2SSR_START_BIT)
#define AW88261_I2SSR_44P1KHZ (7)
#define AW88261_I2SSR_44P1KHZ_VALUE \
(AW88261_I2SSR_44P1KHZ << AW88261_I2SSR_START_BIT)
#define AW88261_I2SSR_48KHZ (8)
#define AW88261_I2SSR_48KHZ_VALUE \
(AW88261_I2SSR_48KHZ << AW88261_I2SSR_START_BIT)
#define AW88261_I2SSR_96KHZ (9)
#define AW88261_I2SSR_96KHZ_VALUE \
(AW88261_I2SSR_96KHZ << AW88261_I2SSR_START_BIT)
#define AW88261_I2SSR_192KHZ (10)
#define AW88261_I2SSR_192KHZ_VALUE \
(AW88261_I2SSR_192KHZ << AW88261_I2SSR_START_BIT)
#define AW88261_CCO_MUX_START_BIT (6)
#define AW88261_CCO_MUX_BITS_LEN (1)
#define AW88261_CCO_MUX_MASK \
(~(((1<<AW88261_CCO_MUX_BITS_LEN)-1) << AW88261_CCO_MUX_START_BIT))
@ -370,7 +474,10 @@
#define AW88261_START_RETRIES (5)
#define AW88261_START_WORK_DELAY_MS (0)
/* NOTE: 192000 has a reg value donwstream but not listed in datasheet */
#define AW88261_RATES (SNDRV_PCM_RATE_8000_48000 | \
SNDRV_PCM_RATE_12000 | \
SNDRV_PCM_RATE_24000 | \
SNDRV_PCM_RATE_96000)
#define AW88261_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
@ -451,6 +558,13 @@ struct aw88261 {
unsigned int mute_st;
unsigned int amppd_st;
unsigned int sr_value;
unsigned int cco_mux_value;
unsigned int fs_value;
unsigned int bck_value;
unsigned int bck_inv_value;
unsigned int md_value;
bool phase_sync;
};