ASoC: codecs: Add aw88083 amplifier driver
The driver is for amplifiers aw88083 of Awinic Technology Corporation. The AW88083 is an intelligent digital audio amplifier with low noise. Signed-off-by: Weidong Wang <wangweidong.a@awinic.com> Link: https://patch.msgid.link/20241231125610.465614-3-wangweidong.a@awinic.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
e7b7398138
commit
be947cc0cb
|
@ -692,7 +692,7 @@ config SND_SOC_AW88261
|
||||||
the input amplitude.
|
the input amplitude.
|
||||||
|
|
||||||
config SND_SOC_AW88081
|
config SND_SOC_AW88081
|
||||||
tristate "Soc Audio for awinic aw88081"
|
tristate "Soc Audio for awinic aw88081/aw88083"
|
||||||
depends on I2C
|
depends on I2C
|
||||||
select REGMAP_I2C
|
select REGMAP_I2C
|
||||||
select SND_SOC_AW88395_LIB
|
select SND_SOC_AW88395_LIB
|
||||||
|
|
|
@ -14,13 +14,18 @@
|
||||||
#include "aw88081.h"
|
#include "aw88081.h"
|
||||||
#include "aw88395/aw88395_device.h"
|
#include "aw88395/aw88395_device.h"
|
||||||
|
|
||||||
|
enum aw8808x_type {
|
||||||
|
AW88081,
|
||||||
|
AW88083,
|
||||||
|
};
|
||||||
|
|
||||||
struct aw88081 {
|
struct aw88081 {
|
||||||
struct aw_device *aw_pa;
|
struct aw_device *aw_pa;
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
struct delayed_work start_work;
|
struct delayed_work start_work;
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
struct aw_container *aw_cfg;
|
struct aw_container *aw_cfg;
|
||||||
|
enum aw8808x_type devtype;
|
||||||
bool phase_sync;
|
bool phase_sync;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -32,6 +37,14 @@ static const struct regmap_config aw88081_regmap_config = {
|
||||||
.val_format_endian = REGMAP_ENDIAN_BIG,
|
.val_format_endian = REGMAP_ENDIAN_BIG,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct regmap_config aw88083_regmap_config = {
|
||||||
|
.val_bits = 16,
|
||||||
|
.reg_bits = 8,
|
||||||
|
.max_register = AW88083_REG_MAX,
|
||||||
|
.reg_format_endian = REGMAP_ENDIAN_LITTLE,
|
||||||
|
.val_format_endian = REGMAP_ENDIAN_BIG,
|
||||||
|
};
|
||||||
|
|
||||||
static int aw88081_dev_get_iis_status(struct aw_device *aw_dev)
|
static int aw88081_dev_get_iis_status(struct aw_device *aw_dev)
|
||||||
{
|
{
|
||||||
unsigned int reg_val;
|
unsigned int reg_val;
|
||||||
|
@ -196,6 +209,41 @@ static void aw88081_dev_amppd(struct aw_device *aw_dev, bool amppd)
|
||||||
~AW88081_EN_PA_MASK, AW88081_EN_PA_WORKING_VALUE);
|
~AW88081_EN_PA_MASK, AW88081_EN_PA_WORKING_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void aw88083_i2c_wen(struct aw88081 *aw88081, bool flag)
|
||||||
|
{
|
||||||
|
struct aw_device *aw_dev = aw88081->aw_pa;
|
||||||
|
|
||||||
|
if (aw88081->devtype != AW88083)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (flag)
|
||||||
|
regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
|
||||||
|
~AW88083_I2C_WEN_MASK, AW88083_I2C_WEN_ENABLE_VALUE);
|
||||||
|
else
|
||||||
|
regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
|
||||||
|
~AW88083_I2C_WEN_MASK, AW88083_I2C_WEN_DISABLE_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void aw88083_dev_amppd(struct aw_device *aw_dev, bool amppd)
|
||||||
|
{
|
||||||
|
if (amppd)
|
||||||
|
regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
|
||||||
|
~AW88083_AMPPD_MASK, AW88083_AMPPD_POWER_DOWN_VALUE);
|
||||||
|
else
|
||||||
|
regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
|
||||||
|
~AW88083_AMPPD_MASK, AW88083_AMPPD_WORKING_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void aw88083_dev_pllpd(struct aw_device *aw_dev, bool pllpd)
|
||||||
|
{
|
||||||
|
if (pllpd)
|
||||||
|
regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
|
||||||
|
~AW88083_PLL_PD_MASK, AW88083_PLL_PD_WORKING_VALUE);
|
||||||
|
else
|
||||||
|
regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
|
||||||
|
~AW88083_PLL_PD_MASK, AW88083_PLL_PD_POWER_DOWN_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
static void aw88081_dev_clear_int_status(struct aw_device *aw_dev)
|
static void aw88081_dev_clear_int_status(struct aw_device *aw_dev)
|
||||||
{
|
{
|
||||||
unsigned int int_status;
|
unsigned int int_status;
|
||||||
|
@ -284,12 +332,90 @@ static void aw88081_dev_uls_hmute(struct aw_device *aw_dev, bool uls_hmute)
|
||||||
AW88081_ULS_HMUTE_DISABLE_VALUE);
|
AW88081_ULS_HMUTE_DISABLE_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int aw88081_dev_reg_value_check(struct aw_device *aw_dev,
|
||||||
|
unsigned char reg_addr, unsigned short *reg_val)
|
||||||
|
{
|
||||||
|
unsigned int read_vol;
|
||||||
|
|
||||||
|
if (reg_addr == AW88081_SYSCTRL_REG) {
|
||||||
|
*reg_val &= ~(~AW88081_EN_PA_MASK |
|
||||||
|
~AW88081_PWDN_MASK |
|
||||||
|
~AW88081_HMUTE_MASK |
|
||||||
|
~AW88081_ULS_HMUTE_MASK);
|
||||||
|
|
||||||
|
*reg_val |= AW88081_EN_PA_POWER_DOWN_VALUE |
|
||||||
|
AW88081_PWDN_POWER_DOWN_VALUE |
|
||||||
|
AW88081_HMUTE_ENABLE_VALUE |
|
||||||
|
AW88081_ULS_HMUTE_ENABLE_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reg_addr == AW88081_SYSCTRL2_REG) {
|
||||||
|
read_vol = (*reg_val & (~AW88081_VOL_MASK)) >> AW88081_VOL_START_BIT;
|
||||||
|
aw_dev->volume_desc.init_volume = read_vol;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* i2stxen */
|
||||||
|
if (reg_addr == AW88081_I2SCTRL3_REG) {
|
||||||
|
/* close tx */
|
||||||
|
*reg_val &= AW88081_I2STXEN_MASK;
|
||||||
|
*reg_val |= AW88081_I2STXEN_DISABLE_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int aw88083_dev_reg_value_check(struct aw_device *aw_dev,
|
||||||
|
unsigned char reg_addr, unsigned short *reg_val)
|
||||||
|
{
|
||||||
|
unsigned int read_vol;
|
||||||
|
|
||||||
|
if (reg_addr == AW88081_SYSCTRL_REG) {
|
||||||
|
*reg_val &= ~(~AW88083_AMPPD_MASK |
|
||||||
|
~AW88081_PWDN_MASK |
|
||||||
|
~AW88081_HMUTE_MASK |
|
||||||
|
~AW88083_I2C_WEN_MASK);
|
||||||
|
|
||||||
|
*reg_val |= AW88083_AMPPD_POWER_DOWN_VALUE |
|
||||||
|
AW88081_PWDN_POWER_DOWN_VALUE |
|
||||||
|
AW88081_HMUTE_ENABLE_VALUE |
|
||||||
|
AW88083_I2C_WEN_ENABLE_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reg_addr == AW88081_SYSCTRL2_REG) {
|
||||||
|
read_vol = (*reg_val & (~AW88081_VOL_MASK)) >> AW88081_VOL_START_BIT;
|
||||||
|
aw_dev->volume_desc.init_volume = read_vol;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int aw88081_reg_value_check(struct aw88081 *aw88081,
|
||||||
|
unsigned char reg_addr, unsigned short *reg_val)
|
||||||
|
{
|
||||||
|
struct aw_device *aw_dev = aw88081->aw_pa;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
switch (aw88081->devtype) {
|
||||||
|
case AW88081:
|
||||||
|
ret = aw88081_dev_reg_value_check(aw_dev, reg_addr, reg_val);
|
||||||
|
break;
|
||||||
|
case AW88083:
|
||||||
|
ret = aw88083_dev_reg_value_check(aw_dev, reg_addr, reg_val);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dev_err(aw_dev->dev, "unsupported device\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int aw88081_dev_reg_update(struct aw88081 *aw88081,
|
static int aw88081_dev_reg_update(struct aw88081 *aw88081,
|
||||||
unsigned char *data, unsigned int len)
|
unsigned char *data, unsigned int len)
|
||||||
{
|
{
|
||||||
struct aw_device *aw_dev = aw88081->aw_pa;
|
struct aw_device *aw_dev = aw88081->aw_pa;
|
||||||
struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
|
struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
|
||||||
unsigned int read_vol;
|
|
||||||
int data_len, i, ret;
|
int data_len, i, ret;
|
||||||
int16_t *reg_data;
|
int16_t *reg_data;
|
||||||
u16 reg_val;
|
u16 reg_val;
|
||||||
|
@ -312,30 +438,9 @@ static int aw88081_dev_reg_update(struct aw88081 *aw88081,
|
||||||
reg_addr = reg_data[i];
|
reg_addr = reg_data[i];
|
||||||
reg_val = reg_data[i + 1];
|
reg_val = reg_data[i + 1];
|
||||||
|
|
||||||
if (reg_addr == AW88081_SYSCTRL_REG) {
|
ret = aw88081_reg_value_check(aw88081, reg_addr, ®_val);
|
||||||
reg_val &= ~(~AW88081_EN_PA_MASK |
|
if (ret)
|
||||||
~AW88081_PWDN_MASK |
|
return ret;
|
||||||
~AW88081_HMUTE_MASK |
|
|
||||||
~AW88081_ULS_HMUTE_MASK);
|
|
||||||
|
|
||||||
reg_val |= AW88081_EN_PA_POWER_DOWN_VALUE |
|
|
||||||
AW88081_PWDN_POWER_DOWN_VALUE |
|
|
||||||
AW88081_HMUTE_ENABLE_VALUE |
|
|
||||||
AW88081_ULS_HMUTE_ENABLE_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reg_addr == AW88081_SYSCTRL2_REG) {
|
|
||||||
read_vol = (reg_val & (~AW88081_VOL_MASK)) >>
|
|
||||||
AW88081_VOL_START_BIT;
|
|
||||||
aw_dev->volume_desc.init_volume = read_vol;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* i2stxen */
|
|
||||||
if (reg_addr == AW88081_I2SCTRL3_REG) {
|
|
||||||
/* close tx */
|
|
||||||
reg_val &= AW88081_I2STXEN_MASK;
|
|
||||||
reg_val |= AW88081_I2STXEN_DISABLE_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = regmap_write(aw_dev->regmap, reg_addr, reg_val);
|
ret = regmap_write(aw_dev->regmap, reg_addr, reg_val);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -474,8 +579,60 @@ pll_check_fail:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int aw88081_dev_stop(struct aw_device *aw_dev)
|
static int aw88083_dev_start(struct aw88081 *aw88081)
|
||||||
{
|
{
|
||||||
|
struct aw_device *aw_dev = aw88081->aw_pa;
|
||||||
|
|
||||||
|
if (aw_dev->status == AW88081_DEV_PW_ON) {
|
||||||
|
dev_dbg(aw_dev->dev, "already power on");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
aw88083_i2c_wen(aw88081, true);
|
||||||
|
|
||||||
|
/* power on */
|
||||||
|
aw88081_dev_pwd(aw_dev, false);
|
||||||
|
usleep_range(AW88081_2000_US, AW88081_2000_US + 10);
|
||||||
|
|
||||||
|
aw88083_dev_pllpd(aw_dev, true);
|
||||||
|
/* amppd on */
|
||||||
|
aw88083_dev_amppd(aw_dev, false);
|
||||||
|
usleep_range(AW88081_2000_US, AW88081_2000_US + 50);
|
||||||
|
|
||||||
|
/* close mute */
|
||||||
|
aw88081_dev_mute(aw_dev, false);
|
||||||
|
|
||||||
|
aw88083_i2c_wen(aw88081, false);
|
||||||
|
|
||||||
|
aw_dev->status = AW88081_DEV_PW_ON;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int aw88081_device_start(struct aw88081 *aw88081)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
switch (aw88081->devtype) {
|
||||||
|
case AW88081:
|
||||||
|
ret = aw88081_dev_start(aw88081);
|
||||||
|
break;
|
||||||
|
case AW88083:
|
||||||
|
ret = aw88083_dev_start(aw88081);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = -EINVAL;
|
||||||
|
dev_err(aw88081->aw_pa->dev, "unsupported device\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int aw88081_dev_stop(struct aw88081 *aw88081)
|
||||||
|
{
|
||||||
|
struct aw_device *aw_dev = aw88081->aw_pa;
|
||||||
|
|
||||||
if (aw_dev->status == AW88081_DEV_PW_OFF) {
|
if (aw_dev->status == AW88081_DEV_PW_OFF) {
|
||||||
dev_dbg(aw_dev->dev, "already power off");
|
dev_dbg(aw_dev->dev, "already power off");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -503,6 +660,56 @@ static int aw88081_dev_stop(struct aw_device *aw_dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int aw88083_dev_stop(struct aw88081 *aw88081)
|
||||||
|
{
|
||||||
|
struct aw_device *aw_dev = aw88081->aw_pa;
|
||||||
|
|
||||||
|
if (aw_dev->status == AW88081_DEV_PW_OFF) {
|
||||||
|
dev_dbg(aw_dev->dev, "already power off");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
aw_dev->status = AW88081_DEV_PW_OFF;
|
||||||
|
|
||||||
|
aw88083_i2c_wen(aw88081, true);
|
||||||
|
/* set mute */
|
||||||
|
aw88081_dev_mute(aw_dev, true);
|
||||||
|
|
||||||
|
usleep_range(AW88081_2000_US, AW88081_2000_US + 100);
|
||||||
|
|
||||||
|
/* enable amppd */
|
||||||
|
aw88083_dev_amppd(aw_dev, true);
|
||||||
|
|
||||||
|
aw88083_dev_pllpd(aw_dev, false);
|
||||||
|
|
||||||
|
/* set power down */
|
||||||
|
aw88081_dev_pwd(aw_dev, true);
|
||||||
|
|
||||||
|
aw88083_i2c_wen(aw88081, false);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int aw88081_stop(struct aw88081 *aw88081)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
switch (aw88081->devtype) {
|
||||||
|
case AW88081:
|
||||||
|
ret = aw88081_dev_stop(aw88081);
|
||||||
|
break;
|
||||||
|
case AW88083:
|
||||||
|
ret = aw88083_dev_stop(aw88081);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dev_err(aw88081->aw_pa->dev, "unsupported device\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int aw88081_reg_update(struct aw88081 *aw88081, bool force)
|
static int aw88081_reg_update(struct aw88081 *aw88081, bool force)
|
||||||
{
|
{
|
||||||
struct aw_device *aw_dev = aw88081->aw_pa;
|
struct aw_device *aw_dev = aw88081->aw_pa;
|
||||||
|
@ -540,7 +747,7 @@ static void aw88081_start_pa(struct aw88081 *aw88081)
|
||||||
dev_err(aw88081->aw_pa->dev, "fw update failed, cnt:%d\n", i);
|
dev_err(aw88081->aw_pa->dev, "fw update failed, cnt:%d\n", i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ret = aw88081_dev_start(aw88081);
|
ret = aw88081_device_start(aw88081);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(aw88081->aw_pa->dev, "aw88081 device start failed. retry = %d", i);
|
dev_err(aw88081->aw_pa->dev, "aw88081 device start failed. retry = %d", i);
|
||||||
continue;
|
continue;
|
||||||
|
@ -745,7 +952,7 @@ static int aw88081_profile_set(struct snd_kcontrol *kcontrol,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aw88081->aw_pa->status) {
|
if (aw88081->aw_pa->status) {
|
||||||
aw88081_dev_stop(aw88081->aw_pa);
|
aw88081_stop(aw88081);
|
||||||
aw88081_start(aw88081, AW88081_SYNC_START);
|
aw88081_start(aw88081, AW88081_SYNC_START);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -781,12 +988,16 @@ static int aw88081_volume_set(struct snd_kcontrol *kcontrol,
|
||||||
if (value < mc->min || value > mc->max)
|
if (value < mc->min || value > mc->max)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
aw88083_i2c_wen(aw88081, true);
|
||||||
|
|
||||||
if (vol_desc->ctl_volume != value) {
|
if (vol_desc->ctl_volume != value) {
|
||||||
vol_desc->ctl_volume = value;
|
vol_desc->ctl_volume = value;
|
||||||
aw88081_dev_set_volume(aw88081->aw_pa, vol_desc->ctl_volume);
|
aw88081_dev_set_volume(aw88081->aw_pa, vol_desc->ctl_volume);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aw88083_i2c_wen(aw88081, false);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -860,13 +1071,19 @@ static int aw88081_init(struct aw88081 *aw88081, struct i2c_client *i2c, struct
|
||||||
dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret);
|
dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
if (chip_id != AW88081_CHIP_ID) {
|
|
||||||
|
switch (chip_id) {
|
||||||
|
case AW88081_CHIP_ID:
|
||||||
|
dev_dbg(&i2c->dev, "chip id = 0x%x\n", chip_id);
|
||||||
|
break;
|
||||||
|
case AW88083_CHIP_ID:
|
||||||
|
dev_dbg(&i2c->dev, "chip id = 0x%x\n", chip_id);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
dev_err(&i2c->dev, "unsupported device");
|
dev_err(&i2c->dev, "unsupported device");
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_dbg(&i2c->dev, "chip id = %x\n", chip_id);
|
|
||||||
|
|
||||||
aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL);
|
aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL);
|
||||||
if (!aw_dev)
|
if (!aw_dev)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -875,7 +1092,7 @@ static int aw88081_init(struct aw88081 *aw88081, struct i2c_client *i2c, struct
|
||||||
aw_dev->i2c = i2c;
|
aw_dev->i2c = i2c;
|
||||||
aw_dev->regmap = regmap;
|
aw_dev->regmap = regmap;
|
||||||
aw_dev->dev = &i2c->dev;
|
aw_dev->dev = &i2c->dev;
|
||||||
aw_dev->chip_id = AW88081_CHIP_ID;
|
aw_dev->chip_id = chip_id;
|
||||||
aw_dev->acf = NULL;
|
aw_dev->acf = NULL;
|
||||||
aw_dev->prof_info.prof_desc = NULL;
|
aw_dev->prof_info.prof_desc = NULL;
|
||||||
aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID;
|
aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID;
|
||||||
|
@ -912,21 +1129,8 @@ static int aw88081_dev_init(struct aw88081 *aw88081, struct aw_container *aw_cfg
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
aw88081_dev_clear_int_status(aw_dev);
|
aw_dev->status = AW88081_DEV_PW_ON;
|
||||||
|
aw88081_stop(aw88081);
|
||||||
aw88081_dev_uls_hmute(aw_dev, true);
|
|
||||||
|
|
||||||
aw88081_dev_mute(aw_dev, true);
|
|
||||||
|
|
||||||
usleep_range(AW88081_5000_US, AW88081_5000_US + 10);
|
|
||||||
|
|
||||||
aw88081_dev_i2s_tx_enable(aw_dev, false);
|
|
||||||
|
|
||||||
usleep_range(AW88081_1000_US, AW88081_1000_US + 100);
|
|
||||||
|
|
||||||
aw88081_dev_amppd(aw_dev, true);
|
|
||||||
|
|
||||||
aw88081_dev_pwd(aw_dev, true);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -977,7 +1181,7 @@ static int aw88081_playback_event(struct snd_soc_dapm_widget *w,
|
||||||
aw88081_start(aw88081, AW88081_ASYNC_START);
|
aw88081_start(aw88081, AW88081_ASYNC_START);
|
||||||
break;
|
break;
|
||||||
case SND_SOC_DAPM_POST_PMD:
|
case SND_SOC_DAPM_POST_PMD:
|
||||||
aw88081_dev_stop(aw88081->aw_pa);
|
aw88081_stop(aw88081);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -1036,8 +1240,17 @@ static const struct snd_soc_component_driver soc_codec_dev_aw88081 = {
|
||||||
.num_controls = ARRAY_SIZE(aw88081_controls),
|
.num_controls = ARRAY_SIZE(aw88081_controls),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct i2c_device_id aw88081_i2c_id[] = {
|
||||||
|
{ AW88081_I2C_NAME, AW88081},
|
||||||
|
{ AW88083_I2C_NAME, AW88083},
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, aw88081_i2c_id);
|
||||||
|
|
||||||
static int aw88081_i2c_probe(struct i2c_client *i2c)
|
static int aw88081_i2c_probe(struct i2c_client *i2c)
|
||||||
{
|
{
|
||||||
|
const struct regmap_config *regmap_config;
|
||||||
|
const struct i2c_device_id *id;
|
||||||
struct aw88081 *aw88081;
|
struct aw88081 *aw88081;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -1049,11 +1262,25 @@ static int aw88081_i2c_probe(struct i2c_client *i2c)
|
||||||
if (!aw88081)
|
if (!aw88081)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
id = i2c_match_id(aw88081_i2c_id, i2c);
|
||||||
|
aw88081->devtype = id->driver_data;
|
||||||
|
|
||||||
mutex_init(&aw88081->lock);
|
mutex_init(&aw88081->lock);
|
||||||
|
|
||||||
i2c_set_clientdata(i2c, aw88081);
|
i2c_set_clientdata(i2c, aw88081);
|
||||||
|
|
||||||
aw88081->regmap = devm_regmap_init_i2c(i2c, &aw88081_regmap_config);
|
switch (aw88081->devtype) {
|
||||||
|
case AW88081:
|
||||||
|
regmap_config = &aw88081_regmap_config;
|
||||||
|
break;
|
||||||
|
case AW88083:
|
||||||
|
regmap_config = &aw88083_regmap_config;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
aw88081->regmap = devm_regmap_init_i2c(i2c, regmap_config);
|
||||||
if (IS_ERR(aw88081->regmap))
|
if (IS_ERR(aw88081->regmap))
|
||||||
return dev_err_probe(&i2c->dev, PTR_ERR(aw88081->regmap),
|
return dev_err_probe(&i2c->dev, PTR_ERR(aw88081->regmap),
|
||||||
"failed to init regmap\n");
|
"failed to init regmap\n");
|
||||||
|
@ -1068,12 +1295,6 @@ static int aw88081_i2c_probe(struct i2c_client *i2c)
|
||||||
aw88081_dai, ARRAY_SIZE(aw88081_dai));
|
aw88081_dai, ARRAY_SIZE(aw88081_dai));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct i2c_device_id aw88081_i2c_id[] = {
|
|
||||||
{ AW88081_I2C_NAME },
|
|
||||||
{ }
|
|
||||||
};
|
|
||||||
MODULE_DEVICE_TABLE(i2c, aw88081_i2c_id);
|
|
||||||
|
|
||||||
static struct i2c_driver aw88081_i2c_driver = {
|
static struct i2c_driver aw88081_i2c_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = AW88081_I2C_NAME,
|
.name = AW88081_I2C_NAME,
|
||||||
|
|
|
@ -231,6 +231,49 @@
|
||||||
#define AW88081_CCO_MUX_BYPASS_VALUE \
|
#define AW88081_CCO_MUX_BYPASS_VALUE \
|
||||||
(AW88081_CCO_MUX_BYPASS << AW88081_CCO_MUX_START_BIT)
|
(AW88081_CCO_MUX_BYPASS << AW88081_CCO_MUX_START_BIT)
|
||||||
|
|
||||||
|
#define AW88083_I2C_WEN_START_BIT (14)
|
||||||
|
#define AW88083_I2C_WEN_BITS_LEN (2)
|
||||||
|
#define AW88083_I2C_WEN_MASK \
|
||||||
|
(~(((1<<AW88083_I2C_WEN_BITS_LEN)-1) << AW88083_I2C_WEN_START_BIT))
|
||||||
|
|
||||||
|
#define AW88083_I2C_WEN_DISABLE (0)
|
||||||
|
#define AW88083_I2C_WEN_DISABLE_VALUE \
|
||||||
|
(AW88083_I2C_WEN_DISABLE << AW88083_I2C_WEN_START_BIT)
|
||||||
|
|
||||||
|
#define AW88083_I2C_WEN_ENABLE (2)
|
||||||
|
#define AW88083_I2C_WEN_ENABLE_VALUE \
|
||||||
|
(AW88083_I2C_WEN_ENABLE << AW88083_I2C_WEN_START_BIT)
|
||||||
|
|
||||||
|
#define AW88083_PLL_PD_START_BIT (2)
|
||||||
|
#define AW88083_PLL_PD_BITS_LEN (1)
|
||||||
|
#define AW88083_PLL_PD_MASK \
|
||||||
|
(~(((1<<AW88083_PLL_PD_BITS_LEN)-1) << AW88083_PLL_PD_START_BIT))
|
||||||
|
|
||||||
|
#define AW88083_PLL_PD_POWER_DOWN (1)
|
||||||
|
#define AW88083_PLL_PD_POWER_DOWN_VALUE \
|
||||||
|
(AW88083_PLL_PD_POWER_DOWN << AW88083_PLL_PD_START_BIT)
|
||||||
|
|
||||||
|
#define AW88083_PLL_PD_WORKING (0)
|
||||||
|
#define AW88083_PLL_PD_WORKING_VALUE \
|
||||||
|
(AW88083_PLL_PD_WORKING << AW88083_PLL_PD_START_BIT)
|
||||||
|
|
||||||
|
#define AW88083_AMPPD_START_BIT (1)
|
||||||
|
#define AW88083_AMPPD_BITS_LEN (1)
|
||||||
|
#define AW88083_AMPPD_MASK \
|
||||||
|
(~(((1<<AW88083_AMPPD_BITS_LEN)-1) << AW88083_AMPPD_START_BIT))
|
||||||
|
|
||||||
|
#define AW88083_AMPPD_WORKING (0)
|
||||||
|
#define AW88083_AMPPD_WORKING_VALUE \
|
||||||
|
(AW88083_AMPPD_WORKING << AW88083_AMPPD_START_BIT)
|
||||||
|
|
||||||
|
#define AW88083_AMPPD_POWER_DOWN (1)
|
||||||
|
#define AW88083_AMPPD_POWER_DOWN_VALUE \
|
||||||
|
(AW88083_AMPPD_POWER_DOWN << AW88083_AMPPD_START_BIT)
|
||||||
|
|
||||||
|
#define AW88083_REG_MAX (0x7D)
|
||||||
|
#define AW88083_I2C_NAME "aw88083"
|
||||||
|
#define AW88083_CHIP_ID 0x2407
|
||||||
|
|
||||||
#define AW88081_START_RETRIES (5)
|
#define AW88081_START_RETRIES (5)
|
||||||
#define AW88081_START_WORK_DELAY_MS (0)
|
#define AW88081_START_WORK_DELAY_MS (0)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue