diff mbox series

[V2,2/2] ASoC: codecs: Add aw88083 amplifier driver

Message ID 20241219123047.33330-3-wangweidong.a@awinic.com (mailing list archive)
State New
Headers show
Series ASoC: codecs: Add aw88083 amplifier driver | expand

Commit Message

wangweidong.a@awinic.com Dec. 19, 2024, 12:30 p.m. UTC
From: Weidong Wang <wangweidong.a@awinic.com>

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>
---
 sound/soc/codecs/Kconfig   |   2 +-
 sound/soc/codecs/aw88081.c | 344 ++++++++++++++++++++++++++++++-------
 sound/soc/codecs/aw88081.h |  43 +++++
 3 files changed, 326 insertions(+), 63 deletions(-)

Comments

kernel test robot Dec. 20, 2024, 10:17 a.m. UTC | #1
Hi,

kernel test robot noticed the following build errors:

[auto build test ERROR on eabcdba3ad4098460a376538df2ae36500223c1e]

url:    https://github.com/intel-lab-lkp/linux/commits/wangweidong-a-awinic-com/ASoC-dt-bindings-Add-schema-for-awinic-aw88083/20241219-203933
base:   eabcdba3ad4098460a376538df2ae36500223c1e
patch link:    https://lore.kernel.org/r/20241219123047.33330-3-wangweidong.a%40awinic.com
patch subject: [PATCH V2 2/2] ASoC: codecs: Add aw88083 amplifier driver
config: arc-randconfig-002-20241220 (https://download.01.org/0day-ci/archive/20241220/202412201745.fBpf3Ui5-lkp@intel.com/config)
compiler: arc-elf-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241220/202412201745.fBpf3Ui5-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202412201745.fBpf3Ui5-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from include/linux/device.h:15,
                    from include/linux/acpi.h:14,
                    from include/linux/i2c.h:13,
                    from sound/soc/codecs/aw88081.c:11:
   sound/soc/codecs/aw88081.c: In function 'aw8808x_reg_value_check':
>> sound/soc/codecs/aw88081.c:407:25: error: passing argument 1 of '_dev_err' from incompatible pointer type [-Werror=incompatible-pointer-types]
     407 |                 dev_err(aw_dev, "unsupported this device\n");
         |                         ^~~~~~
         |                         |
         |                         struct aw_device *
   include/linux/dev_printk.h:110:25: note: in definition of macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                         ^~~
   sound/soc/codecs/aw88081.c:407:17: note: in expansion of macro 'dev_err'
     407 |                 dev_err(aw_dev, "unsupported this device\n");
         |                 ^~~~~~~
   include/linux/dev_printk.h:50:36: note: expected 'const struct device *' but argument is of type 'struct aw_device *'
      50 | void _dev_err(const struct device *dev, const char *fmt, ...);
         |               ~~~~~~~~~~~~~~~~~~~~~^~~
   sound/soc/codecs/aw88081.c: In function 'aw88081_dev_reg_update':
>> sound/soc/codecs/aw88081.c:442:66: error: passing argument 3 of 'aw8808x_reg_value_check' from incompatible pointer type [-Werror=incompatible-pointer-types]
     442 |                 ret = aw8808x_reg_value_check(aw88081, reg_addr, &reg_val);
         |                                                                  ^~~~~~~~
         |                                                                  |
         |                                                                  u16 * {aka short unsigned int *}
   sound/soc/codecs/aw88081.c:394:78: note: expected 'unsigned int *' but argument is of type 'u16 *' {aka 'short unsigned int *'}
     394 |                                         unsigned int reg_addr, unsigned int *reg_val)
         |                                                                ~~~~~~~~~~~~~~^~~~~~~
   cc1: some warnings being treated as errors


vim +/_dev_err +407 sound/soc/codecs/aw88081.c

   392	
   393	static int aw8808x_reg_value_check(struct aw88081 *aw88081,
   394						unsigned int reg_addr, unsigned int *reg_val)
   395	{
   396		struct aw_device *aw_dev = aw88081->aw_pa;
   397		int ret;
   398	
   399		switch (aw88081->devtype) {
   400		case AW88081:
   401			ret = aw88081_dev_reg_value_check(aw_dev, reg_addr, reg_val);
   402			break;
   403		case AW88083:
   404			ret = aw88083_dev_reg_value_check(aw_dev, reg_addr, reg_val);
   405			break;
   406		default:
 > 407			dev_err(aw_dev, "unsupported this device\n");
   408			ret = -EINVAL;
   409			break;
   410		}
   411	
   412		return ret;
   413	}
   414	
   415	static int aw88081_dev_reg_update(struct aw88081 *aw88081,
   416						unsigned char *data, unsigned int len)
   417	{
   418		struct aw_device *aw_dev = aw88081->aw_pa;
   419		struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
   420		int data_len, i, ret;
   421		int16_t *reg_data;
   422		u16 reg_val;
   423		u8 reg_addr;
   424	
   425		if (!len || !data) {
   426			dev_err(aw_dev->dev, "reg data is null or len is 0");
   427			return -EINVAL;
   428		}
   429	
   430		reg_data = (int16_t *)data;
   431		data_len = len >> 1;
   432	
   433		if (data_len & 0x1) {
   434			dev_err(aw_dev->dev, "data len:%d unsupported",	data_len);
   435			return -EINVAL;
   436		}
   437	
   438		for (i = 0; i < data_len; i += 2) {
   439			reg_addr = reg_data[i];
   440			reg_val = reg_data[i + 1];
   441	
 > 442			ret = aw8808x_reg_value_check(aw88081, reg_addr, &reg_val);
   443			if (ret)
   444				return ret;
   445	
   446			ret = regmap_write(aw_dev->regmap, reg_addr, reg_val);
   447			if (ret)
   448				return ret;
   449		}
   450	
   451		if (aw_dev->prof_cur != aw_dev->prof_index)
   452			vol_desc->ctl_volume = 0;
   453	
   454		/* keep min volume */
   455		aw88081_dev_set_volume(aw_dev, vol_desc->mute_volume);
   456	
   457		return 0;
   458	}
   459
kernel test robot Dec. 20, 2024, 1:42 p.m. UTC | #2
Hi,

kernel test robot noticed the following build errors:

[auto build test ERROR on eabcdba3ad4098460a376538df2ae36500223c1e]

url:    https://github.com/intel-lab-lkp/linux/commits/wangweidong-a-awinic-com/ASoC-dt-bindings-Add-schema-for-awinic-aw88083/20241219-203933
base:   eabcdba3ad4098460a376538df2ae36500223c1e
patch link:    https://lore.kernel.org/r/20241219123047.33330-3-wangweidong.a%40awinic.com
patch subject: [PATCH V2 2/2] ASoC: codecs: Add aw88083 amplifier driver
config: i386-randconfig-014-20241220 (https://download.01.org/0day-ci/archive/20241220/202412202139.OayEq3D3-lkp@intel.com/config)
compiler: clang version 19.1.3 (https://github.com/llvm/llvm-project ab51eccf88f5321e7c60591c5546b254b6afab99)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241220/202412202139.OayEq3D3-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202412202139.OayEq3D3-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from sound/soc/codecs/aw88081.c:11:
   In file included from include/linux/i2c.h:19:
   In file included from include/linux/regulator/consumer.h:35:
   In file included from include/linux/suspend.h:5:
   In file included from include/linux/swap.h:9:
   In file included from include/linux/memcontrol.h:21:
   In file included from include/linux/mm.h:2223:
   include/linux/vmstat.h:518:36: warning: arithmetic between different enumeration types ('enum node_stat_item' and 'enum lru_list') [-Wenum-enum-conversion]
     518 |         return node_stat_name(NR_LRU_BASE + lru) + 3; // skip "nr_"
         |                               ~~~~~~~~~~~ ^ ~~~
>> sound/soc/codecs/aw88081.c:407:11: error: incompatible pointer types passing 'struct aw_device *' to parameter of type 'const struct device *' [-Werror,-Wincompatible-pointer-types]
     407 |                 dev_err(aw_dev, "unsupported this device\n");
         |                         ^~~~~~
   include/linux/dev_printk.h:154:44: note: expanded from macro 'dev_err'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                   ^~~
   include/linux/dev_printk.h:110:11: note: expanded from macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                         ^~~
   include/linux/dev_printk.h:50:36: note: passing argument to parameter 'dev' here
      50 | void _dev_err(const struct device *dev, const char *fmt, ...);
         |                                    ^
>> sound/soc/codecs/aw88081.c:442:52: error: incompatible pointer types passing 'u16 *' (aka 'unsigned short *') to parameter of type 'unsigned int *' [-Werror,-Wincompatible-pointer-types]
     442 |                 ret = aw8808x_reg_value_check(aw88081, reg_addr, &reg_val);
         |                                                                  ^~~~~~~~
   sound/soc/codecs/aw88081.c:394:43: note: passing argument to parameter 'reg_val' here
     394 |                                         unsigned int reg_addr, unsigned int *reg_val)
         |                                                                              ^
   1 warning and 2 errors generated.


vim +407 sound/soc/codecs/aw88081.c

   392	
   393	static int aw8808x_reg_value_check(struct aw88081 *aw88081,
   394						unsigned int reg_addr, unsigned int *reg_val)
   395	{
   396		struct aw_device *aw_dev = aw88081->aw_pa;
   397		int ret;
   398	
   399		switch (aw88081->devtype) {
   400		case AW88081:
   401			ret = aw88081_dev_reg_value_check(aw_dev, reg_addr, reg_val);
   402			break;
   403		case AW88083:
   404			ret = aw88083_dev_reg_value_check(aw_dev, reg_addr, reg_val);
   405			break;
   406		default:
 > 407			dev_err(aw_dev, "unsupported this device\n");
   408			ret = -EINVAL;
   409			break;
   410		}
   411	
   412		return ret;
   413	}
   414	
   415	static int aw88081_dev_reg_update(struct aw88081 *aw88081,
   416						unsigned char *data, unsigned int len)
   417	{
   418		struct aw_device *aw_dev = aw88081->aw_pa;
   419		struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
   420		int data_len, i, ret;
   421		int16_t *reg_data;
   422		u16 reg_val;
   423		u8 reg_addr;
   424	
   425		if (!len || !data) {
   426			dev_err(aw_dev->dev, "reg data is null or len is 0");
   427			return -EINVAL;
   428		}
   429	
   430		reg_data = (int16_t *)data;
   431		data_len = len >> 1;
   432	
   433		if (data_len & 0x1) {
   434			dev_err(aw_dev->dev, "data len:%d unsupported",	data_len);
   435			return -EINVAL;
   436		}
   437	
   438		for (i = 0; i < data_len; i += 2) {
   439			reg_addr = reg_data[i];
   440			reg_val = reg_data[i + 1];
   441	
 > 442			ret = aw8808x_reg_value_check(aw88081, reg_addr, &reg_val);
   443			if (ret)
   444				return ret;
   445	
   446			ret = regmap_write(aw_dev->regmap, reg_addr, reg_val);
   447			if (ret)
   448				return ret;
   449		}
   450	
   451		if (aw_dev->prof_cur != aw_dev->prof_index)
   452			vol_desc->ctl_volume = 0;
   453	
   454		/* keep min volume */
   455		aw88081_dev_set_volume(aw_dev, vol_desc->mute_volume);
   456	
   457		return 0;
   458	}
   459
diff mbox series

Patch

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 0f2df7c91e18..0ba319683b6b 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -692,7 +692,7 @@  config SND_SOC_AW88261
 	  the input amplitude.
 
 config SND_SOC_AW88081
-	tristate "Soc Audio for awinic aw88081"
+	tristate "Soc Audio for awinic aw88081/aw88083"
 	depends on I2C
 	select REGMAP_I2C
 	select SND_SOC_AW88395_LIB
diff --git a/sound/soc/codecs/aw88081.c b/sound/soc/codecs/aw88081.c
index 58b8e002d76f..dc8359074f4b 100644
--- a/sound/soc/codecs/aw88081.c
+++ b/sound/soc/codecs/aw88081.c
@@ -14,13 +14,18 @@ 
 #include "aw88081.h"
 #include "aw88395/aw88395_device.h"
 
+enum aw8808x_type {
+	AW88081,
+	AW88083,
+};
+
 struct aw88081 {
 	struct aw_device *aw_pa;
 	struct mutex lock;
 	struct delayed_work start_work;
 	struct regmap *regmap;
 	struct aw_container *aw_cfg;
-
+	enum aw8808x_type devtype;
 	bool phase_sync;
 };
 
@@ -32,6 +37,14 @@  static const struct regmap_config aw88081_regmap_config = {
 	.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)
 {
 	unsigned int reg_val;
@@ -176,6 +189,21 @@  static void aw88081_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag)
 			~AW88081_I2STXEN_MASK, AW88081_I2STXEN_DISABLE_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 aw88081_dev_pwd(struct aw_device *aw_dev, bool pwd)
 {
 	if (pwd)
@@ -196,6 +224,26 @@  static void aw88081_dev_amppd(struct aw_device *aw_dev, bool amppd)
 				~AW88081_EN_PA_MASK, AW88081_EN_PA_WORKING_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)
 {
 	unsigned int int_status;
@@ -284,12 +332,91 @@  static void aw88081_dev_uls_hmute(struct aw_device *aw_dev, bool uls_hmute)
 				AW88081_ULS_HMUTE_DISABLE_VALUE);
 }
 
+static int aw88081_dev_reg_value_check(struct aw_device *aw_dev,
+					unsigned int reg_addr, unsigned int *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 int reg_addr, unsigned int *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 aw8808x_reg_value_check(struct aw88081 *aw88081,
+					unsigned int reg_addr, unsigned int *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, "unsupported this device\n");
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
 static int aw88081_dev_reg_update(struct aw88081 *aw88081,
 					unsigned char *data, unsigned int len)
 {
 	struct aw_device *aw_dev = aw88081->aw_pa;
 	struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
-	unsigned int read_vol;
 	int data_len, i, ret;
 	int16_t *reg_data;
 	u16 reg_val;
@@ -312,30 +439,9 @@  static int aw88081_dev_reg_update(struct aw88081 *aw88081,
 		reg_addr = reg_data[i];
 		reg_val = reg_data[i + 1];
 
-		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;
-		}
+		ret = aw8808x_reg_value_check(aw88081, reg_addr, &reg_val);
+		if (ret)
+			return ret;
 
 		ret = regmap_write(aw_dev->regmap, reg_addr, reg_val);
 		if (ret)
@@ -474,8 +580,59 @@  static int aw88081_dev_start(struct aw88081 *aw88081)
 	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 aw8808x_dev_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, "unsupport 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) {
 		dev_dbg(aw_dev->dev, "already power off");
 		return 0;
@@ -503,6 +660,56 @@  static int aw88081_dev_stop(struct aw_device *aw_dev)
 	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 aw8808x_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, "unsupport device\n");
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
 static int aw88081_reg_update(struct aw88081 *aw88081, bool force)
 {
 	struct aw_device *aw_dev = aw88081->aw_pa;
@@ -530,7 +737,7 @@  static int aw88081_reg_update(struct aw88081 *aw88081, bool force)
 	return 0;
 }
 
-static void aw88081_start_pa(struct aw88081 *aw88081)
+static void aw8808x_start_pa(struct aw88081 *aw88081)
 {
 	int ret, i;
 
@@ -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);
 			continue;
 		}
-		ret = aw88081_dev_start(aw88081);
+		ret = aw8808x_dev_start(aw88081);
 		if (ret) {
 			dev_err(aw88081->aw_pa->dev, "aw88081 device start failed. retry = %d", i);
 			continue;
@@ -557,11 +764,11 @@  static void aw88081_startup_work(struct work_struct *work)
 		container_of(work, struct aw88081, start_work.work);
 
 	mutex_lock(&aw88081->lock);
-	aw88081_start_pa(aw88081);
+	aw8808x_start_pa(aw88081);
 	mutex_unlock(&aw88081->lock);
 }
 
-static void aw88081_start(struct aw88081 *aw88081, bool sync_start)
+static void aw8808x_start(struct aw88081 *aw88081, bool sync_start)
 {
 	if (aw88081->aw_pa->fw_status != AW88081_DEV_FW_OK)
 		return;
@@ -570,7 +777,7 @@  static void aw88081_start(struct aw88081 *aw88081, bool sync_start)
 		return;
 
 	if (sync_start == AW88081_SYNC_START)
-		aw88081_start_pa(aw88081);
+		aw8808x_start_pa(aw88081);
 	else
 		queue_delayed_work(system_wq,
 			&aw88081->start_work,
@@ -745,8 +952,8 @@  static int aw88081_profile_set(struct snd_kcontrol *kcontrol,
 	}
 
 	if (aw88081->aw_pa->status) {
-		aw88081_dev_stop(aw88081->aw_pa);
-		aw88081_start(aw88081, AW88081_SYNC_START);
+		aw8808x_stop(aw88081);
+		aw8808x_start(aw88081, AW88081_SYNC_START);
 	}
 
 	mutex_unlock(&aw88081->lock);
@@ -781,12 +988,15 @@  static int aw88081_volume_set(struct snd_kcontrol *kcontrol,
 	if (value < mc->min || value > mc->max)
 		return -EINVAL;
 
+	aw88083_i2c_wen(aw88081, true);
+
 	if (vol_desc->ctl_volume != value) {
 		vol_desc->ctl_volume = value;
 		aw88081_dev_set_volume(aw88081->aw_pa, vol_desc->ctl_volume);
 		return 1;
 	}
 
+	aw88083_i2c_wen(aw88081, false);
 	return 0;
 }
 
@@ -860,13 +1070,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);
 		return ret;
 	}
-	if (chip_id != AW88081_CHIP_ID) {
+
+	switch (chip_id) {
+	case AW88081_CHIP_ID:
+		dev_dbg(&i2c->dev, "chip id = %x\n", chip_id);
+		break;
+	case AW88083_CHIP_ID:
+		dev_dbg(&i2c->dev, "chip id = %x\n", chip_id);
+		break;
+	default:
 		dev_err(&i2c->dev, "unsupported device");
 		return -ENXIO;
 	}
 
-	dev_dbg(&i2c->dev, "chip id = %x\n", chip_id);
-
 	aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL);
 	if (!aw_dev)
 		return -ENOMEM;
@@ -875,7 +1091,7 @@  static int aw88081_init(struct aw88081 *aw88081, struct i2c_client *i2c, struct
 	aw_dev->i2c = i2c;
 	aw_dev->regmap = regmap;
 	aw_dev->dev = &i2c->dev;
-	aw_dev->chip_id = AW88081_CHIP_ID;
+	aw_dev->chip_id = chip_id;
 	aw_dev->acf = NULL;
 	aw_dev->prof_info.prof_desc = NULL;
 	aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID;
@@ -912,21 +1128,8 @@  static int aw88081_dev_init(struct aw88081 *aw88081, struct aw_container *aw_cfg
 		return ret;
 	}
 
-	aw88081_dev_clear_int_status(aw_dev);
-
-	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);
+	aw_dev->status = AW88081_DEV_PW_ON;
+	aw8808x_stop(aw88081);
 
 	return 0;
 }
@@ -974,10 +1177,10 @@  static int aw88081_playback_event(struct snd_soc_dapm_widget *w,
 	mutex_lock(&aw88081->lock);
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		aw88081_start(aw88081, AW88081_ASYNC_START);
+		aw8808x_start(aw88081, AW88081_ASYNC_START);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		aw88081_dev_stop(aw88081->aw_pa);
+		aw8808x_stop(aw88081);
 		break;
 	default:
 		break;
@@ -1036,8 +1239,17 @@  static const struct snd_soc_component_driver soc_codec_dev_aw88081 = {
 	.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)
 {
+	const struct regmap_config *regmap_config;
+	const struct i2c_device_id *id;
 	struct aw88081 *aw88081;
 	int ret;
 
@@ -1049,11 +1261,25 @@  static int aw88081_i2c_probe(struct i2c_client *i2c)
 	if (!aw88081)
 		return -ENOMEM;
 
+	id = i2c_match_id(aw88081_i2c_id, i2c);
+	aw88081->devtype = id->driver_data;
+
 	mutex_init(&aw88081->lock);
 
 	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))
 		return dev_err_probe(&i2c->dev, PTR_ERR(aw88081->regmap),
 						"failed to init regmap\n");
@@ -1068,12 +1294,6 @@  static int aw88081_i2c_probe(struct i2c_client *i2c)
 			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 = {
 	.driver = {
 		.name = AW88081_I2C_NAME,
diff --git a/sound/soc/codecs/aw88081.h b/sound/soc/codecs/aw88081.h
index b4bf7288021a..c4679476f524 100644
--- a/sound/soc/codecs/aw88081.h
+++ b/sound/soc/codecs/aw88081.h
@@ -231,6 +231,49 @@ 
 #define AW88081_CCO_MUX_BYPASS_VALUE	\
 	(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_WORK_DELAY_MS	(0)