xref: /linux/sound/soc/codecs/aw88166.c (revision a9e6060bb2a6cae6d43a98ec0794844ad01273d3)
194e412c2SWeidong Wang // SPDX-License-Identifier: GPL-2.0-only
294e412c2SWeidong Wang //
394e412c2SWeidong Wang // aw88166.c --  ALSA SoC AW88166 codec support
494e412c2SWeidong Wang //
594e412c2SWeidong Wang // Copyright (c) 2025 AWINIC Technology CO., LTD
694e412c2SWeidong Wang //
794e412c2SWeidong Wang // Author: Weidong Wang <wangweidong.a@awinic.com>
894e412c2SWeidong Wang //
994e412c2SWeidong Wang 
1094e412c2SWeidong Wang #include <linux/crc32.h>
1194e412c2SWeidong Wang #include <linux/firmware.h>
1294e412c2SWeidong Wang #include <linux/gpio/consumer.h>
1394e412c2SWeidong Wang #include <linux/i2c.h>
14*84dea31dSThorsten Blum #include <linux/minmax.h>
1594e412c2SWeidong Wang #include <linux/regmap.h>
1694e412c2SWeidong Wang #include <sound/soc.h>
1794e412c2SWeidong Wang #include "aw88166.h"
1894e412c2SWeidong Wang #include "aw88395/aw88395_device.h"
1994e412c2SWeidong Wang 
2094e412c2SWeidong Wang struct aw88166 {
2194e412c2SWeidong Wang 	struct aw_device *aw_pa;
2294e412c2SWeidong Wang 	struct mutex lock;
2394e412c2SWeidong Wang 	struct gpio_desc *reset_gpio;
2494e412c2SWeidong Wang 	struct delayed_work start_work;
2594e412c2SWeidong Wang 	struct regmap *regmap;
2694e412c2SWeidong Wang 	struct aw_container *aw_cfg;
2794e412c2SWeidong Wang 
2894e412c2SWeidong Wang 	unsigned int check_val;
2994e412c2SWeidong Wang 	unsigned int crc_init_val;
3094e412c2SWeidong Wang 	unsigned int vcalb_init_val;
3194e412c2SWeidong Wang 	unsigned int re_init_val;
3294e412c2SWeidong Wang 	unsigned int dither_st;
3394e412c2SWeidong Wang 	bool phase_sync;
3494e412c2SWeidong Wang };
3594e412c2SWeidong Wang 
3694e412c2SWeidong Wang static const struct regmap_config aw88166_remap_config = {
3794e412c2SWeidong Wang 	.val_bits = 16,
3894e412c2SWeidong Wang 	.reg_bits = 8,
3994e412c2SWeidong Wang 	.max_register = AW88166_REG_MAX,
4094e412c2SWeidong Wang 	.reg_format_endian = REGMAP_ENDIAN_LITTLE,
4194e412c2SWeidong Wang 	.val_format_endian = REGMAP_ENDIAN_BIG,
4294e412c2SWeidong Wang };
4394e412c2SWeidong Wang 
aw_dev_dsp_write_16bit(struct aw_device * aw_dev,unsigned short dsp_addr,unsigned int dsp_data)4494e412c2SWeidong Wang static int aw_dev_dsp_write_16bit(struct aw_device *aw_dev,
4594e412c2SWeidong Wang 		unsigned short dsp_addr, unsigned int dsp_data)
4694e412c2SWeidong Wang {
4794e412c2SWeidong Wang 	int ret;
4894e412c2SWeidong Wang 
4994e412c2SWeidong Wang 	ret = regmap_write(aw_dev->regmap, AW88166_DSPMADD_REG, dsp_addr);
5094e412c2SWeidong Wang 	if (ret) {
5194e412c2SWeidong Wang 		dev_err(aw_dev->dev, "%s write addr error, ret=%d", __func__, ret);
5294e412c2SWeidong Wang 		return ret;
5394e412c2SWeidong Wang 	}
5494e412c2SWeidong Wang 
5594e412c2SWeidong Wang 	ret = regmap_write(aw_dev->regmap, AW88166_DSPMDAT_REG, (u16)dsp_data);
5694e412c2SWeidong Wang 	if (ret) {
5794e412c2SWeidong Wang 		dev_err(aw_dev->dev, "%s write data error, ret=%d", __func__, ret);
5894e412c2SWeidong Wang 		return ret;
5994e412c2SWeidong Wang 	}
6094e412c2SWeidong Wang 
6194e412c2SWeidong Wang 	return 0;
6294e412c2SWeidong Wang }
6394e412c2SWeidong Wang 
aw_dev_dsp_read_16bit(struct aw_device * aw_dev,unsigned short dsp_addr,unsigned int * dsp_data)6494e412c2SWeidong Wang static int aw_dev_dsp_read_16bit(struct aw_device *aw_dev,
6594e412c2SWeidong Wang 		unsigned short dsp_addr, unsigned int *dsp_data)
6694e412c2SWeidong Wang {
6794e412c2SWeidong Wang 	unsigned int temp_data;
6894e412c2SWeidong Wang 	int ret;
6994e412c2SWeidong Wang 
7094e412c2SWeidong Wang 	ret = regmap_write(aw_dev->regmap, AW88166_DSPMADD_REG, dsp_addr);
7194e412c2SWeidong Wang 	if (ret) {
7294e412c2SWeidong Wang 		dev_err(aw_dev->dev, "%s write error, ret=%d", __func__, ret);
7394e412c2SWeidong Wang 		return ret;
7494e412c2SWeidong Wang 	}
7594e412c2SWeidong Wang 
7694e412c2SWeidong Wang 	ret = regmap_read(aw_dev->regmap, AW88166_DSPMDAT_REG, &temp_data);
7794e412c2SWeidong Wang 	if (ret) {
7894e412c2SWeidong Wang 		dev_err(aw_dev->dev, "%s read error, ret=%d", __func__, ret);
7994e412c2SWeidong Wang 		return ret;
8094e412c2SWeidong Wang 	}
8194e412c2SWeidong Wang 	*dsp_data = temp_data;
8294e412c2SWeidong Wang 
8394e412c2SWeidong Wang 	return 0;
8494e412c2SWeidong Wang }
8594e412c2SWeidong Wang 
aw_dev_dsp_read_32bit(struct aw_device * aw_dev,unsigned short dsp_addr,unsigned int * dsp_data)8694e412c2SWeidong Wang static int aw_dev_dsp_read_32bit(struct aw_device *aw_dev,
8794e412c2SWeidong Wang 		unsigned short dsp_addr, unsigned int *dsp_data)
8894e412c2SWeidong Wang {
8994e412c2SWeidong Wang 	unsigned int temp_data;
9094e412c2SWeidong Wang 	int ret;
9194e412c2SWeidong Wang 
9294e412c2SWeidong Wang 	ret = regmap_write(aw_dev->regmap, AW88166_DSPMADD_REG, dsp_addr);
9394e412c2SWeidong Wang 	if (ret) {
9494e412c2SWeidong Wang 		dev_err(aw_dev->dev, "%s write error, ret=%d", __func__, ret);
9594e412c2SWeidong Wang 		return ret;
9694e412c2SWeidong Wang 	}
9794e412c2SWeidong Wang 
9894e412c2SWeidong Wang 	ret = regmap_read(aw_dev->regmap, AW88166_DSPMDAT_REG, &temp_data);
9994e412c2SWeidong Wang 	if (ret) {
10094e412c2SWeidong Wang 		dev_err(aw_dev->dev, "%s read error, ret=%d", __func__, ret);
10194e412c2SWeidong Wang 		return ret;
10294e412c2SWeidong Wang 	}
10394e412c2SWeidong Wang 	*dsp_data = temp_data;
10494e412c2SWeidong Wang 
10594e412c2SWeidong Wang 	ret = regmap_read(aw_dev->regmap, AW88166_DSPMDAT_REG, &temp_data);
10694e412c2SWeidong Wang 	if (ret) {
10794e412c2SWeidong Wang 		dev_err(aw_dev->dev, "%s read error, ret=%d", __func__, ret);
10894e412c2SWeidong Wang 		return ret;
10994e412c2SWeidong Wang 	}
11094e412c2SWeidong Wang 	*dsp_data |= (temp_data << 16);
11194e412c2SWeidong Wang 
11294e412c2SWeidong Wang 	return 0;
11394e412c2SWeidong Wang }
11494e412c2SWeidong Wang 
aw_dev_dsp_read(struct aw_device * aw_dev,unsigned short dsp_addr,unsigned int * dsp_data,unsigned char data_type)11594e412c2SWeidong Wang static int aw_dev_dsp_read(struct aw_device *aw_dev,
11694e412c2SWeidong Wang 		unsigned short dsp_addr, unsigned int *dsp_data, unsigned char data_type)
11794e412c2SWeidong Wang {
11894e412c2SWeidong Wang 	u32 reg_value;
11994e412c2SWeidong Wang 	int ret;
12094e412c2SWeidong Wang 
12194e412c2SWeidong Wang 	mutex_lock(&aw_dev->dsp_lock);
12294e412c2SWeidong Wang 	switch (data_type) {
12394e412c2SWeidong Wang 	case AW88166_DSP_16_DATA:
12494e412c2SWeidong Wang 		ret = aw_dev_dsp_read_16bit(aw_dev, dsp_addr, dsp_data);
12594e412c2SWeidong Wang 		if (ret)
12694e412c2SWeidong Wang 			dev_err(aw_dev->dev, "read dsp_addr[0x%x] 16-bit failed", (u32)dsp_addr);
12794e412c2SWeidong Wang 		break;
12894e412c2SWeidong Wang 	case AW88166_DSP_32_DATA:
12994e412c2SWeidong Wang 		ret = aw_dev_dsp_read_32bit(aw_dev, dsp_addr, dsp_data);
13094e412c2SWeidong Wang 		if (ret)
13194e412c2SWeidong Wang 			dev_err(aw_dev->dev, "read dsp_addr[0x%x] 32-bit failed", (u32)dsp_addr);
13294e412c2SWeidong Wang 		break;
13394e412c2SWeidong Wang 	default:
13494e412c2SWeidong Wang 		dev_err(aw_dev->dev, "data type[%d] unsupported", data_type);
13594e412c2SWeidong Wang 		ret = -EINVAL;
13694e412c2SWeidong Wang 		break;
13794e412c2SWeidong Wang 	}
13894e412c2SWeidong Wang 
13994e412c2SWeidong Wang 	/* clear dsp chip select state */
14094e412c2SWeidong Wang 	if (regmap_read(aw_dev->regmap, AW88166_ID_REG, &reg_value))
14194e412c2SWeidong Wang 		dev_err(aw_dev->dev, "%s fail to clear chip state. ret=%d\n", __func__, ret);
14294e412c2SWeidong Wang 	mutex_unlock(&aw_dev->dsp_lock);
14394e412c2SWeidong Wang 
14494e412c2SWeidong Wang 	return ret;
14594e412c2SWeidong Wang }
14694e412c2SWeidong Wang 
aw_dev_pwd(struct aw_device * aw_dev,bool pwd)14794e412c2SWeidong Wang static void aw_dev_pwd(struct aw_device *aw_dev, bool pwd)
14894e412c2SWeidong Wang {
14994e412c2SWeidong Wang 	int ret;
15094e412c2SWeidong Wang 
15194e412c2SWeidong Wang 	if (pwd)
15294e412c2SWeidong Wang 		ret = regmap_update_bits(aw_dev->regmap, AW88166_SYSCTRL_REG,
15394e412c2SWeidong Wang 				~AW88166_PWDN_MASK, AW88166_PWDN_POWER_DOWN_VALUE);
15494e412c2SWeidong Wang 	else
15594e412c2SWeidong Wang 		ret = regmap_update_bits(aw_dev->regmap, AW88166_SYSCTRL_REG,
15694e412c2SWeidong Wang 				~AW88166_PWDN_MASK, AW88166_PWDN_WORKING_VALUE);
15794e412c2SWeidong Wang 
15894e412c2SWeidong Wang 	if (ret)
15994e412c2SWeidong Wang 		dev_dbg(aw_dev->dev, "%s failed", __func__);
16094e412c2SWeidong Wang }
16194e412c2SWeidong Wang 
aw_dev_get_int_status(struct aw_device * aw_dev,unsigned short * int_status)16294e412c2SWeidong Wang static void aw_dev_get_int_status(struct aw_device *aw_dev, unsigned short *int_status)
16394e412c2SWeidong Wang {
16494e412c2SWeidong Wang 	unsigned int reg_val;
16594e412c2SWeidong Wang 	int ret;
16694e412c2SWeidong Wang 
16794e412c2SWeidong Wang 	ret = regmap_read(aw_dev->regmap, AW88166_SYSINT_REG, &reg_val);
16894e412c2SWeidong Wang 	if (ret)
16994e412c2SWeidong Wang 		dev_err(aw_dev->dev, "read interrupt reg fail, ret=%d", ret);
17094e412c2SWeidong Wang 	else
17194e412c2SWeidong Wang 		*int_status = reg_val;
17294e412c2SWeidong Wang 
17394e412c2SWeidong Wang 	dev_dbg(aw_dev->dev, "read interrupt reg=0x%04x", *int_status);
17494e412c2SWeidong Wang }
17594e412c2SWeidong Wang 
aw_dev_clear_int_status(struct aw_device * aw_dev)17694e412c2SWeidong Wang static void aw_dev_clear_int_status(struct aw_device *aw_dev)
17794e412c2SWeidong Wang {
17894e412c2SWeidong Wang 	u16 int_status;
17994e412c2SWeidong Wang 
18094e412c2SWeidong Wang 	/* read int status and clear */
18194e412c2SWeidong Wang 	aw_dev_get_int_status(aw_dev, &int_status);
18294e412c2SWeidong Wang 	/* make sure int status is clear */
18394e412c2SWeidong Wang 	aw_dev_get_int_status(aw_dev, &int_status);
18494e412c2SWeidong Wang 	if (int_status)
18594e412c2SWeidong Wang 		dev_dbg(aw_dev->dev, "int status(%d) is not cleaned.\n", int_status);
18694e412c2SWeidong Wang }
18794e412c2SWeidong Wang 
aw_dev_get_iis_status(struct aw_device * aw_dev)18894e412c2SWeidong Wang static int aw_dev_get_iis_status(struct aw_device *aw_dev)
18994e412c2SWeidong Wang {
19094e412c2SWeidong Wang 	unsigned int reg_val;
19194e412c2SWeidong Wang 	int ret;
19294e412c2SWeidong Wang 
19394e412c2SWeidong Wang 	ret = regmap_read(aw_dev->regmap, AW88166_SYSST_REG, &reg_val);
19494e412c2SWeidong Wang 	if (ret)
19594e412c2SWeidong Wang 		return ret;
19694e412c2SWeidong Wang 	if ((reg_val & AW88166_BIT_PLL_CHECK) != AW88166_BIT_PLL_CHECK) {
19794e412c2SWeidong Wang 		dev_err(aw_dev->dev, "check pll lock fail, reg_val:0x%04x", reg_val);
19894e412c2SWeidong Wang 		return -EINVAL;
19994e412c2SWeidong Wang 	}
20094e412c2SWeidong Wang 
20194e412c2SWeidong Wang 	return 0;
20294e412c2SWeidong Wang }
20394e412c2SWeidong Wang 
aw_dev_check_mode1_pll(struct aw_device * aw_dev)20494e412c2SWeidong Wang static int aw_dev_check_mode1_pll(struct aw_device *aw_dev)
20594e412c2SWeidong Wang {
20694e412c2SWeidong Wang 	int ret, i;
20794e412c2SWeidong Wang 
20894e412c2SWeidong Wang 	for (i = 0; i < AW88166_DEV_SYSST_CHECK_MAX; i++) {
20994e412c2SWeidong Wang 		ret = aw_dev_get_iis_status(aw_dev);
21094e412c2SWeidong Wang 		if (ret) {
21194e412c2SWeidong Wang 			dev_err(aw_dev->dev, "mode1 iis signal check error");
21294e412c2SWeidong Wang 			usleep_range(AW88166_2000_US, AW88166_2000_US + 10);
21394e412c2SWeidong Wang 		} else {
21494e412c2SWeidong Wang 			return 0;
21594e412c2SWeidong Wang 		}
21694e412c2SWeidong Wang 	}
21794e412c2SWeidong Wang 
21894e412c2SWeidong Wang 	return -EPERM;
21994e412c2SWeidong Wang }
22094e412c2SWeidong Wang 
aw_dev_check_mode2_pll(struct aw_device * aw_dev)22194e412c2SWeidong Wang static int aw_dev_check_mode2_pll(struct aw_device *aw_dev)
22294e412c2SWeidong Wang {
22394e412c2SWeidong Wang 	unsigned int reg_val;
22494e412c2SWeidong Wang 	int ret, i;
22594e412c2SWeidong Wang 
22694e412c2SWeidong Wang 	ret = regmap_read(aw_dev->regmap, AW88166_PLLCTRL2_REG, &reg_val);
22794e412c2SWeidong Wang 	if (ret)
22894e412c2SWeidong Wang 		return ret;
22994e412c2SWeidong Wang 
23094e412c2SWeidong Wang 	reg_val &= (~AW88166_CCO_MUX_MASK);
23194e412c2SWeidong Wang 	if (reg_val == AW88166_CCO_MUX_DIVIDED_VALUE) {
23294e412c2SWeidong Wang 		dev_dbg(aw_dev->dev, "CCO_MUX is already divider");
23394e412c2SWeidong Wang 		return -EPERM;
23494e412c2SWeidong Wang 	}
23594e412c2SWeidong Wang 
23694e412c2SWeidong Wang 	/* change mode2 */
23794e412c2SWeidong Wang 	ret = regmap_update_bits(aw_dev->regmap, AW88166_PLLCTRL2_REG,
23894e412c2SWeidong Wang 			~AW88166_CCO_MUX_MASK, AW88166_CCO_MUX_DIVIDED_VALUE);
23994e412c2SWeidong Wang 	if (ret)
24094e412c2SWeidong Wang 		return ret;
24194e412c2SWeidong Wang 
24294e412c2SWeidong Wang 	for (i = 0; i < AW88166_DEV_SYSST_CHECK_MAX; i++) {
24394e412c2SWeidong Wang 		ret = aw_dev_get_iis_status(aw_dev);
24494e412c2SWeidong Wang 		if (ret) {
24594e412c2SWeidong Wang 			dev_err(aw_dev->dev, "mode2 iis signal check error");
24694e412c2SWeidong Wang 			usleep_range(AW88166_2000_US, AW88166_2000_US + 10);
24794e412c2SWeidong Wang 		} else {
24894e412c2SWeidong Wang 			break;
24994e412c2SWeidong Wang 		}
25094e412c2SWeidong Wang 	}
25194e412c2SWeidong Wang 
25294e412c2SWeidong Wang 	/* change mode1 */
25394e412c2SWeidong Wang 	regmap_update_bits(aw_dev->regmap, AW88166_PLLCTRL2_REG,
25494e412c2SWeidong Wang 			~AW88166_CCO_MUX_MASK, AW88166_CCO_MUX_BYPASS_VALUE);
25594e412c2SWeidong Wang 	if (ret == 0) {
25694e412c2SWeidong Wang 		usleep_range(AW88166_2000_US, AW88166_2000_US + 10);
25794e412c2SWeidong Wang 		for (i = 0; i < AW88166_DEV_SYSST_CHECK_MAX; i++) {
25894e412c2SWeidong Wang 			ret = aw_dev_get_iis_status(aw_dev);
25994e412c2SWeidong Wang 			if (ret) {
26094e412c2SWeidong Wang 				dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error");
26194e412c2SWeidong Wang 				usleep_range(AW88166_2000_US, AW88166_2000_US + 10);
26294e412c2SWeidong Wang 			} else {
26394e412c2SWeidong Wang 				break;
26494e412c2SWeidong Wang 			}
26594e412c2SWeidong Wang 		}
26694e412c2SWeidong Wang 	}
26794e412c2SWeidong Wang 
26894e412c2SWeidong Wang 	return ret;
26994e412c2SWeidong Wang }
27094e412c2SWeidong Wang 
aw_dev_check_syspll(struct aw_device * aw_dev)27194e412c2SWeidong Wang static int aw_dev_check_syspll(struct aw_device *aw_dev)
27294e412c2SWeidong Wang {
27394e412c2SWeidong Wang 	int ret;
27494e412c2SWeidong Wang 
27594e412c2SWeidong Wang 	ret = aw_dev_check_mode1_pll(aw_dev);
27694e412c2SWeidong Wang 	if (ret) {
27794e412c2SWeidong Wang 		dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check");
27894e412c2SWeidong Wang 		ret = aw_dev_check_mode2_pll(aw_dev);
27994e412c2SWeidong Wang 		if (ret) {
28094e412c2SWeidong Wang 			dev_err(aw_dev->dev, "mode2 check iis failed");
28194e412c2SWeidong Wang 			return ret;
28294e412c2SWeidong Wang 		}
28394e412c2SWeidong Wang 	}
28494e412c2SWeidong Wang 
28594e412c2SWeidong Wang 	return 0;
28694e412c2SWeidong Wang }
28794e412c2SWeidong Wang 
aw_dev_check_sysst(struct aw_device * aw_dev)28894e412c2SWeidong Wang static int aw_dev_check_sysst(struct aw_device *aw_dev)
28994e412c2SWeidong Wang {
29094e412c2SWeidong Wang 	unsigned int check_val;
29194e412c2SWeidong Wang 	unsigned int reg_val;
29294e412c2SWeidong Wang 	int ret, i;
29394e412c2SWeidong Wang 
29494e412c2SWeidong Wang 	ret = regmap_read(aw_dev->regmap, AW88166_PWMCTRL3_REG, &reg_val);
29594e412c2SWeidong Wang 	if (ret)
29694e412c2SWeidong Wang 		return ret;
29794e412c2SWeidong Wang 
29894e412c2SWeidong Wang 	if (reg_val & (~AW88166_NOISE_GATE_EN_MASK))
29994e412c2SWeidong Wang 		check_val = AW88166_BIT_SYSST_NOSWS_CHECK;
30094e412c2SWeidong Wang 	else
30194e412c2SWeidong Wang 		check_val = AW88166_BIT_SYSST_SWS_CHECK;
30294e412c2SWeidong Wang 
30394e412c2SWeidong Wang 	for (i = 0; i < AW88166_DEV_SYSST_CHECK_MAX; i++) {
30494e412c2SWeidong Wang 		ret = regmap_read(aw_dev->regmap, AW88166_SYSST_REG, &reg_val);
30594e412c2SWeidong Wang 		if (ret)
30694e412c2SWeidong Wang 			return ret;
30794e412c2SWeidong Wang 
30894e412c2SWeidong Wang 		if ((reg_val & (~AW88166_BIT_SYSST_CHECK_MASK) & check_val) != check_val) {
30994e412c2SWeidong Wang 			dev_err(aw_dev->dev, "check sysst fail, cnt=%d, reg_val=0x%04x, check:0x%x",
31094e412c2SWeidong Wang 				i, reg_val, AW88166_BIT_SYSST_NOSWS_CHECK);
31194e412c2SWeidong Wang 			usleep_range(AW88166_2000_US, AW88166_2000_US + 10);
31294e412c2SWeidong Wang 		} else {
31394e412c2SWeidong Wang 			return 0;
31494e412c2SWeidong Wang 		}
31594e412c2SWeidong Wang 	}
31694e412c2SWeidong Wang 
31794e412c2SWeidong Wang 	return -EPERM;
31894e412c2SWeidong Wang }
31994e412c2SWeidong Wang 
aw_dev_amppd(struct aw_device * aw_dev,bool amppd)32094e412c2SWeidong Wang static void aw_dev_amppd(struct aw_device *aw_dev, bool amppd)
32194e412c2SWeidong Wang {
32294e412c2SWeidong Wang 	int ret;
32394e412c2SWeidong Wang 
32494e412c2SWeidong Wang 	if (amppd)
32594e412c2SWeidong Wang 		ret = regmap_update_bits(aw_dev->regmap, AW88166_SYSCTRL_REG,
32694e412c2SWeidong Wang 				~AW88166_AMPPD_MASK, AW88166_AMPPD_POWER_DOWN_VALUE);
32794e412c2SWeidong Wang 	else
32894e412c2SWeidong Wang 		ret = regmap_update_bits(aw_dev->regmap, AW88166_SYSCTRL_REG,
32994e412c2SWeidong Wang 				~AW88166_AMPPD_MASK, AW88166_AMPPD_WORKING_VALUE);
33094e412c2SWeidong Wang 
33194e412c2SWeidong Wang 	if (ret)
33294e412c2SWeidong Wang 		dev_dbg(aw_dev->dev, "%s failed", __func__);
33394e412c2SWeidong Wang }
33494e412c2SWeidong Wang 
aw_dev_dsp_enable(struct aw_device * aw_dev,bool is_enable)33594e412c2SWeidong Wang static void aw_dev_dsp_enable(struct aw_device *aw_dev, bool is_enable)
33694e412c2SWeidong Wang {
33794e412c2SWeidong Wang 	int ret;
33894e412c2SWeidong Wang 
33994e412c2SWeidong Wang 	if (is_enable)
34094e412c2SWeidong Wang 		ret = regmap_update_bits(aw_dev->regmap, AW88166_SYSCTRL_REG,
34194e412c2SWeidong Wang 					~AW88166_DSPBY_MASK, AW88166_DSPBY_WORKING_VALUE);
34294e412c2SWeidong Wang 	else
34394e412c2SWeidong Wang 		ret = regmap_update_bits(aw_dev->regmap, AW88166_SYSCTRL_REG,
34494e412c2SWeidong Wang 					~AW88166_DSPBY_MASK, AW88166_DSPBY_BYPASS_VALUE);
34594e412c2SWeidong Wang 
34694e412c2SWeidong Wang 	if (ret)
34794e412c2SWeidong Wang 		dev_dbg(aw_dev->dev, "%s failed\n", __func__);
34894e412c2SWeidong Wang }
34994e412c2SWeidong Wang 
aw88166_dev_get_icalk(struct aw88166 * aw88166,int16_t * icalk)35094e412c2SWeidong Wang static int aw88166_dev_get_icalk(struct aw88166 *aw88166, int16_t *icalk)
35194e412c2SWeidong Wang {
35294e412c2SWeidong Wang 	struct aw_device *aw_dev = aw88166->aw_pa;
35394e412c2SWeidong Wang 	unsigned int efrm_reg_val, efrl_reg_val;
35494e412c2SWeidong Wang 	uint16_t ef_isn_geslp, ef_isn_h5bits;
35594e412c2SWeidong Wang 	uint16_t icalk_val;
35694e412c2SWeidong Wang 	int ret;
35794e412c2SWeidong Wang 
35894e412c2SWeidong Wang 	ret = regmap_read(aw_dev->regmap, AW88166_EFRM2_REG, &efrm_reg_val);
35994e412c2SWeidong Wang 	if (ret)
36094e412c2SWeidong Wang 		return ret;
36194e412c2SWeidong Wang 
36294e412c2SWeidong Wang 	ef_isn_geslp = (efrm_reg_val & (~AW88166_EF_ISN_GESLP_MASK)) >>
36394e412c2SWeidong Wang 						AW88166_EF_ISN_GESLP_SHIFT;
36494e412c2SWeidong Wang 
36594e412c2SWeidong Wang 	ret = regmap_read(aw_dev->regmap, AW88166_EFRL_REG, &efrl_reg_val);
36694e412c2SWeidong Wang 	if (ret)
36794e412c2SWeidong Wang 		return ret;
36894e412c2SWeidong Wang 
36994e412c2SWeidong Wang 	ef_isn_h5bits = (efrl_reg_val & (~AW88166_EF_ISN_H5BITS_MASK)) >>
37094e412c2SWeidong Wang 						AW88166_EF_ISN_H5BITS_SHIFT;
37194e412c2SWeidong Wang 
37294e412c2SWeidong Wang 	if (aw88166->check_val == AW_EF_AND_CHECK)
37394e412c2SWeidong Wang 		icalk_val = ef_isn_geslp & (ef_isn_h5bits | AW88166_EF_ISN_H5BITS_SIGN_MASK);
37494e412c2SWeidong Wang 	else
37594e412c2SWeidong Wang 		icalk_val = ef_isn_geslp | (ef_isn_h5bits & (~AW88166_EF_ISN_H5BITS_SIGN_MASK));
37694e412c2SWeidong Wang 
37794e412c2SWeidong Wang 	if (icalk_val & (~AW88166_ICALK_SIGN_MASK))
37894e412c2SWeidong Wang 		icalk_val = icalk_val | AW88166_ICALK_NEG_MASK;
37994e412c2SWeidong Wang 	*icalk = (int16_t)icalk_val;
38094e412c2SWeidong Wang 
38194e412c2SWeidong Wang 	return 0;
38294e412c2SWeidong Wang }
38394e412c2SWeidong Wang 
aw88166_dev_get_vcalk(struct aw88166 * aw88166,int16_t * vcalk)38494e412c2SWeidong Wang static int aw88166_dev_get_vcalk(struct aw88166 *aw88166, int16_t *vcalk)
38594e412c2SWeidong Wang {
38694e412c2SWeidong Wang 	struct aw_device *aw_dev = aw88166->aw_pa;
38794e412c2SWeidong Wang 	unsigned int efrm_reg_val, efrl_reg_val;
38894e412c2SWeidong Wang 	uint16_t ef_vsn_geslp, ef_vsn_h3bits;
38994e412c2SWeidong Wang 	uint16_t vcalk_val;
39094e412c2SWeidong Wang 	int ret;
39194e412c2SWeidong Wang 
39294e412c2SWeidong Wang 	ret = regmap_read(aw_dev->regmap, AW88166_EFRM2_REG, &efrm_reg_val);
39394e412c2SWeidong Wang 	if (ret)
39494e412c2SWeidong Wang 		return ret;
39594e412c2SWeidong Wang 
39694e412c2SWeidong Wang 	ef_vsn_geslp = (efrm_reg_val & (~AW88166_EF_VSN_GESLP_MASK)) >>
39794e412c2SWeidong Wang 					AW88166_EF_VSN_GESLP_SHIFT;
39894e412c2SWeidong Wang 
39994e412c2SWeidong Wang 	ret = regmap_read(aw_dev->regmap, AW88166_EFRL_REG, &efrl_reg_val);
40094e412c2SWeidong Wang 	if (ret)
40194e412c2SWeidong Wang 		return ret;
40294e412c2SWeidong Wang 
40394e412c2SWeidong Wang 	ef_vsn_h3bits = (efrl_reg_val & (~AW88166_EF_VSN_H3BITS_MASK)) >>
40494e412c2SWeidong Wang 					AW88166_EF_VSN_H3BITS_SHIFT;
40594e412c2SWeidong Wang 
40694e412c2SWeidong Wang 	if (aw88166->check_val == AW_EF_AND_CHECK)
40794e412c2SWeidong Wang 		vcalk_val = ef_vsn_geslp & (ef_vsn_h3bits | AW88166_EF_VSN_H3BITS_SIGN_MASK);
40894e412c2SWeidong Wang 	else
40994e412c2SWeidong Wang 		vcalk_val = ef_vsn_geslp | (ef_vsn_h3bits & (~AW88166_EF_VSN_H3BITS_SIGN_MASK));
41094e412c2SWeidong Wang 
41194e412c2SWeidong Wang 	if (vcalk_val & (~AW88166_VCALK_SIGN_MASK))
41294e412c2SWeidong Wang 		vcalk_val = vcalk_val | AW88166_VCALK_NEG_MASK;
41394e412c2SWeidong Wang 	*vcalk = (int16_t)vcalk_val;
41494e412c2SWeidong Wang 
41594e412c2SWeidong Wang 	return 0;
41694e412c2SWeidong Wang }
41794e412c2SWeidong Wang 
aw88166_dev_set_vcalb(struct aw88166 * aw88166)41894e412c2SWeidong Wang static int aw88166_dev_set_vcalb(struct aw88166 *aw88166)
41994e412c2SWeidong Wang {
42094e412c2SWeidong Wang 	struct aw_device *aw_dev = aw88166->aw_pa;
42194e412c2SWeidong Wang 	int32_t ical_k, vcal_k, vcalb;
42294e412c2SWeidong Wang 	int16_t icalk, vcalk;
42394e412c2SWeidong Wang 	unsigned int reg_val;
42494e412c2SWeidong Wang 	int ret;
42594e412c2SWeidong Wang 
42694e412c2SWeidong Wang 	ret = aw88166_dev_get_icalk(aw88166, &icalk);
42794e412c2SWeidong Wang 	if (ret) {
42894e412c2SWeidong Wang 		dev_err(aw_dev->dev, "get icalk failed\n");
42994e412c2SWeidong Wang 		return ret;
43094e412c2SWeidong Wang 	}
43194e412c2SWeidong Wang 	ical_k = icalk * AW88166_ICABLK_FACTOR + AW88166_CABL_BASE_VALUE;
43294e412c2SWeidong Wang 
43394e412c2SWeidong Wang 	ret = aw88166_dev_get_vcalk(aw88166, &vcalk);
43494e412c2SWeidong Wang 	if (ret) {
43594e412c2SWeidong Wang 		dev_err(aw_dev->dev, "get vbcalk failed\n");
43694e412c2SWeidong Wang 		return ret;
43794e412c2SWeidong Wang 	}
43894e412c2SWeidong Wang 	vcal_k = vcalk * AW88166_VCABLK_FACTOR + AW88166_CABL_BASE_VALUE;
43994e412c2SWeidong Wang 
44094e412c2SWeidong Wang 	vcalb = AW88166_VCALB_ACCURACY * AW88166_VSCAL_FACTOR /
44194e412c2SWeidong Wang 			AW88166_ISCAL_FACTOR * ical_k / vcal_k * aw88166->vcalb_init_val;
44294e412c2SWeidong Wang 
44394e412c2SWeidong Wang 	vcalb = vcalb >> AW88166_VCALB_ADJ_FACTOR;
44494e412c2SWeidong Wang 	reg_val = (uint32_t)vcalb;
44594e412c2SWeidong Wang 
44694e412c2SWeidong Wang 	regmap_write(aw_dev->regmap, AW88166_DSPVCALB_REG, reg_val);
44794e412c2SWeidong Wang 
44894e412c2SWeidong Wang 	return 0;
44994e412c2SWeidong Wang }
45094e412c2SWeidong Wang 
aw_dev_init_vcalb_update(struct aw88166 * aw88166,int flag)45194e412c2SWeidong Wang static int aw_dev_init_vcalb_update(struct aw88166 *aw88166, int flag)
45294e412c2SWeidong Wang {
45394e412c2SWeidong Wang 	struct aw_device *aw_dev = aw88166->aw_pa;
45494e412c2SWeidong Wang 	int ret;
45594e412c2SWeidong Wang 
45694e412c2SWeidong Wang 	switch (flag) {
45794e412c2SWeidong Wang 	case AW88166_RECOVERY_SEC_DATA:
45894e412c2SWeidong Wang 		ret = regmap_write(aw_dev->regmap, AW88166_DSPVCALB_REG, aw88166->vcalb_init_val);
45994e412c2SWeidong Wang 		break;
46094e412c2SWeidong Wang 	case AW88166_RECORD_SEC_DATA:
46194e412c2SWeidong Wang 		ret = regmap_read(aw_dev->regmap, AW88166_DSPVCALB_REG, &aw88166->vcalb_init_val);
46294e412c2SWeidong Wang 		break;
46394e412c2SWeidong Wang 	default:
46494e412c2SWeidong Wang 		dev_err(aw_dev->dev, "unsupported type:%d\n", flag);
46594e412c2SWeidong Wang 		ret = -EINVAL;
46694e412c2SWeidong Wang 		break;
46794e412c2SWeidong Wang 	}
46894e412c2SWeidong Wang 
46994e412c2SWeidong Wang 	return ret;
47094e412c2SWeidong Wang }
47194e412c2SWeidong Wang 
aw_dev_init_re_update(struct aw88166 * aw88166,int flag)47294e412c2SWeidong Wang static int aw_dev_init_re_update(struct aw88166 *aw88166, int flag)
47394e412c2SWeidong Wang {
47494e412c2SWeidong Wang 	struct aw_device *aw_dev = aw88166->aw_pa;
47594e412c2SWeidong Wang 	unsigned int re_temp_h, re_temp_l;
47694e412c2SWeidong Wang 	int ret;
47794e412c2SWeidong Wang 
47894e412c2SWeidong Wang 	switch (flag) {
47994e412c2SWeidong Wang 	case AW88166_RECOVERY_SEC_DATA:
48094e412c2SWeidong Wang 		ret = regmap_write(aw_dev->regmap, AW88166_ACR1_REG, aw88166->re_init_val >> 16);
48194e412c2SWeidong Wang 		if (ret)
48294e412c2SWeidong Wang 			return ret;
48394e412c2SWeidong Wang 		ret = regmap_write(aw_dev->regmap, AW88166_ACR2_REG,
48494e412c2SWeidong Wang 						(uint16_t)aw88166->re_init_val);
48594e412c2SWeidong Wang 		if (ret)
48694e412c2SWeidong Wang 			return ret;
48794e412c2SWeidong Wang 		break;
48894e412c2SWeidong Wang 	case AW88166_RECORD_SEC_DATA:
48994e412c2SWeidong Wang 		ret = regmap_read(aw_dev->regmap, AW88166_ACR1_REG, &re_temp_h);
49094e412c2SWeidong Wang 		if (ret)
49194e412c2SWeidong Wang 			return ret;
49294e412c2SWeidong Wang 		ret = regmap_read(aw_dev->regmap, AW88166_ACR2_REG, &re_temp_l);
49394e412c2SWeidong Wang 		if (ret)
49494e412c2SWeidong Wang 			return ret;
49594e412c2SWeidong Wang 		aw88166->re_init_val = (re_temp_h << 16) + re_temp_l;
49694e412c2SWeidong Wang 		break;
49794e412c2SWeidong Wang 	default:
49894e412c2SWeidong Wang 		dev_err(aw_dev->dev, "unsupported type:%d\n", flag);
49994e412c2SWeidong Wang 		ret = -EINVAL;
50094e412c2SWeidong Wang 		break;
50194e412c2SWeidong Wang 	}
50294e412c2SWeidong Wang 
50394e412c2SWeidong Wang 	return ret;
50494e412c2SWeidong Wang }
50594e412c2SWeidong Wang 
aw_dev_backup_sec_record(struct aw88166 * aw88166)50694e412c2SWeidong Wang static void aw_dev_backup_sec_record(struct aw88166 *aw88166)
50794e412c2SWeidong Wang {
50894e412c2SWeidong Wang 	aw_dev_init_vcalb_update(aw88166, AW88166_RECORD_SEC_DATA);
50994e412c2SWeidong Wang 	aw_dev_init_re_update(aw88166, AW88166_RECOVERY_SEC_DATA);
51094e412c2SWeidong Wang }
51194e412c2SWeidong Wang 
aw_dev_backup_sec_recovery(struct aw88166 * aw88166)51294e412c2SWeidong Wang static void aw_dev_backup_sec_recovery(struct aw88166 *aw88166)
51394e412c2SWeidong Wang {
51494e412c2SWeidong Wang 	aw_dev_init_vcalb_update(aw88166, AW88166_RECOVERY_SEC_DATA);
51594e412c2SWeidong Wang 	aw_dev_init_re_update(aw88166, AW88166_RECOVERY_SEC_DATA);
51694e412c2SWeidong Wang }
51794e412c2SWeidong Wang 
aw_dev_update_cali_re(struct aw_cali_desc * cali_desc)51894e412c2SWeidong Wang static int aw_dev_update_cali_re(struct aw_cali_desc *cali_desc)
51994e412c2SWeidong Wang {
52094e412c2SWeidong Wang 	struct aw_device *aw_dev =
52194e412c2SWeidong Wang 		container_of(cali_desc, struct aw_device, cali_desc);
52294e412c2SWeidong Wang 	uint16_t re_lbits, re_hbits;
52394e412c2SWeidong Wang 	u32 cali_re;
52494e412c2SWeidong Wang 	int ret;
52594e412c2SWeidong Wang 
52694e412c2SWeidong Wang 	if ((aw_dev->cali_desc.cali_re >= AW88166_CALI_RE_MAX) ||
52794e412c2SWeidong Wang 			(aw_dev->cali_desc.cali_re <= AW88166_CALI_RE_MIN))
52894e412c2SWeidong Wang 		return -EINVAL;
52994e412c2SWeidong Wang 
53094e412c2SWeidong Wang 	cali_re = AW88166_SHOW_RE_TO_DSP_RE((aw_dev->cali_desc.cali_re +
53194e412c2SWeidong Wang 				aw_dev->cali_desc.ra), AW88166_DSP_RE_SHIFT);
53294e412c2SWeidong Wang 
53394e412c2SWeidong Wang 	re_hbits = (cali_re & (~AW88166_CALI_RE_HBITS_MASK)) >> AW88166_CALI_RE_HBITS_SHIFT;
53494e412c2SWeidong Wang 	re_lbits = (cali_re & (~AW88166_CALI_RE_LBITS_MASK)) >> AW88166_CALI_RE_LBITS_SHIFT;
53594e412c2SWeidong Wang 
53694e412c2SWeidong Wang 	ret = regmap_write(aw_dev->regmap, AW88166_ACR1_REG, re_hbits);
53794e412c2SWeidong Wang 	if (ret) {
53894e412c2SWeidong Wang 		dev_err(aw_dev->dev, "set cali re error");
53994e412c2SWeidong Wang 		return ret;
54094e412c2SWeidong Wang 	}
54194e412c2SWeidong Wang 
54294e412c2SWeidong Wang 	ret = regmap_write(aw_dev->regmap, AW88166_ACR2_REG, re_lbits);
54394e412c2SWeidong Wang 	if (ret)
54494e412c2SWeidong Wang 		dev_err(aw_dev->dev, "set cali re error");
54594e412c2SWeidong Wang 
54694e412c2SWeidong Wang 	return ret;
54794e412c2SWeidong Wang }
54894e412c2SWeidong Wang 
aw_dev_fw_crc_check(struct aw_device * aw_dev)54994e412c2SWeidong Wang static int aw_dev_fw_crc_check(struct aw_device *aw_dev)
55094e412c2SWeidong Wang {
55194e412c2SWeidong Wang 	uint16_t check_val, fw_len_val;
55294e412c2SWeidong Wang 	unsigned int reg_val;
55394e412c2SWeidong Wang 	int ret;
55494e412c2SWeidong Wang 
55594e412c2SWeidong Wang 	/* calculate fw_end_addr */
55694e412c2SWeidong Wang 	fw_len_val = ((aw_dev->dsp_fw_len / AW_FW_ADDR_LEN) - 1) + AW88166_CRC_FW_BASE_ADDR;
55794e412c2SWeidong Wang 
55894e412c2SWeidong Wang 	/* write fw_end_addr to crc_end_addr */
55994e412c2SWeidong Wang 	ret = regmap_update_bits(aw_dev->regmap, AW88166_CRCCTRL_REG,
56094e412c2SWeidong Wang 					~AW88166_CRC_END_ADDR_MASK, fw_len_val);
56194e412c2SWeidong Wang 	if (ret)
56294e412c2SWeidong Wang 		return ret;
56394e412c2SWeidong Wang 	/* enable fw crc check */
56494e412c2SWeidong Wang 	ret = regmap_update_bits(aw_dev->regmap, AW88166_CRCCTRL_REG,
56594e412c2SWeidong Wang 		~AW88166_CRC_CODE_EN_MASK, AW88166_CRC_CODE_EN_ENABLE_VALUE);
56694e412c2SWeidong Wang 
56794e412c2SWeidong Wang 	usleep_range(AW88166_2000_US, AW88166_2000_US + 10);
56894e412c2SWeidong Wang 
56994e412c2SWeidong Wang 	/* read crc check result */
57094e412c2SWeidong Wang 	regmap_read(aw_dev->regmap, AW88166_HAGCST_REG, &reg_val);
57194e412c2SWeidong Wang 	if (ret)
57294e412c2SWeidong Wang 		return ret;
57394e412c2SWeidong Wang 
57494e412c2SWeidong Wang 	check_val = (reg_val & (~AW88166_CRC_CHECK_BITS_MASK)) >> AW88166_CRC_CHECK_START_BIT;
57594e412c2SWeidong Wang 
57694e412c2SWeidong Wang 	/* disable fw crc check */
57794e412c2SWeidong Wang 	ret = regmap_update_bits(aw_dev->regmap, AW88166_CRCCTRL_REG,
57894e412c2SWeidong Wang 		~AW88166_CRC_CODE_EN_MASK, AW88166_CRC_CODE_EN_DISABLE_VALUE);
57994e412c2SWeidong Wang 	if (ret)
58094e412c2SWeidong Wang 		return ret;
58194e412c2SWeidong Wang 
58294e412c2SWeidong Wang 	if (check_val != AW88166_CRC_CHECK_PASS_VAL) {
58394e412c2SWeidong Wang 		dev_err(aw_dev->dev, "%s failed, check_val 0x%x != 0x%x\n",
58494e412c2SWeidong Wang 				__func__, check_val, AW88166_CRC_CHECK_PASS_VAL);
58594e412c2SWeidong Wang 		ret = -EINVAL;
58694e412c2SWeidong Wang 	}
58794e412c2SWeidong Wang 
58894e412c2SWeidong Wang 	return ret;
58994e412c2SWeidong Wang }
59094e412c2SWeidong Wang 
aw_dev_cfg_crc_check(struct aw_device * aw_dev)59194e412c2SWeidong Wang static int aw_dev_cfg_crc_check(struct aw_device *aw_dev)
59294e412c2SWeidong Wang {
59394e412c2SWeidong Wang 	uint16_t check_val, cfg_len_val;
59494e412c2SWeidong Wang 	unsigned int reg_val;
59594e412c2SWeidong Wang 	int ret;
59694e412c2SWeidong Wang 
59794e412c2SWeidong Wang 	/* calculate cfg end addr */
59894e412c2SWeidong Wang 	cfg_len_val = ((aw_dev->dsp_cfg_len / AW_FW_ADDR_LEN) - 1) + AW88166_CRC_CFG_BASE_ADDR;
59994e412c2SWeidong Wang 
60094e412c2SWeidong Wang 	/* write cfg_end_addr to crc_end_addr */
60194e412c2SWeidong Wang 	ret = regmap_update_bits(aw_dev->regmap, AW88166_CRCCTRL_REG,
60294e412c2SWeidong Wang 				~AW88166_CRC_END_ADDR_MASK, cfg_len_val);
60394e412c2SWeidong Wang 	if (ret)
60494e412c2SWeidong Wang 		return ret;
60594e412c2SWeidong Wang 
60694e412c2SWeidong Wang 	/* enable cfg crc check */
60794e412c2SWeidong Wang 	ret = regmap_update_bits(aw_dev->regmap, AW88166_CRCCTRL_REG,
60894e412c2SWeidong Wang 			~AW88166_CRC_CFG_EN_MASK, AW88166_CRC_CFG_EN_ENABLE_VALUE);
60994e412c2SWeidong Wang 	if (ret)
61094e412c2SWeidong Wang 		return ret;
61194e412c2SWeidong Wang 
61294e412c2SWeidong Wang 	usleep_range(AW88166_1000_US, AW88166_1000_US + 10);
61394e412c2SWeidong Wang 
61494e412c2SWeidong Wang 	/* read crc check result */
61594e412c2SWeidong Wang 	ret = regmap_read(aw_dev->regmap, AW88166_HAGCST_REG, &reg_val);
61694e412c2SWeidong Wang 	if (ret)
61794e412c2SWeidong Wang 		return ret;
61894e412c2SWeidong Wang 
61994e412c2SWeidong Wang 	check_val = (reg_val & (~AW88166_CRC_CHECK_BITS_MASK)) >> AW88166_CRC_CHECK_START_BIT;
62094e412c2SWeidong Wang 
62194e412c2SWeidong Wang 	/* disable cfg crc check */
62294e412c2SWeidong Wang 	ret = regmap_update_bits(aw_dev->regmap, AW88166_CRCCTRL_REG,
62394e412c2SWeidong Wang 			~AW88166_CRC_CFG_EN_MASK, AW88166_CRC_CFG_EN_DISABLE_VALUE);
62494e412c2SWeidong Wang 	if (ret)
62594e412c2SWeidong Wang 		return ret;
62694e412c2SWeidong Wang 
62794e412c2SWeidong Wang 	if (check_val != AW88166_CRC_CHECK_PASS_VAL) {
62894e412c2SWeidong Wang 		dev_err(aw_dev->dev, "crc_check failed, check val 0x%x != 0x%x\n",
62994e412c2SWeidong Wang 						check_val, AW88166_CRC_CHECK_PASS_VAL);
63094e412c2SWeidong Wang 		ret = -EINVAL;
63194e412c2SWeidong Wang 	}
63294e412c2SWeidong Wang 
63394e412c2SWeidong Wang 	return ret;
63494e412c2SWeidong Wang }
63594e412c2SWeidong Wang 
aw_dev_hw_crc_check(struct aw88166 * aw88166)63694e412c2SWeidong Wang static int aw_dev_hw_crc_check(struct aw88166 *aw88166)
63794e412c2SWeidong Wang {
63894e412c2SWeidong Wang 	struct aw_device *aw_dev = aw88166->aw_pa;
63994e412c2SWeidong Wang 	int ret;
64094e412c2SWeidong Wang 
64194e412c2SWeidong Wang 	ret = regmap_update_bits(aw_dev->regmap, AW88166_I2SCFG1_REG,
64294e412c2SWeidong Wang 		~AW88166_RAM_CG_BYP_MASK, AW88166_RAM_CG_BYP_BYPASS_VALUE);
64394e412c2SWeidong Wang 	if (ret)
64494e412c2SWeidong Wang 		return ret;
64594e412c2SWeidong Wang 
64694e412c2SWeidong Wang 	ret = aw_dev_fw_crc_check(aw_dev);
64794e412c2SWeidong Wang 	if (ret) {
64894e412c2SWeidong Wang 		dev_err(aw_dev->dev, "fw_crc_check failed\n");
64994e412c2SWeidong Wang 		goto crc_check_failed;
65094e412c2SWeidong Wang 	}
65194e412c2SWeidong Wang 
65294e412c2SWeidong Wang 	ret = aw_dev_cfg_crc_check(aw_dev);
65394e412c2SWeidong Wang 	if (ret) {
65494e412c2SWeidong Wang 		dev_err(aw_dev->dev, "cfg_crc_check failed\n");
65594e412c2SWeidong Wang 		goto crc_check_failed;
65694e412c2SWeidong Wang 	}
65794e412c2SWeidong Wang 
65894e412c2SWeidong Wang 	ret = regmap_write(aw_dev->regmap, AW88166_CRCCTRL_REG, aw88166->crc_init_val);
65994e412c2SWeidong Wang 	if (ret)
66094e412c2SWeidong Wang 		return ret;
66194e412c2SWeidong Wang 
66294e412c2SWeidong Wang 	ret = regmap_update_bits(aw_dev->regmap, AW88166_I2SCFG1_REG,
66394e412c2SWeidong Wang 		~AW88166_RAM_CG_BYP_MASK, AW88166_RAM_CG_BYP_WORK_VALUE);
66494e412c2SWeidong Wang 
66594e412c2SWeidong Wang 	return ret;
66694e412c2SWeidong Wang 
66794e412c2SWeidong Wang crc_check_failed:
66894e412c2SWeidong Wang 	regmap_update_bits(aw_dev->regmap, AW88166_I2SCFG1_REG,
66994e412c2SWeidong Wang 		~AW88166_RAM_CG_BYP_MASK, AW88166_RAM_CG_BYP_WORK_VALUE);
67094e412c2SWeidong Wang 	return ret;
67194e412c2SWeidong Wang }
67294e412c2SWeidong Wang 
aw_dev_i2s_tx_enable(struct aw_device * aw_dev,bool flag)67394e412c2SWeidong Wang static void aw_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag)
67494e412c2SWeidong Wang {
67594e412c2SWeidong Wang 	int ret;
67694e412c2SWeidong Wang 
67794e412c2SWeidong Wang 	if (flag)
67894e412c2SWeidong Wang 		ret = regmap_update_bits(aw_dev->regmap, AW88166_I2SCTRL3_REG,
67994e412c2SWeidong Wang 			~AW88166_I2STXEN_MASK, AW88166_I2STXEN_ENABLE_VALUE);
68094e412c2SWeidong Wang 	else
68194e412c2SWeidong Wang 		ret = regmap_update_bits(aw_dev->regmap, AW88166_I2SCTRL3_REG,
68294e412c2SWeidong Wang 			~AW88166_I2STXEN_MASK, AW88166_I2STXEN_DISABLE_VALUE);
68394e412c2SWeidong Wang 
68494e412c2SWeidong Wang 	if (ret)
68594e412c2SWeidong Wang 		dev_dbg(aw_dev->dev, "%s failed", __func__);
68694e412c2SWeidong Wang }
68794e412c2SWeidong Wang 
aw_dev_get_dsp_status(struct aw_device * aw_dev)68894e412c2SWeidong Wang static int aw_dev_get_dsp_status(struct aw_device *aw_dev)
68994e412c2SWeidong Wang {
69094e412c2SWeidong Wang 	unsigned int reg_val;
69194e412c2SWeidong Wang 	int ret;
69294e412c2SWeidong Wang 
69394e412c2SWeidong Wang 	ret = regmap_read(aw_dev->regmap, AW88166_WDT_REG, &reg_val);
69494e412c2SWeidong Wang 	if (ret)
69594e412c2SWeidong Wang 		return ret;
69694e412c2SWeidong Wang 	if (!(reg_val & (~AW88166_WDT_CNT_MASK)))
69794e412c2SWeidong Wang 		return -EPERM;
69894e412c2SWeidong Wang 
69994e412c2SWeidong Wang 	return 0;
70094e412c2SWeidong Wang }
70194e412c2SWeidong Wang 
aw_dev_dsp_check(struct aw_device * aw_dev)70294e412c2SWeidong Wang static int aw_dev_dsp_check(struct aw_device *aw_dev)
70394e412c2SWeidong Wang {
70494e412c2SWeidong Wang 	int ret, i;
70594e412c2SWeidong Wang 
70694e412c2SWeidong Wang 	switch (aw_dev->dsp_cfg) {
70794e412c2SWeidong Wang 	case AW88166_DEV_DSP_BYPASS:
70894e412c2SWeidong Wang 		dev_dbg(aw_dev->dev, "dsp bypass");
70994e412c2SWeidong Wang 		ret = 0;
71094e412c2SWeidong Wang 		break;
71194e412c2SWeidong Wang 	case AW88166_DEV_DSP_WORK:
71294e412c2SWeidong Wang 		aw_dev_dsp_enable(aw_dev, false);
71394e412c2SWeidong Wang 		aw_dev_dsp_enable(aw_dev, true);
71494e412c2SWeidong Wang 		usleep_range(AW88166_1000_US, AW88166_1000_US + 10);
71594e412c2SWeidong Wang 		for (i = 0; i < AW88166_DEV_DSP_CHECK_MAX; i++) {
71694e412c2SWeidong Wang 			ret = aw_dev_get_dsp_status(aw_dev);
71794e412c2SWeidong Wang 			if (ret) {
71894e412c2SWeidong Wang 				dev_err(aw_dev->dev, "dsp wdt status error=%d", ret);
71994e412c2SWeidong Wang 				usleep_range(AW88166_2000_US, AW88166_2000_US + 10);
72094e412c2SWeidong Wang 			}
72194e412c2SWeidong Wang 		}
72294e412c2SWeidong Wang 		break;
72394e412c2SWeidong Wang 	default:
72494e412c2SWeidong Wang 		dev_err(aw_dev->dev, "unknown dsp cfg=%d", aw_dev->dsp_cfg);
72594e412c2SWeidong Wang 		ret = -EINVAL;
72694e412c2SWeidong Wang 		break;
72794e412c2SWeidong Wang 	}
72894e412c2SWeidong Wang 
72994e412c2SWeidong Wang 	return ret;
73094e412c2SWeidong Wang }
73194e412c2SWeidong Wang 
aw_dev_set_volume(struct aw_device * aw_dev,unsigned int value)73294e412c2SWeidong Wang static int aw_dev_set_volume(struct aw_device *aw_dev, unsigned int value)
73394e412c2SWeidong Wang {
73494e412c2SWeidong Wang 	struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
73594e412c2SWeidong Wang 	unsigned int reg_value;
73694e412c2SWeidong Wang 	u16 real_value;
73794e412c2SWeidong Wang 	int ret;
73894e412c2SWeidong Wang 
73994e412c2SWeidong Wang 	real_value = min((value + vol_desc->init_volume), (unsigned int)AW88166_MUTE_VOL);
74094e412c2SWeidong Wang 
74194e412c2SWeidong Wang 	ret = regmap_read(aw_dev->regmap, AW88166_SYSCTRL2_REG, &reg_value);
74294e412c2SWeidong Wang 	if (ret)
74394e412c2SWeidong Wang 		return ret;
74494e412c2SWeidong Wang 
74594e412c2SWeidong Wang 	dev_dbg(aw_dev->dev, "value 0x%x , reg:0x%x", value, real_value);
74694e412c2SWeidong Wang 
74794e412c2SWeidong Wang 	real_value = (real_value << AW88166_VOL_START_BIT) | (reg_value & AW88166_VOL_MASK);
74894e412c2SWeidong Wang 
74994e412c2SWeidong Wang 	ret = regmap_write(aw_dev->regmap, AW88166_SYSCTRL2_REG, real_value);
75094e412c2SWeidong Wang 
75194e412c2SWeidong Wang 	return ret;
75294e412c2SWeidong Wang }
75394e412c2SWeidong Wang 
aw_dev_fade_in(struct aw_device * aw_dev)75494e412c2SWeidong Wang static void aw_dev_fade_in(struct aw_device *aw_dev)
75594e412c2SWeidong Wang {
75694e412c2SWeidong Wang 	struct aw_volume_desc *desc = &aw_dev->volume_desc;
75794e412c2SWeidong Wang 	u16 fade_in_vol = desc->ctl_volume;
75894e412c2SWeidong Wang 	int fade_step = aw_dev->fade_step;
75994e412c2SWeidong Wang 	int i;
76094e412c2SWeidong Wang 
76194e412c2SWeidong Wang 	if (fade_step == 0 || aw_dev->fade_in_time == 0) {
76294e412c2SWeidong Wang 		aw_dev_set_volume(aw_dev, fade_in_vol);
76394e412c2SWeidong Wang 		return;
76494e412c2SWeidong Wang 	}
76594e412c2SWeidong Wang 
76694e412c2SWeidong Wang 	for (i = AW88166_MUTE_VOL; i >= fade_in_vol; i -= fade_step) {
76794e412c2SWeidong Wang 		aw_dev_set_volume(aw_dev, i);
76894e412c2SWeidong Wang 		usleep_range(aw_dev->fade_in_time, aw_dev->fade_in_time + 10);
76994e412c2SWeidong Wang 	}
77094e412c2SWeidong Wang 
77194e412c2SWeidong Wang 	if (i != fade_in_vol)
77294e412c2SWeidong Wang 		aw_dev_set_volume(aw_dev, fade_in_vol);
77394e412c2SWeidong Wang }
77494e412c2SWeidong Wang 
aw_dev_fade_out(struct aw_device * aw_dev)77594e412c2SWeidong Wang static void aw_dev_fade_out(struct aw_device *aw_dev)
77694e412c2SWeidong Wang {
77794e412c2SWeidong Wang 	struct aw_volume_desc *desc = &aw_dev->volume_desc;
77894e412c2SWeidong Wang 	int fade_step = aw_dev->fade_step;
77994e412c2SWeidong Wang 	int i;
78094e412c2SWeidong Wang 
78194e412c2SWeidong Wang 	if (fade_step == 0 || aw_dev->fade_out_time == 0) {
78294e412c2SWeidong Wang 		aw_dev_set_volume(aw_dev, AW88166_MUTE_VOL);
78394e412c2SWeidong Wang 		return;
78494e412c2SWeidong Wang 	}
78594e412c2SWeidong Wang 
78694e412c2SWeidong Wang 	for (i = desc->ctl_volume; i <= AW88166_MUTE_VOL; i += fade_step) {
78794e412c2SWeidong Wang 		aw_dev_set_volume(aw_dev, i);
78894e412c2SWeidong Wang 		usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
78994e412c2SWeidong Wang 	}
79094e412c2SWeidong Wang 
79194e412c2SWeidong Wang 	if (i != AW88166_MUTE_VOL) {
79294e412c2SWeidong Wang 		aw_dev_set_volume(aw_dev, AW88166_MUTE_VOL);
79394e412c2SWeidong Wang 		usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
79494e412c2SWeidong Wang 	}
79594e412c2SWeidong Wang }
79694e412c2SWeidong Wang 
aw88166_dev_mute(struct aw_device * aw_dev,bool is_mute)79794e412c2SWeidong Wang static void aw88166_dev_mute(struct aw_device *aw_dev, bool is_mute)
79894e412c2SWeidong Wang {
79994e412c2SWeidong Wang 	if (is_mute) {
80094e412c2SWeidong Wang 		aw_dev_fade_out(aw_dev);
80194e412c2SWeidong Wang 		regmap_update_bits(aw_dev->regmap, AW88166_SYSCTRL_REG,
80294e412c2SWeidong Wang 				~AW88166_HMUTE_MASK, AW88166_HMUTE_ENABLE_VALUE);
80394e412c2SWeidong Wang 	} else {
80494e412c2SWeidong Wang 		regmap_update_bits(aw_dev->regmap, AW88166_SYSCTRL_REG,
80594e412c2SWeidong Wang 				~AW88166_HMUTE_MASK, AW88166_HMUTE_DISABLE_VALUE);
80694e412c2SWeidong Wang 		aw_dev_fade_in(aw_dev);
80794e412c2SWeidong Wang 	}
80894e412c2SWeidong Wang }
80994e412c2SWeidong Wang 
aw88166_dev_set_dither(struct aw88166 * aw88166,bool dither)81094e412c2SWeidong Wang static void aw88166_dev_set_dither(struct aw88166 *aw88166, bool dither)
81194e412c2SWeidong Wang {
81294e412c2SWeidong Wang 	struct aw_device *aw_dev = aw88166->aw_pa;
81394e412c2SWeidong Wang 
81494e412c2SWeidong Wang 	if (dither)
81594e412c2SWeidong Wang 		regmap_update_bits(aw_dev->regmap, AW88166_DBGCTRL_REG,
81694e412c2SWeidong Wang 				~AW88166_DITHER_EN_MASK, AW88166_DITHER_EN_ENABLE_VALUE);
81794e412c2SWeidong Wang 	else
81894e412c2SWeidong Wang 		regmap_update_bits(aw_dev->regmap, AW88166_DBGCTRL_REG,
81994e412c2SWeidong Wang 				~AW88166_DITHER_EN_MASK, AW88166_DITHER_EN_DISABLE_VALUE);
82094e412c2SWeidong Wang }
82194e412c2SWeidong Wang 
aw88166_dev_start(struct aw88166 * aw88166)82294e412c2SWeidong Wang static int aw88166_dev_start(struct aw88166 *aw88166)
82394e412c2SWeidong Wang {
82494e412c2SWeidong Wang 	struct aw_device *aw_dev = aw88166->aw_pa;
82594e412c2SWeidong Wang 	int ret;
82694e412c2SWeidong Wang 
82794e412c2SWeidong Wang 	if (aw_dev->status == AW88166_DEV_PW_ON) {
82894e412c2SWeidong Wang 		dev_dbg(aw_dev->dev, "already power on");
82994e412c2SWeidong Wang 		return 0;
83094e412c2SWeidong Wang 	}
83194e412c2SWeidong Wang 
83294e412c2SWeidong Wang 	aw88166_dev_set_dither(aw88166, false);
83394e412c2SWeidong Wang 
83494e412c2SWeidong Wang 	/* power on */
83594e412c2SWeidong Wang 	aw_dev_pwd(aw_dev, false);
83694e412c2SWeidong Wang 	usleep_range(AW88166_2000_US, AW88166_2000_US + 10);
83794e412c2SWeidong Wang 
83894e412c2SWeidong Wang 	ret = aw_dev_check_syspll(aw_dev);
83994e412c2SWeidong Wang 	if (ret) {
84094e412c2SWeidong Wang 		dev_err(aw_dev->dev, "pll check failed cannot start\n");
84194e412c2SWeidong Wang 		goto pll_check_fail;
84294e412c2SWeidong Wang 	}
84394e412c2SWeidong Wang 
84494e412c2SWeidong Wang 	/* amppd on */
84594e412c2SWeidong Wang 	aw_dev_amppd(aw_dev, false);
84694e412c2SWeidong Wang 	usleep_range(AW88166_1000_US, AW88166_1000_US + 50);
84794e412c2SWeidong Wang 
84894e412c2SWeidong Wang 	/* check i2s status */
84994e412c2SWeidong Wang 	ret = aw_dev_check_sysst(aw_dev);
85094e412c2SWeidong Wang 	if (ret) {
85194e412c2SWeidong Wang 		dev_err(aw_dev->dev, "sysst check failed\n");
85294e412c2SWeidong Wang 		goto sysst_check_fail;
85394e412c2SWeidong Wang 	}
85494e412c2SWeidong Wang 
85594e412c2SWeidong Wang 	if (aw_dev->dsp_cfg == AW88166_DEV_DSP_WORK) {
85694e412c2SWeidong Wang 		aw_dev_backup_sec_recovery(aw88166);
85794e412c2SWeidong Wang 		ret = aw_dev_hw_crc_check(aw88166);
85894e412c2SWeidong Wang 		if (ret) {
85994e412c2SWeidong Wang 			dev_err(aw_dev->dev, "dsp crc check failed\n");
86094e412c2SWeidong Wang 			goto crc_check_fail;
86194e412c2SWeidong Wang 		}
86294e412c2SWeidong Wang 		aw_dev_dsp_enable(aw_dev, false);
86394e412c2SWeidong Wang 		aw88166_dev_set_vcalb(aw88166);
86494e412c2SWeidong Wang 		aw_dev_update_cali_re(&aw_dev->cali_desc);
86594e412c2SWeidong Wang 		ret = aw_dev_dsp_check(aw_dev);
86694e412c2SWeidong Wang 		if (ret) {
86794e412c2SWeidong Wang 			dev_err(aw_dev->dev, "dsp status check failed\n");
86894e412c2SWeidong Wang 			goto dsp_check_fail;
86994e412c2SWeidong Wang 		}
87094e412c2SWeidong Wang 	} else {
87194e412c2SWeidong Wang 		dev_dbg(aw_dev->dev, "start pa with dsp bypass");
87294e412c2SWeidong Wang 	}
87394e412c2SWeidong Wang 
87494e412c2SWeidong Wang 	/* enable tx feedback */
87594e412c2SWeidong Wang 	aw_dev_i2s_tx_enable(aw_dev, true);
87694e412c2SWeidong Wang 
87794e412c2SWeidong Wang 	if (aw88166->dither_st == AW88166_DITHER_EN_ENABLE_VALUE)
87894e412c2SWeidong Wang 		aw88166_dev_set_dither(aw88166, true);
87994e412c2SWeidong Wang 
88094e412c2SWeidong Wang 	/* close mute */
88194e412c2SWeidong Wang 	aw88166_dev_mute(aw_dev, false);
88294e412c2SWeidong Wang 	/* clear inturrupt */
88394e412c2SWeidong Wang 	aw_dev_clear_int_status(aw_dev);
88494e412c2SWeidong Wang 	aw_dev->status = AW88166_DEV_PW_ON;
88594e412c2SWeidong Wang 
88694e412c2SWeidong Wang 	return 0;
88794e412c2SWeidong Wang 
88894e412c2SWeidong Wang dsp_check_fail:
88994e412c2SWeidong Wang crc_check_fail:
89094e412c2SWeidong Wang 	aw_dev_dsp_enable(aw_dev, false);
89194e412c2SWeidong Wang sysst_check_fail:
89294e412c2SWeidong Wang 	aw_dev_clear_int_status(aw_dev);
89394e412c2SWeidong Wang 	aw_dev_amppd(aw_dev, true);
89494e412c2SWeidong Wang pll_check_fail:
89594e412c2SWeidong Wang 	aw_dev_pwd(aw_dev, true);
89694e412c2SWeidong Wang 	aw_dev->status = AW88166_DEV_PW_OFF;
89794e412c2SWeidong Wang 
89894e412c2SWeidong Wang 	return ret;
89994e412c2SWeidong Wang }
90094e412c2SWeidong Wang 
aw_dev_dsp_update_container(struct aw_device * aw_dev,unsigned char * data,unsigned int len,unsigned short base)90194e412c2SWeidong Wang static int aw_dev_dsp_update_container(struct aw_device *aw_dev,
90294e412c2SWeidong Wang 			unsigned char *data, unsigned int len, unsigned short base)
90394e412c2SWeidong Wang {
90494e412c2SWeidong Wang 	u32 tmp_len;
90594e412c2SWeidong Wang 	int i, ret;
90694e412c2SWeidong Wang 
90794e412c2SWeidong Wang 	mutex_lock(&aw_dev->dsp_lock);
90894e412c2SWeidong Wang 	ret = regmap_write(aw_dev->regmap, AW88166_DSPMADD_REG, base);
90994e412c2SWeidong Wang 	if (ret)
91094e412c2SWeidong Wang 		goto error_operation;
91194e412c2SWeidong Wang 
91294e412c2SWeidong Wang 	for (i = 0; i < len; i += AW88166_MAX_RAM_WRITE_BYTE_SIZE) {
913*84dea31dSThorsten Blum 		tmp_len = min(len - i, AW88166_MAX_RAM_WRITE_BYTE_SIZE);
91494e412c2SWeidong Wang 		ret = regmap_raw_write(aw_dev->regmap, AW88166_DSPMDAT_REG,
91594e412c2SWeidong Wang 					&data[i], tmp_len);
91694e412c2SWeidong Wang 		if (ret)
91794e412c2SWeidong Wang 			goto error_operation;
91894e412c2SWeidong Wang 	}
91994e412c2SWeidong Wang 	mutex_unlock(&aw_dev->dsp_lock);
92094e412c2SWeidong Wang 
92194e412c2SWeidong Wang 	return 0;
92294e412c2SWeidong Wang 
92394e412c2SWeidong Wang error_operation:
92494e412c2SWeidong Wang 	mutex_unlock(&aw_dev->dsp_lock);
92594e412c2SWeidong Wang 	return ret;
92694e412c2SWeidong Wang }
92794e412c2SWeidong Wang 
aw_dev_get_ra(struct aw_cali_desc * cali_desc)92894e412c2SWeidong Wang static int aw_dev_get_ra(struct aw_cali_desc *cali_desc)
92994e412c2SWeidong Wang {
93094e412c2SWeidong Wang 	struct aw_device *aw_dev =
93194e412c2SWeidong Wang 		container_of(cali_desc, struct aw_device, cali_desc);
93294e412c2SWeidong Wang 	u32 dsp_ra;
93394e412c2SWeidong Wang 	int ret;
93494e412c2SWeidong Wang 
93594e412c2SWeidong Wang 	ret = aw_dev_dsp_read(aw_dev, AW88166_DSP_REG_CFG_ADPZ_RA,
93694e412c2SWeidong Wang 				&dsp_ra, AW88166_DSP_32_DATA);
93794e412c2SWeidong Wang 	if (ret) {
93894e412c2SWeidong Wang 		dev_err(aw_dev->dev, "read ra error\n");
93994e412c2SWeidong Wang 		return ret;
94094e412c2SWeidong Wang 	}
94194e412c2SWeidong Wang 
94294e412c2SWeidong Wang 	cali_desc->ra = AW88166_DSP_RE_TO_SHOW_RE(dsp_ra,
94394e412c2SWeidong Wang 					AW88166_DSP_RE_SHIFT);
94494e412c2SWeidong Wang 
94594e412c2SWeidong Wang 	return 0;
94694e412c2SWeidong Wang }
94794e412c2SWeidong Wang 
aw_dev_dsp_update_cfg(struct aw_device * aw_dev,unsigned char * data,unsigned int len)94894e412c2SWeidong Wang static int aw_dev_dsp_update_cfg(struct aw_device *aw_dev,
94994e412c2SWeidong Wang 			unsigned char *data, unsigned int len)
95094e412c2SWeidong Wang {
95194e412c2SWeidong Wang 	int ret;
95294e412c2SWeidong Wang 
95394e412c2SWeidong Wang 	dev_dbg(aw_dev->dev, "dsp config len:%d", len);
95494e412c2SWeidong Wang 
95594e412c2SWeidong Wang 	if (!len || !data) {
95694e412c2SWeidong Wang 		dev_err(aw_dev->dev, "dsp config data is null or len is 0\n");
95794e412c2SWeidong Wang 		return -EINVAL;
95894e412c2SWeidong Wang 	}
95994e412c2SWeidong Wang 
96094e412c2SWeidong Wang 	ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88166_DSP_CFG_ADDR);
96194e412c2SWeidong Wang 	if (ret)
96294e412c2SWeidong Wang 		return ret;
96394e412c2SWeidong Wang 
96494e412c2SWeidong Wang 	aw_dev->dsp_cfg_len = len;
96594e412c2SWeidong Wang 
96694e412c2SWeidong Wang 	ret = aw_dev_get_ra(&aw_dev->cali_desc);
96794e412c2SWeidong Wang 
96894e412c2SWeidong Wang 	return ret;
96994e412c2SWeidong Wang }
97094e412c2SWeidong Wang 
aw_dev_dsp_update_fw(struct aw_device * aw_dev,unsigned char * data,unsigned int len)97194e412c2SWeidong Wang static int aw_dev_dsp_update_fw(struct aw_device *aw_dev,
97294e412c2SWeidong Wang 			unsigned char *data, unsigned int len)
97394e412c2SWeidong Wang {
97494e412c2SWeidong Wang 	int ret;
97594e412c2SWeidong Wang 
97694e412c2SWeidong Wang 	dev_dbg(aw_dev->dev, "dsp firmware len:%d", len);
97794e412c2SWeidong Wang 
97894e412c2SWeidong Wang 	if (!len || !data) {
97994e412c2SWeidong Wang 		dev_err(aw_dev->dev, "dsp firmware data is null or len is 0\n");
98094e412c2SWeidong Wang 		return -EINVAL;
98194e412c2SWeidong Wang 	}
98294e412c2SWeidong Wang 
98394e412c2SWeidong Wang 	aw_dev->dsp_fw_len = len;
98494e412c2SWeidong Wang 	ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88166_DSP_FW_ADDR);
98594e412c2SWeidong Wang 
98694e412c2SWeidong Wang 	return ret;
98794e412c2SWeidong Wang }
98894e412c2SWeidong Wang 
aw_dev_check_sram(struct aw_device * aw_dev)98994e412c2SWeidong Wang static int aw_dev_check_sram(struct aw_device *aw_dev)
99094e412c2SWeidong Wang {
99194e412c2SWeidong Wang 	unsigned int reg_val;
99294e412c2SWeidong Wang 
99394e412c2SWeidong Wang 	mutex_lock(&aw_dev->dsp_lock);
99494e412c2SWeidong Wang 	/* read dsp_rom_check_reg */
99594e412c2SWeidong Wang 	aw_dev_dsp_read_16bit(aw_dev, AW88166_DSP_ROM_CHECK_ADDR, &reg_val);
99694e412c2SWeidong Wang 	if (reg_val != AW88166_DSP_ROM_CHECK_DATA) {
99794e412c2SWeidong Wang 		dev_err(aw_dev->dev, "check dsp rom failed, read[0x%x] != check[0x%x]\n",
99894e412c2SWeidong Wang 						reg_val, AW88166_DSP_ROM_CHECK_DATA);
99994e412c2SWeidong Wang 		goto error;
100094e412c2SWeidong Wang 	}
100194e412c2SWeidong Wang 
100294e412c2SWeidong Wang 	/* check dsp_cfg_base_addr */
100394e412c2SWeidong Wang 	aw_dev_dsp_write_16bit(aw_dev, AW88166_DSP_CFG_ADDR, AW88166_DSP_ODD_NUM_BIT_TEST);
100494e412c2SWeidong Wang 	aw_dev_dsp_read_16bit(aw_dev, AW88166_DSP_CFG_ADDR, &reg_val);
100594e412c2SWeidong Wang 	if (reg_val != AW88166_DSP_ODD_NUM_BIT_TEST) {
100694e412c2SWeidong Wang 		dev_err(aw_dev->dev, "check dsp cfg failed, read[0x%x] != write[0x%x]\n",
100794e412c2SWeidong Wang 						reg_val, AW88166_DSP_ODD_NUM_BIT_TEST);
100894e412c2SWeidong Wang 		goto error;
100994e412c2SWeidong Wang 	}
101094e412c2SWeidong Wang 	mutex_unlock(&aw_dev->dsp_lock);
101194e412c2SWeidong Wang 
101294e412c2SWeidong Wang 	return 0;
101394e412c2SWeidong Wang error:
101494e412c2SWeidong Wang 	mutex_unlock(&aw_dev->dsp_lock);
101594e412c2SWeidong Wang 	return -EPERM;
101694e412c2SWeidong Wang }
101794e412c2SWeidong Wang 
aw_dev_select_memclk(struct aw_device * aw_dev,unsigned char flag)101894e412c2SWeidong Wang static void aw_dev_select_memclk(struct aw_device *aw_dev, unsigned char flag)
101994e412c2SWeidong Wang {
102094e412c2SWeidong Wang 	int ret;
102194e412c2SWeidong Wang 
102294e412c2SWeidong Wang 	switch (flag) {
102394e412c2SWeidong Wang 	case AW88166_DEV_MEMCLK_PLL:
102494e412c2SWeidong Wang 		ret = regmap_update_bits(aw_dev->regmap, AW88166_DBGCTRL_REG,
102594e412c2SWeidong Wang 					~AW88166_MEM_CLKSEL_MASK,
102694e412c2SWeidong Wang 					AW88166_MEM_CLKSEL_DAPHCLK_VALUE);
102794e412c2SWeidong Wang 		if (ret)
102894e412c2SWeidong Wang 			dev_err(aw_dev->dev, "memclk select pll failed\n");
102994e412c2SWeidong Wang 		break;
103094e412c2SWeidong Wang 	case AW88166_DEV_MEMCLK_OSC:
103194e412c2SWeidong Wang 		ret = regmap_update_bits(aw_dev->regmap, AW88166_DBGCTRL_REG,
103294e412c2SWeidong Wang 					~AW88166_MEM_CLKSEL_MASK,
103394e412c2SWeidong Wang 					AW88166_MEM_CLKSEL_OSCCLK_VALUE);
103494e412c2SWeidong Wang 		if (ret)
103594e412c2SWeidong Wang 			dev_err(aw_dev->dev, "memclk select OSC failed\n");
103694e412c2SWeidong Wang 		break;
103794e412c2SWeidong Wang 	default:
103894e412c2SWeidong Wang 		dev_err(aw_dev->dev, "unknown memclk config, flag=0x%x\n", flag);
103994e412c2SWeidong Wang 		break;
104094e412c2SWeidong Wang 	}
104194e412c2SWeidong Wang }
104294e412c2SWeidong Wang 
aw_dev_update_reg_container(struct aw88166 * aw88166,unsigned char * data,unsigned int len)104394e412c2SWeidong Wang static int aw_dev_update_reg_container(struct aw88166 *aw88166,
104494e412c2SWeidong Wang 				unsigned char *data, unsigned int len)
104594e412c2SWeidong Wang {
104694e412c2SWeidong Wang 	struct aw_device *aw_dev = aw88166->aw_pa;
104794e412c2SWeidong Wang 	struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
104894e412c2SWeidong Wang 	u16 read_vol, reg_val;
104994e412c2SWeidong Wang 	int data_len, i, ret;
105094e412c2SWeidong Wang 	int16_t *reg_data;
105194e412c2SWeidong Wang 	u8 reg_addr;
105294e412c2SWeidong Wang 
105394e412c2SWeidong Wang 	reg_data = (int16_t *)data;
105494e412c2SWeidong Wang 	data_len = len >> 1;
105594e412c2SWeidong Wang 
105694e412c2SWeidong Wang 	if (data_len & 0x1) {
105794e412c2SWeidong Wang 		dev_err(aw_dev->dev, "data len:%d unsupported\n",	data_len);
105894e412c2SWeidong Wang 		return -EINVAL;
105994e412c2SWeidong Wang 	}
106094e412c2SWeidong Wang 
106194e412c2SWeidong Wang 	for (i = 0; i < data_len; i += 2) {
106294e412c2SWeidong Wang 		reg_addr = reg_data[i];
106394e412c2SWeidong Wang 		reg_val = reg_data[i + 1];
106494e412c2SWeidong Wang 
106594e412c2SWeidong Wang 		if (reg_addr == AW88166_DSPVCALB_REG) {
106694e412c2SWeidong Wang 			aw88166->vcalb_init_val = reg_val;
106794e412c2SWeidong Wang 			continue;
106894e412c2SWeidong Wang 		}
106994e412c2SWeidong Wang 
107094e412c2SWeidong Wang 		if (reg_addr == AW88166_SYSCTRL_REG) {
107194e412c2SWeidong Wang 			if (reg_val & (~AW88166_DSPBY_MASK))
107294e412c2SWeidong Wang 				aw_dev->dsp_cfg = AW88166_DEV_DSP_BYPASS;
107394e412c2SWeidong Wang 			else
107494e412c2SWeidong Wang 				aw_dev->dsp_cfg = AW88166_DEV_DSP_WORK;
107594e412c2SWeidong Wang 
107694e412c2SWeidong Wang 			reg_val &= (AW88166_HMUTE_MASK | AW88166_PWDN_MASK |
107794e412c2SWeidong Wang 						AW88166_DSPBY_MASK);
107894e412c2SWeidong Wang 			reg_val |= (AW88166_HMUTE_ENABLE_VALUE | AW88166_PWDN_POWER_DOWN_VALUE |
107994e412c2SWeidong Wang 						AW88166_DSPBY_BYPASS_VALUE);
108094e412c2SWeidong Wang 		}
108194e412c2SWeidong Wang 
108294e412c2SWeidong Wang 		if (reg_addr == AW88166_I2SCTRL3_REG) {
108394e412c2SWeidong Wang 			reg_val &= AW88166_I2STXEN_MASK;
108494e412c2SWeidong Wang 			reg_val |= AW88166_I2STXEN_DISABLE_VALUE;
108594e412c2SWeidong Wang 		}
108694e412c2SWeidong Wang 
108794e412c2SWeidong Wang 		if (reg_addr == AW88166_SYSCTRL2_REG) {
108894e412c2SWeidong Wang 			read_vol = (reg_val & (~AW88166_VOL_MASK)) >>
108994e412c2SWeidong Wang 				AW88166_VOL_START_BIT;
109094e412c2SWeidong Wang 			aw_dev->volume_desc.init_volume = read_vol;
109194e412c2SWeidong Wang 		}
109294e412c2SWeidong Wang 
109394e412c2SWeidong Wang 		if (reg_addr == AW88166_DBGCTRL_REG) {
109494e412c2SWeidong Wang 			if ((reg_val & (~AW88166_EF_DBMD_MASK)) == AW88166_EF_DBMD_OR_VALUE)
109594e412c2SWeidong Wang 				aw88166->check_val = AW_EF_OR_CHECK;
109694e412c2SWeidong Wang 			else
109794e412c2SWeidong Wang 				aw88166->check_val = AW_EF_AND_CHECK;
109894e412c2SWeidong Wang 
109994e412c2SWeidong Wang 			aw88166->dither_st = reg_val & (~AW88166_DITHER_EN_MASK);
110094e412c2SWeidong Wang 		}
110194e412c2SWeidong Wang 
110294e412c2SWeidong Wang 		if (reg_addr == AW88166_ACR1_REG) {
110394e412c2SWeidong Wang 			aw88166->re_init_val |= (uint32_t)reg_val << 16;
110494e412c2SWeidong Wang 			continue;
110594e412c2SWeidong Wang 		}
110694e412c2SWeidong Wang 
110794e412c2SWeidong Wang 		if (reg_addr == AW88166_ACR2_REG) {
110894e412c2SWeidong Wang 			aw88166->re_init_val |= (uint32_t)reg_val;
110994e412c2SWeidong Wang 			continue;
111094e412c2SWeidong Wang 		}
111194e412c2SWeidong Wang 
111294e412c2SWeidong Wang 		if (reg_addr == AW88166_CRCCTRL_REG)
111394e412c2SWeidong Wang 			aw88166->crc_init_val = reg_val;
111494e412c2SWeidong Wang 
111594e412c2SWeidong Wang 		ret = regmap_write(aw_dev->regmap, reg_addr, reg_val);
111694e412c2SWeidong Wang 		if (ret)
111794e412c2SWeidong Wang 			return ret;
111894e412c2SWeidong Wang 	}
111994e412c2SWeidong Wang 
112094e412c2SWeidong Wang 	aw_dev_pwd(aw_dev, false);
112194e412c2SWeidong Wang 	usleep_range(AW88166_1000_US, AW88166_1000_US + 10);
112294e412c2SWeidong Wang 
112394e412c2SWeidong Wang 	if (aw_dev->prof_cur != aw_dev->prof_index)
112494e412c2SWeidong Wang 		vol_desc->ctl_volume = 0;
112594e412c2SWeidong Wang 	else
112694e412c2SWeidong Wang 		aw_dev_set_volume(aw_dev, vol_desc->ctl_volume);
112794e412c2SWeidong Wang 
112894e412c2SWeidong Wang 	return 0;
112994e412c2SWeidong Wang }
113094e412c2SWeidong Wang 
aw_dev_reg_update(struct aw88166 * aw88166,unsigned char * data,unsigned int len)113194e412c2SWeidong Wang static int aw_dev_reg_update(struct aw88166 *aw88166,
113294e412c2SWeidong Wang 					unsigned char *data, unsigned int len)
113394e412c2SWeidong Wang {
113494e412c2SWeidong Wang 	int ret;
113594e412c2SWeidong Wang 
113694e412c2SWeidong Wang 	if (!len || !data) {
113794e412c2SWeidong Wang 		dev_err(aw88166->aw_pa->dev, "reg data is null or len is 0\n");
113894e412c2SWeidong Wang 		return -EINVAL;
113994e412c2SWeidong Wang 	}
114094e412c2SWeidong Wang 
114194e412c2SWeidong Wang 	ret = aw_dev_update_reg_container(aw88166, data, len);
114294e412c2SWeidong Wang 	if (ret)
114394e412c2SWeidong Wang 		dev_err(aw88166->aw_pa->dev, "reg update failed\n");
114494e412c2SWeidong Wang 
114594e412c2SWeidong Wang 	return ret;
114694e412c2SWeidong Wang }
114794e412c2SWeidong Wang 
aw88166_dev_get_prof_name(struct aw_device * aw_dev,int index,char ** prof_name)114894e412c2SWeidong Wang static int aw88166_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name)
114994e412c2SWeidong Wang {
115094e412c2SWeidong Wang 	struct aw_prof_info *prof_info = &aw_dev->prof_info;
115194e412c2SWeidong Wang 	struct aw_prof_desc *prof_desc;
115294e412c2SWeidong Wang 
115394e412c2SWeidong Wang 	if ((index >= aw_dev->prof_info.count) || (index < 0)) {
115494e412c2SWeidong Wang 		dev_err(aw_dev->dev, "index[%d] overflow count[%d]\n",
115594e412c2SWeidong Wang 						index, aw_dev->prof_info.count);
115694e412c2SWeidong Wang 		return -EINVAL;
115794e412c2SWeidong Wang 	}
115894e412c2SWeidong Wang 
115994e412c2SWeidong Wang 	prof_desc = &aw_dev->prof_info.prof_desc[index];
116094e412c2SWeidong Wang 
116194e412c2SWeidong Wang 	*prof_name = prof_info->prof_name_list[prof_desc->id];
116294e412c2SWeidong Wang 
116394e412c2SWeidong Wang 	return 0;
116494e412c2SWeidong Wang }
116594e412c2SWeidong Wang 
aw88166_dev_get_prof_data(struct aw_device * aw_dev,int index,struct aw_prof_desc ** prof_desc)116694e412c2SWeidong Wang static int aw88166_dev_get_prof_data(struct aw_device *aw_dev, int index,
116794e412c2SWeidong Wang 			struct aw_prof_desc **prof_desc)
116894e412c2SWeidong Wang {
116994e412c2SWeidong Wang 	if ((index >= aw_dev->prof_info.count) || (index < 0)) {
117094e412c2SWeidong Wang 		dev_err(aw_dev->dev, "%s: index[%d] overflow count[%d]\n",
117194e412c2SWeidong Wang 				__func__, index, aw_dev->prof_info.count);
117294e412c2SWeidong Wang 		return -EINVAL;
117394e412c2SWeidong Wang 	}
117494e412c2SWeidong Wang 
117594e412c2SWeidong Wang 	*prof_desc = &aw_dev->prof_info.prof_desc[index];
117694e412c2SWeidong Wang 
117794e412c2SWeidong Wang 	return 0;
117894e412c2SWeidong Wang }
117994e412c2SWeidong Wang 
aw88166_dev_fw_update(struct aw88166 * aw88166,bool up_dsp_fw_en,bool force_up_en)118094e412c2SWeidong Wang static int aw88166_dev_fw_update(struct aw88166 *aw88166, bool up_dsp_fw_en, bool force_up_en)
118194e412c2SWeidong Wang {
118294e412c2SWeidong Wang 	struct aw_device *aw_dev = aw88166->aw_pa;
118394e412c2SWeidong Wang 	struct aw_prof_desc *prof_index_desc;
118494e412c2SWeidong Wang 	struct aw_sec_data_desc *sec_desc;
118594e412c2SWeidong Wang 	char *prof_name;
118694e412c2SWeidong Wang 	int ret;
118794e412c2SWeidong Wang 
118894e412c2SWeidong Wang 	if ((aw_dev->prof_cur == aw_dev->prof_index) &&
118994e412c2SWeidong Wang 			(force_up_en == AW88166_FORCE_UPDATE_OFF)) {
119094e412c2SWeidong Wang 		dev_dbg(aw_dev->dev, "scene no change, not update");
119194e412c2SWeidong Wang 		return 0;
119294e412c2SWeidong Wang 	}
119394e412c2SWeidong Wang 
119494e412c2SWeidong Wang 	if (aw_dev->fw_status == AW88166_DEV_FW_FAILED) {
119594e412c2SWeidong Wang 		dev_err(aw_dev->dev, "fw status[%d] error\n", aw_dev->fw_status);
119694e412c2SWeidong Wang 		return -EPERM;
119794e412c2SWeidong Wang 	}
119894e412c2SWeidong Wang 
119994e412c2SWeidong Wang 	ret = aw88166_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name);
120094e412c2SWeidong Wang 	if (ret)
120194e412c2SWeidong Wang 		return ret;
120294e412c2SWeidong Wang 
120394e412c2SWeidong Wang 	dev_dbg(aw_dev->dev, "start update %s", prof_name);
120494e412c2SWeidong Wang 
120594e412c2SWeidong Wang 	ret = aw88166_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc);
120694e412c2SWeidong Wang 	if (ret)
120794e412c2SWeidong Wang 		return ret;
120894e412c2SWeidong Wang 
120994e412c2SWeidong Wang 	/* update reg */
121094e412c2SWeidong Wang 	sec_desc = prof_index_desc->sec_desc;
121194e412c2SWeidong Wang 	ret = aw_dev_reg_update(aw88166, sec_desc[AW88395_DATA_TYPE_REG].data,
121294e412c2SWeidong Wang 					sec_desc[AW88395_DATA_TYPE_REG].len);
121394e412c2SWeidong Wang 	if (ret) {
121494e412c2SWeidong Wang 		dev_err(aw_dev->dev, "update reg failed\n");
121594e412c2SWeidong Wang 		return ret;
121694e412c2SWeidong Wang 	}
121794e412c2SWeidong Wang 
121894e412c2SWeidong Wang 	aw88166_dev_mute(aw_dev, true);
121994e412c2SWeidong Wang 
122094e412c2SWeidong Wang 	if (aw_dev->dsp_cfg == AW88166_DEV_DSP_WORK)
122194e412c2SWeidong Wang 		aw_dev_dsp_enable(aw_dev, false);
122294e412c2SWeidong Wang 
122394e412c2SWeidong Wang 	aw_dev_select_memclk(aw_dev, AW88166_DEV_MEMCLK_OSC);
122494e412c2SWeidong Wang 
122594e412c2SWeidong Wang 	ret = aw_dev_check_sram(aw_dev);
122694e412c2SWeidong Wang 	if (ret) {
122794e412c2SWeidong Wang 		dev_err(aw_dev->dev, "check sram failed\n");
122894e412c2SWeidong Wang 		goto error;
122994e412c2SWeidong Wang 	}
123094e412c2SWeidong Wang 
123194e412c2SWeidong Wang 	aw_dev_backup_sec_recovery(aw88166);
123294e412c2SWeidong Wang 
123394e412c2SWeidong Wang 	if (up_dsp_fw_en) {
123494e412c2SWeidong Wang 		dev_dbg(aw_dev->dev, "fw_ver: [%x]", prof_index_desc->fw_ver);
123594e412c2SWeidong Wang 		ret = aw_dev_dsp_update_fw(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_FW].data,
123694e412c2SWeidong Wang 					sec_desc[AW88395_DATA_TYPE_DSP_FW].len);
123794e412c2SWeidong Wang 		if (ret) {
123894e412c2SWeidong Wang 			dev_err(aw_dev->dev, "update dsp fw failed\n");
123994e412c2SWeidong Wang 			goto error;
124094e412c2SWeidong Wang 		}
124194e412c2SWeidong Wang 	}
124294e412c2SWeidong Wang 
124394e412c2SWeidong Wang 	/* update dsp config */
124494e412c2SWeidong Wang 	ret = aw_dev_dsp_update_cfg(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_CFG].data,
124594e412c2SWeidong Wang 					sec_desc[AW88395_DATA_TYPE_DSP_CFG].len);
124694e412c2SWeidong Wang 	if (ret) {
124794e412c2SWeidong Wang 		dev_err(aw_dev->dev, "update dsp cfg failed\n");
124894e412c2SWeidong Wang 		goto error;
124994e412c2SWeidong Wang 	}
125094e412c2SWeidong Wang 
125194e412c2SWeidong Wang 	aw_dev_backup_sec_record(aw88166);
125294e412c2SWeidong Wang 
125394e412c2SWeidong Wang 	aw_dev_select_memclk(aw_dev, AW88166_DEV_MEMCLK_PLL);
125494e412c2SWeidong Wang 
125594e412c2SWeidong Wang 	aw_dev->prof_cur = aw_dev->prof_index;
125694e412c2SWeidong Wang 
125794e412c2SWeidong Wang 	return 0;
125894e412c2SWeidong Wang 
125994e412c2SWeidong Wang error:
126094e412c2SWeidong Wang 	aw_dev_select_memclk(aw_dev, AW88166_DEV_MEMCLK_PLL);
126194e412c2SWeidong Wang 	return ret;
126294e412c2SWeidong Wang }
126394e412c2SWeidong Wang 
aw88166_start_pa(struct aw88166 * aw88166)126494e412c2SWeidong Wang static void aw88166_start_pa(struct aw88166 *aw88166)
126594e412c2SWeidong Wang {
126694e412c2SWeidong Wang 	int ret, i;
126794e412c2SWeidong Wang 
126894e412c2SWeidong Wang 	for (i = 0; i < AW88166_START_RETRIES; i++) {
126994e412c2SWeidong Wang 		ret = aw88166_dev_start(aw88166);
127094e412c2SWeidong Wang 		if (ret) {
127194e412c2SWeidong Wang 			dev_err(aw88166->aw_pa->dev, "aw88166 device start failed. retry = %d", i);
127294e412c2SWeidong Wang 			ret = aw88166_dev_fw_update(aw88166, AW88166_DSP_FW_UPDATE_ON, true);
127394e412c2SWeidong Wang 			if (ret) {
127494e412c2SWeidong Wang 				dev_err(aw88166->aw_pa->dev, "fw update failed");
127594e412c2SWeidong Wang 				continue;
127694e412c2SWeidong Wang 			}
127794e412c2SWeidong Wang 		} else {
127894e412c2SWeidong Wang 			dev_dbg(aw88166->aw_pa->dev, "start success\n");
127994e412c2SWeidong Wang 			break;
128094e412c2SWeidong Wang 		}
128194e412c2SWeidong Wang 	}
128294e412c2SWeidong Wang }
128394e412c2SWeidong Wang 
aw88166_startup_work(struct work_struct * work)128494e412c2SWeidong Wang static void aw88166_startup_work(struct work_struct *work)
128594e412c2SWeidong Wang {
128694e412c2SWeidong Wang 	struct aw88166 *aw88166 =
128794e412c2SWeidong Wang 		container_of(work, struct aw88166, start_work.work);
128894e412c2SWeidong Wang 
128994e412c2SWeidong Wang 	mutex_lock(&aw88166->lock);
129094e412c2SWeidong Wang 	aw88166_start_pa(aw88166);
129194e412c2SWeidong Wang 	mutex_unlock(&aw88166->lock);
129294e412c2SWeidong Wang }
129394e412c2SWeidong Wang 
aw88166_start(struct aw88166 * aw88166,bool sync_start)129494e412c2SWeidong Wang static void aw88166_start(struct aw88166 *aw88166, bool sync_start)
129594e412c2SWeidong Wang {
129694e412c2SWeidong Wang 	int ret;
129794e412c2SWeidong Wang 
129894e412c2SWeidong Wang 	if (aw88166->aw_pa->fw_status != AW88166_DEV_FW_OK)
129994e412c2SWeidong Wang 		return;
130094e412c2SWeidong Wang 
130194e412c2SWeidong Wang 	if (aw88166->aw_pa->status == AW88166_DEV_PW_ON)
130294e412c2SWeidong Wang 		return;
130394e412c2SWeidong Wang 
130494e412c2SWeidong Wang 	ret = aw88166_dev_fw_update(aw88166, AW88166_DSP_FW_UPDATE_OFF, aw88166->phase_sync);
130594e412c2SWeidong Wang 	if (ret) {
130694e412c2SWeidong Wang 		dev_err(aw88166->aw_pa->dev, "fw update failed\n");
130794e412c2SWeidong Wang 		return;
130894e412c2SWeidong Wang 	}
130994e412c2SWeidong Wang 
131094e412c2SWeidong Wang 	if (sync_start == AW88166_SYNC_START)
131194e412c2SWeidong Wang 		aw88166_start_pa(aw88166);
131294e412c2SWeidong Wang 	else
131394e412c2SWeidong Wang 		queue_delayed_work(system_wq,
131494e412c2SWeidong Wang 			&aw88166->start_work,
131594e412c2SWeidong Wang 			AW88166_START_WORK_DELAY_MS);
131694e412c2SWeidong Wang }
131794e412c2SWeidong Wang 
aw_dev_check_sysint(struct aw_device * aw_dev)131894e412c2SWeidong Wang static int aw_dev_check_sysint(struct aw_device *aw_dev)
131994e412c2SWeidong Wang {
132094e412c2SWeidong Wang 	u16 reg_val;
132194e412c2SWeidong Wang 
132294e412c2SWeidong Wang 	aw_dev_get_int_status(aw_dev, &reg_val);
132394e412c2SWeidong Wang 	if (reg_val & AW88166_BIT_SYSINT_CHECK) {
132494e412c2SWeidong Wang 		dev_err(aw_dev->dev, "pa stop check fail:0x%04x\n", reg_val);
132594e412c2SWeidong Wang 		return -EINVAL;
132694e412c2SWeidong Wang 	}
132794e412c2SWeidong Wang 
132894e412c2SWeidong Wang 	return 0;
132994e412c2SWeidong Wang }
133094e412c2SWeidong Wang 
aw88166_stop(struct aw_device * aw_dev)133194e412c2SWeidong Wang static int aw88166_stop(struct aw_device *aw_dev)
133294e412c2SWeidong Wang {
133394e412c2SWeidong Wang 	struct aw_sec_data_desc *dsp_cfg =
133494e412c2SWeidong Wang 		&aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_CFG];
133594e412c2SWeidong Wang 	struct aw_sec_data_desc *dsp_fw =
133694e412c2SWeidong Wang 		&aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_FW];
133794e412c2SWeidong Wang 	int int_st;
133894e412c2SWeidong Wang 
133994e412c2SWeidong Wang 	if (aw_dev->status == AW88166_DEV_PW_OFF) {
134094e412c2SWeidong Wang 		dev_dbg(aw_dev->dev, "already power off");
134194e412c2SWeidong Wang 		return 0;
134294e412c2SWeidong Wang 	}
134394e412c2SWeidong Wang 
134494e412c2SWeidong Wang 	aw_dev->status = AW88166_DEV_PW_OFF;
134594e412c2SWeidong Wang 
134694e412c2SWeidong Wang 	aw88166_dev_mute(aw_dev, true);
134794e412c2SWeidong Wang 	usleep_range(AW88166_4000_US, AW88166_4000_US + 100);
134894e412c2SWeidong Wang 
134994e412c2SWeidong Wang 	aw_dev_i2s_tx_enable(aw_dev, false);
135094e412c2SWeidong Wang 	usleep_range(AW88166_1000_US, AW88166_1000_US + 100);
135194e412c2SWeidong Wang 
135294e412c2SWeidong Wang 	int_st = aw_dev_check_sysint(aw_dev);
135394e412c2SWeidong Wang 
135494e412c2SWeidong Wang 	aw_dev_dsp_enable(aw_dev, false);
135594e412c2SWeidong Wang 
135694e412c2SWeidong Wang 	aw_dev_amppd(aw_dev, true);
135794e412c2SWeidong Wang 
135894e412c2SWeidong Wang 	if (int_st) {
135994e412c2SWeidong Wang 		aw_dev_select_memclk(aw_dev, AW88166_DEV_MEMCLK_OSC);
136094e412c2SWeidong Wang 		aw_dev_dsp_update_fw(aw_dev, dsp_fw->data, dsp_fw->len);
136194e412c2SWeidong Wang 		aw_dev_dsp_update_cfg(aw_dev, dsp_cfg->data, dsp_cfg->len);
136294e412c2SWeidong Wang 		aw_dev_select_memclk(aw_dev, AW88166_DEV_MEMCLK_PLL);
136394e412c2SWeidong Wang 	}
136494e412c2SWeidong Wang 
136594e412c2SWeidong Wang 	aw_dev_pwd(aw_dev, true);
136694e412c2SWeidong Wang 
136794e412c2SWeidong Wang 	return 0;
136894e412c2SWeidong Wang }
136994e412c2SWeidong Wang 
137094e412c2SWeidong Wang static struct snd_soc_dai_driver aw88166_dai[] = {
137194e412c2SWeidong Wang 	{
137294e412c2SWeidong Wang 		.name = "aw88166-aif",
137394e412c2SWeidong Wang 		.id = 1,
137494e412c2SWeidong Wang 		.playback = {
137594e412c2SWeidong Wang 			.stream_name = "Speaker_Playback",
137694e412c2SWeidong Wang 			.channels_min = 1,
137794e412c2SWeidong Wang 			.channels_max = 2,
137894e412c2SWeidong Wang 			.rates = AW88166_RATES,
137994e412c2SWeidong Wang 			.formats = AW88166_FORMATS,
138094e412c2SWeidong Wang 		},
138194e412c2SWeidong Wang 		.capture = {
138294e412c2SWeidong Wang 			.stream_name = "Speaker_Capture",
138394e412c2SWeidong Wang 			.channels_min = 1,
138494e412c2SWeidong Wang 			.channels_max = 2,
138594e412c2SWeidong Wang 			.rates = AW88166_RATES,
138694e412c2SWeidong Wang 			.formats = AW88166_FORMATS,
138794e412c2SWeidong Wang 		},
138894e412c2SWeidong Wang 	},
138994e412c2SWeidong Wang };
139094e412c2SWeidong Wang 
aw88166_get_fade_in_time(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)139194e412c2SWeidong Wang static int aw88166_get_fade_in_time(struct snd_kcontrol *kcontrol,
139294e412c2SWeidong Wang 	struct snd_ctl_elem_value *ucontrol)
139394e412c2SWeidong Wang {
139494e412c2SWeidong Wang 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
139594e412c2SWeidong Wang 	struct aw88166 *aw88166 = snd_soc_component_get_drvdata(component);
139694e412c2SWeidong Wang 	struct aw_device *aw_dev = aw88166->aw_pa;
139794e412c2SWeidong Wang 
139894e412c2SWeidong Wang 	ucontrol->value.integer.value[0] = aw_dev->fade_in_time;
139994e412c2SWeidong Wang 
140094e412c2SWeidong Wang 	return 0;
140194e412c2SWeidong Wang }
140294e412c2SWeidong Wang 
aw88166_set_fade_in_time(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)140394e412c2SWeidong Wang static int aw88166_set_fade_in_time(struct snd_kcontrol *kcontrol,
140494e412c2SWeidong Wang 	struct snd_ctl_elem_value *ucontrol)
140594e412c2SWeidong Wang {
140694e412c2SWeidong Wang 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
140794e412c2SWeidong Wang 	struct aw88166 *aw88166 = snd_soc_component_get_drvdata(component);
140894e412c2SWeidong Wang 	struct soc_mixer_control *mc =
140994e412c2SWeidong Wang 		(struct soc_mixer_control *)kcontrol->private_value;
141094e412c2SWeidong Wang 	struct aw_device *aw_dev = aw88166->aw_pa;
141194e412c2SWeidong Wang 	int time;
141294e412c2SWeidong Wang 
141394e412c2SWeidong Wang 	time = ucontrol->value.integer.value[0];
141494e412c2SWeidong Wang 
141594e412c2SWeidong Wang 	if (time < mc->min || time > mc->max)
141694e412c2SWeidong Wang 		return -EINVAL;
141794e412c2SWeidong Wang 
141894e412c2SWeidong Wang 	if (time != aw_dev->fade_in_time) {
141994e412c2SWeidong Wang 		aw_dev->fade_in_time = time;
142094e412c2SWeidong Wang 		return 1;
142194e412c2SWeidong Wang 	}
142294e412c2SWeidong Wang 
142394e412c2SWeidong Wang 	return 0;
142494e412c2SWeidong Wang }
142594e412c2SWeidong Wang 
aw88166_get_fade_out_time(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)142694e412c2SWeidong Wang static int aw88166_get_fade_out_time(struct snd_kcontrol *kcontrol,
142794e412c2SWeidong Wang 	struct snd_ctl_elem_value *ucontrol)
142894e412c2SWeidong Wang {
142994e412c2SWeidong Wang 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
143094e412c2SWeidong Wang 	struct aw88166 *aw88166 = snd_soc_component_get_drvdata(component);
143194e412c2SWeidong Wang 	struct aw_device *aw_dev = aw88166->aw_pa;
143294e412c2SWeidong Wang 
143394e412c2SWeidong Wang 	ucontrol->value.integer.value[0] = aw_dev->fade_out_time;
143494e412c2SWeidong Wang 
143594e412c2SWeidong Wang 	return 0;
143694e412c2SWeidong Wang }
143794e412c2SWeidong Wang 
aw88166_set_fade_out_time(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)143894e412c2SWeidong Wang static int aw88166_set_fade_out_time(struct snd_kcontrol *kcontrol,
143994e412c2SWeidong Wang 	struct snd_ctl_elem_value *ucontrol)
144094e412c2SWeidong Wang {
144194e412c2SWeidong Wang 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
144294e412c2SWeidong Wang 	struct aw88166 *aw88166 = snd_soc_component_get_drvdata(component);
144394e412c2SWeidong Wang 	struct soc_mixer_control *mc =
144494e412c2SWeidong Wang 		(struct soc_mixer_control *)kcontrol->private_value;
144594e412c2SWeidong Wang 	struct aw_device *aw_dev = aw88166->aw_pa;
144694e412c2SWeidong Wang 	int time;
144794e412c2SWeidong Wang 
144894e412c2SWeidong Wang 	time = ucontrol->value.integer.value[0];
144994e412c2SWeidong Wang 	if (time < mc->min || time > mc->max)
145094e412c2SWeidong Wang 		return -EINVAL;
145194e412c2SWeidong Wang 
145294e412c2SWeidong Wang 	if (time != aw_dev->fade_out_time) {
145394e412c2SWeidong Wang 		aw_dev->fade_out_time = time;
145494e412c2SWeidong Wang 		return 1;
145594e412c2SWeidong Wang 	}
145694e412c2SWeidong Wang 
145794e412c2SWeidong Wang 	return 0;
145894e412c2SWeidong Wang }
145994e412c2SWeidong Wang 
aw88166_dev_set_profile_index(struct aw_device * aw_dev,int index)146094e412c2SWeidong Wang static int aw88166_dev_set_profile_index(struct aw_device *aw_dev, int index)
146194e412c2SWeidong Wang {
146294e412c2SWeidong Wang 	/* check the index whether is valid */
146394e412c2SWeidong Wang 	if ((index >= aw_dev->prof_info.count) || (index < 0))
146494e412c2SWeidong Wang 		return -EINVAL;
146594e412c2SWeidong Wang 	/* check the index whether change */
146694e412c2SWeidong Wang 	if (aw_dev->prof_index == index)
146794e412c2SWeidong Wang 		return -EINVAL;
146894e412c2SWeidong Wang 
146994e412c2SWeidong Wang 	aw_dev->prof_index = index;
147094e412c2SWeidong Wang 	dev_dbg(aw_dev->dev, "set prof[%s]",
147194e412c2SWeidong Wang 		aw_dev->prof_info.prof_name_list[aw_dev->prof_info.prof_desc[index].id]);
147294e412c2SWeidong Wang 
147394e412c2SWeidong Wang 	return 0;
147494e412c2SWeidong Wang }
147594e412c2SWeidong Wang 
aw88166_profile_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)147694e412c2SWeidong Wang static int aw88166_profile_info(struct snd_kcontrol *kcontrol,
147794e412c2SWeidong Wang 			 struct snd_ctl_elem_info *uinfo)
147894e412c2SWeidong Wang {
147994e412c2SWeidong Wang 	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
148094e412c2SWeidong Wang 	struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec);
148194e412c2SWeidong Wang 	char *prof_name, *name;
148294e412c2SWeidong Wang 	int count, ret;
148394e412c2SWeidong Wang 
148494e412c2SWeidong Wang 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
148594e412c2SWeidong Wang 	uinfo->count = 1;
148694e412c2SWeidong Wang 
148794e412c2SWeidong Wang 	count = aw88166->aw_pa->prof_info.count;
148894e412c2SWeidong Wang 	if (count <= 0) {
148994e412c2SWeidong Wang 		uinfo->value.enumerated.items = 0;
149094e412c2SWeidong Wang 		return 0;
149194e412c2SWeidong Wang 	}
149294e412c2SWeidong Wang 
149394e412c2SWeidong Wang 	uinfo->value.enumerated.items = count;
149494e412c2SWeidong Wang 
149594e412c2SWeidong Wang 	if (uinfo->value.enumerated.item >= count)
149694e412c2SWeidong Wang 		uinfo->value.enumerated.item = count - 1;
149794e412c2SWeidong Wang 
149894e412c2SWeidong Wang 	name = uinfo->value.enumerated.name;
149994e412c2SWeidong Wang 	count = uinfo->value.enumerated.item;
150094e412c2SWeidong Wang 
150194e412c2SWeidong Wang 	ret = aw88166_dev_get_prof_name(aw88166->aw_pa, count, &prof_name);
150294e412c2SWeidong Wang 	if (ret) {
150394e412c2SWeidong Wang 		strscpy(uinfo->value.enumerated.name, "null",
150494e412c2SWeidong Wang 						strlen("null") + 1);
150594e412c2SWeidong Wang 		return 0;
150694e412c2SWeidong Wang 	}
150794e412c2SWeidong Wang 
150894e412c2SWeidong Wang 	strscpy(name, prof_name, sizeof(uinfo->value.enumerated.name));
150994e412c2SWeidong Wang 
151094e412c2SWeidong Wang 	return 0;
151194e412c2SWeidong Wang }
151294e412c2SWeidong Wang 
aw88166_profile_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)151394e412c2SWeidong Wang static int aw88166_profile_get(struct snd_kcontrol *kcontrol,
151494e412c2SWeidong Wang 			struct snd_ctl_elem_value *ucontrol)
151594e412c2SWeidong Wang {
151694e412c2SWeidong Wang 	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
151794e412c2SWeidong Wang 	struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec);
151894e412c2SWeidong Wang 
151994e412c2SWeidong Wang 	ucontrol->value.integer.value[0] = aw88166->aw_pa->prof_index;
152094e412c2SWeidong Wang 
152194e412c2SWeidong Wang 	return 0;
152294e412c2SWeidong Wang }
152394e412c2SWeidong Wang 
aw88166_profile_set(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)152494e412c2SWeidong Wang static int aw88166_profile_set(struct snd_kcontrol *kcontrol,
152594e412c2SWeidong Wang 		struct snd_ctl_elem_value *ucontrol)
152694e412c2SWeidong Wang {
152794e412c2SWeidong Wang 	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
152894e412c2SWeidong Wang 	struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec);
152994e412c2SWeidong Wang 	int ret;
153094e412c2SWeidong Wang 
153194e412c2SWeidong Wang 	mutex_lock(&aw88166->lock);
153294e412c2SWeidong Wang 	ret = aw88166_dev_set_profile_index(aw88166->aw_pa, ucontrol->value.integer.value[0]);
153394e412c2SWeidong Wang 	if (ret) {
153494e412c2SWeidong Wang 		dev_dbg(codec->dev, "profile index does not change");
153594e412c2SWeidong Wang 		mutex_unlock(&aw88166->lock);
153694e412c2SWeidong Wang 		return 0;
153794e412c2SWeidong Wang 	}
153894e412c2SWeidong Wang 
153994e412c2SWeidong Wang 	if (aw88166->aw_pa->status) {
154094e412c2SWeidong Wang 		aw88166_stop(aw88166->aw_pa);
154194e412c2SWeidong Wang 		aw88166_start(aw88166, AW88166_SYNC_START);
154294e412c2SWeidong Wang 	}
154394e412c2SWeidong Wang 
154494e412c2SWeidong Wang 	mutex_unlock(&aw88166->lock);
154594e412c2SWeidong Wang 
154694e412c2SWeidong Wang 	return 1;
154794e412c2SWeidong Wang }
154894e412c2SWeidong Wang 
aw88166_volume_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)154994e412c2SWeidong Wang static int aw88166_volume_get(struct snd_kcontrol *kcontrol,
155094e412c2SWeidong Wang 				struct snd_ctl_elem_value *ucontrol)
155194e412c2SWeidong Wang {
155294e412c2SWeidong Wang 	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
155394e412c2SWeidong Wang 	struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec);
155494e412c2SWeidong Wang 	struct aw_volume_desc *vol_desc = &aw88166->aw_pa->volume_desc;
155594e412c2SWeidong Wang 
155694e412c2SWeidong Wang 	ucontrol->value.integer.value[0] = vol_desc->ctl_volume;
155794e412c2SWeidong Wang 
155894e412c2SWeidong Wang 	return 0;
155994e412c2SWeidong Wang }
156094e412c2SWeidong Wang 
aw88166_volume_set(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)156194e412c2SWeidong Wang static int aw88166_volume_set(struct snd_kcontrol *kcontrol,
156294e412c2SWeidong Wang 				struct snd_ctl_elem_value *ucontrol)
156394e412c2SWeidong Wang {
156494e412c2SWeidong Wang 	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
156594e412c2SWeidong Wang 	struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec);
156694e412c2SWeidong Wang 	struct aw_volume_desc *vol_desc = &aw88166->aw_pa->volume_desc;
156794e412c2SWeidong Wang 	struct soc_mixer_control *mc =
156894e412c2SWeidong Wang 		(struct soc_mixer_control *)kcontrol->private_value;
156994e412c2SWeidong Wang 	int value;
157094e412c2SWeidong Wang 
157194e412c2SWeidong Wang 	value = ucontrol->value.integer.value[0];
157294e412c2SWeidong Wang 	if (value < mc->min || value > mc->max)
157394e412c2SWeidong Wang 		return -EINVAL;
157494e412c2SWeidong Wang 
157594e412c2SWeidong Wang 	if (vol_desc->ctl_volume != value) {
157694e412c2SWeidong Wang 		vol_desc->ctl_volume = value;
157794e412c2SWeidong Wang 		aw_dev_set_volume(aw88166->aw_pa, vol_desc->ctl_volume);
157894e412c2SWeidong Wang 
157994e412c2SWeidong Wang 		return 1;
158094e412c2SWeidong Wang 	}
158194e412c2SWeidong Wang 
158294e412c2SWeidong Wang 	return 0;
158394e412c2SWeidong Wang }
158494e412c2SWeidong Wang 
aw88166_get_fade_step(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)158594e412c2SWeidong Wang static int aw88166_get_fade_step(struct snd_kcontrol *kcontrol,
158694e412c2SWeidong Wang 				struct snd_ctl_elem_value *ucontrol)
158794e412c2SWeidong Wang {
158894e412c2SWeidong Wang 	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
158994e412c2SWeidong Wang 	struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec);
159094e412c2SWeidong Wang 
159194e412c2SWeidong Wang 	ucontrol->value.integer.value[0] = aw88166->aw_pa->fade_step;
159294e412c2SWeidong Wang 
159394e412c2SWeidong Wang 	return 0;
159494e412c2SWeidong Wang }
159594e412c2SWeidong Wang 
aw88166_set_fade_step(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)159694e412c2SWeidong Wang static int aw88166_set_fade_step(struct snd_kcontrol *kcontrol,
159794e412c2SWeidong Wang 				struct snd_ctl_elem_value *ucontrol)
159894e412c2SWeidong Wang {
159994e412c2SWeidong Wang 	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
160094e412c2SWeidong Wang 	struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec);
160194e412c2SWeidong Wang 	struct soc_mixer_control *mc =
160294e412c2SWeidong Wang 		(struct soc_mixer_control *)kcontrol->private_value;
160394e412c2SWeidong Wang 	int value;
160494e412c2SWeidong Wang 
160594e412c2SWeidong Wang 	value = ucontrol->value.integer.value[0];
160694e412c2SWeidong Wang 	if (value < mc->min || value > mc->max)
160794e412c2SWeidong Wang 		return -EINVAL;
160894e412c2SWeidong Wang 
160994e412c2SWeidong Wang 	if (aw88166->aw_pa->fade_step != value) {
161094e412c2SWeidong Wang 		aw88166->aw_pa->fade_step = value;
161194e412c2SWeidong Wang 		return 1;
161294e412c2SWeidong Wang 	}
161394e412c2SWeidong Wang 
161494e412c2SWeidong Wang 	return 0;
161594e412c2SWeidong Wang }
161694e412c2SWeidong Wang 
aw88166_re_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)161794e412c2SWeidong Wang static int aw88166_re_get(struct snd_kcontrol *kcontrol,
161894e412c2SWeidong Wang 				struct snd_ctl_elem_value *ucontrol)
161994e412c2SWeidong Wang {
162094e412c2SWeidong Wang 	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
162194e412c2SWeidong Wang 	struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec);
162294e412c2SWeidong Wang 	struct aw_device *aw_dev = aw88166->aw_pa;
162394e412c2SWeidong Wang 
162494e412c2SWeidong Wang 	ucontrol->value.integer.value[0] = aw_dev->cali_desc.cali_re;
162594e412c2SWeidong Wang 
162694e412c2SWeidong Wang 	return 0;
162794e412c2SWeidong Wang }
162894e412c2SWeidong Wang 
aw88166_re_set(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)162994e412c2SWeidong Wang static int aw88166_re_set(struct snd_kcontrol *kcontrol,
163094e412c2SWeidong Wang 				struct snd_ctl_elem_value *ucontrol)
163194e412c2SWeidong Wang {
163294e412c2SWeidong Wang 	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
163394e412c2SWeidong Wang 	struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec);
163494e412c2SWeidong Wang 	struct soc_mixer_control *mc =
163594e412c2SWeidong Wang 		(struct soc_mixer_control *)kcontrol->private_value;
163694e412c2SWeidong Wang 	struct aw_device *aw_dev = aw88166->aw_pa;
163794e412c2SWeidong Wang 	int value;
163894e412c2SWeidong Wang 
163994e412c2SWeidong Wang 	value = ucontrol->value.integer.value[0];
164094e412c2SWeidong Wang 	if (value < mc->min || value > mc->max)
164194e412c2SWeidong Wang 		return -EINVAL;
164294e412c2SWeidong Wang 
164394e412c2SWeidong Wang 	if (aw_dev->cali_desc.cali_re != value) {
164494e412c2SWeidong Wang 		aw_dev->cali_desc.cali_re = value;
164594e412c2SWeidong Wang 		return 1;
164694e412c2SWeidong Wang 	}
164794e412c2SWeidong Wang 
164894e412c2SWeidong Wang 	return 0;
164994e412c2SWeidong Wang }
165094e412c2SWeidong Wang 
aw88166_dev_init(struct aw88166 * aw88166,struct aw_container * aw_cfg)165194e412c2SWeidong Wang static int aw88166_dev_init(struct aw88166 *aw88166, struct aw_container *aw_cfg)
165294e412c2SWeidong Wang {
165394e412c2SWeidong Wang 	struct aw_device *aw_dev = aw88166->aw_pa;
165494e412c2SWeidong Wang 	int ret;
165594e412c2SWeidong Wang 
165694e412c2SWeidong Wang 	ret = aw88395_dev_cfg_load(aw_dev, aw_cfg);
165794e412c2SWeidong Wang 	if (ret) {
165894e412c2SWeidong Wang 		dev_err(aw_dev->dev, "aw_dev acf parse failed\n");
165994e412c2SWeidong Wang 		return -EINVAL;
166094e412c2SWeidong Wang 	}
166194e412c2SWeidong Wang 	aw_dev->fade_in_time = AW88166_1000_US / 10;
166294e412c2SWeidong Wang 	aw_dev->fade_out_time = AW88166_1000_US >> 1;
166394e412c2SWeidong Wang 	aw_dev->prof_cur = aw_dev->prof_info.prof_desc[0].id;
166494e412c2SWeidong Wang 	aw_dev->prof_index = aw_dev->prof_info.prof_desc[0].id;
166594e412c2SWeidong Wang 
166694e412c2SWeidong Wang 	ret = aw88166_dev_fw_update(aw88166, AW88166_FORCE_UPDATE_ON, AW88166_DSP_FW_UPDATE_ON);
166794e412c2SWeidong Wang 	if (ret) {
166894e412c2SWeidong Wang 		dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret);
166994e412c2SWeidong Wang 		return ret;
167094e412c2SWeidong Wang 	}
167194e412c2SWeidong Wang 
167294e412c2SWeidong Wang 	aw88166_dev_mute(aw_dev, true);
167394e412c2SWeidong Wang 
167494e412c2SWeidong Wang 	/* close tx feedback */
167594e412c2SWeidong Wang 	aw_dev_i2s_tx_enable(aw_dev, false);
167694e412c2SWeidong Wang 	usleep_range(AW88166_1000_US, AW88166_1000_US + 100);
167794e412c2SWeidong Wang 
167894e412c2SWeidong Wang 	/* enable amppd */
167994e412c2SWeidong Wang 	aw_dev_amppd(aw_dev, true);
168094e412c2SWeidong Wang 
168194e412c2SWeidong Wang 	/* close dsp */
168294e412c2SWeidong Wang 	aw_dev_dsp_enable(aw_dev, false);
168394e412c2SWeidong Wang 	/* set power down */
168494e412c2SWeidong Wang 	aw_dev_pwd(aw_dev, true);
168594e412c2SWeidong Wang 
168694e412c2SWeidong Wang 	return 0;
168794e412c2SWeidong Wang }
168894e412c2SWeidong Wang 
aw88166_request_firmware_file(struct aw88166 * aw88166)168994e412c2SWeidong Wang static int aw88166_request_firmware_file(struct aw88166 *aw88166)
169094e412c2SWeidong Wang {
169194e412c2SWeidong Wang 	const struct firmware *cont = NULL;
169294e412c2SWeidong Wang 	int ret;
169394e412c2SWeidong Wang 
169494e412c2SWeidong Wang 	aw88166->aw_pa->fw_status = AW88166_DEV_FW_FAILED;
169594e412c2SWeidong Wang 
169694e412c2SWeidong Wang 	ret = request_firmware(&cont, AW88166_ACF_FILE, aw88166->aw_pa->dev);
169794e412c2SWeidong Wang 	if (ret) {
169894e412c2SWeidong Wang 		dev_err(aw88166->aw_pa->dev, "request [%s] failed!\n", AW88166_ACF_FILE);
169994e412c2SWeidong Wang 		return ret;
170094e412c2SWeidong Wang 	}
170194e412c2SWeidong Wang 
170294e412c2SWeidong Wang 	dev_dbg(aw88166->aw_pa->dev, "loaded %s - size: %zu\n",
170394e412c2SWeidong Wang 			AW88166_ACF_FILE, cont ? cont->size : 0);
170494e412c2SWeidong Wang 
170594e412c2SWeidong Wang 	aw88166->aw_cfg = devm_kzalloc(aw88166->aw_pa->dev,
170694e412c2SWeidong Wang 			struct_size(aw88166->aw_cfg, data, cont->size), GFP_KERNEL);
170794e412c2SWeidong Wang 	if (!aw88166->aw_cfg) {
170894e412c2SWeidong Wang 		release_firmware(cont);
170994e412c2SWeidong Wang 		return -ENOMEM;
171094e412c2SWeidong Wang 	}
171194e412c2SWeidong Wang 	aw88166->aw_cfg->len = (int)cont->size;
171294e412c2SWeidong Wang 	memcpy(aw88166->aw_cfg->data, cont->data, cont->size);
171394e412c2SWeidong Wang 	release_firmware(cont);
171494e412c2SWeidong Wang 
171594e412c2SWeidong Wang 	ret = aw88395_dev_load_acf_check(aw88166->aw_pa, aw88166->aw_cfg);
171694e412c2SWeidong Wang 	if (ret) {
171794e412c2SWeidong Wang 		dev_err(aw88166->aw_pa->dev, "load [%s] failed!\n", AW88166_ACF_FILE);
171894e412c2SWeidong Wang 		return ret;
171994e412c2SWeidong Wang 	}
172094e412c2SWeidong Wang 
172194e412c2SWeidong Wang 	mutex_lock(&aw88166->lock);
172294e412c2SWeidong Wang 	/* aw device init */
172394e412c2SWeidong Wang 	ret = aw88166_dev_init(aw88166, aw88166->aw_cfg);
172494e412c2SWeidong Wang 	if (ret)
172594e412c2SWeidong Wang 		dev_err(aw88166->aw_pa->dev, "dev init failed\n");
172694e412c2SWeidong Wang 	mutex_unlock(&aw88166->lock);
172794e412c2SWeidong Wang 
172894e412c2SWeidong Wang 	return ret;
172994e412c2SWeidong Wang }
173094e412c2SWeidong Wang 
173194e412c2SWeidong Wang static const struct snd_kcontrol_new aw88166_controls[] = {
173294e412c2SWeidong Wang 	SOC_SINGLE_EXT("PCM Playback Volume", AW88166_SYSCTRL2_REG,
173394e412c2SWeidong Wang 		6, AW88166_MUTE_VOL, 0, aw88166_volume_get,
173494e412c2SWeidong Wang 		aw88166_volume_set),
173594e412c2SWeidong Wang 	SOC_SINGLE_EXT("Fade Step", 0, 0, AW88166_MUTE_VOL, 0,
173694e412c2SWeidong Wang 		aw88166_get_fade_step, aw88166_set_fade_step),
173794e412c2SWeidong Wang 	SOC_SINGLE_EXT("Volume Ramp Up Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN,
173894e412c2SWeidong Wang 		aw88166_get_fade_in_time, aw88166_set_fade_in_time),
173994e412c2SWeidong Wang 	SOC_SINGLE_EXT("Volume Ramp Down Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN,
174094e412c2SWeidong Wang 		aw88166_get_fade_out_time, aw88166_set_fade_out_time),
174194e412c2SWeidong Wang 	SOC_SINGLE_EXT("Calib", 0, 0, AW88166_CALI_RE_MAX, 0,
174294e412c2SWeidong Wang 		aw88166_re_get, aw88166_re_set),
174394e412c2SWeidong Wang 	AW88166_PROFILE_EXT("AW88166 Profile Set", aw88166_profile_info,
174494e412c2SWeidong Wang 		aw88166_profile_get, aw88166_profile_set),
174594e412c2SWeidong Wang };
174694e412c2SWeidong Wang 
aw88166_playback_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * k,int event)174794e412c2SWeidong Wang static int aw88166_playback_event(struct snd_soc_dapm_widget *w,
174894e412c2SWeidong Wang 				struct snd_kcontrol *k, int event)
174994e412c2SWeidong Wang {
175094e412c2SWeidong Wang 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
175194e412c2SWeidong Wang 	struct aw88166 *aw88166 = snd_soc_component_get_drvdata(component);
175294e412c2SWeidong Wang 
175394e412c2SWeidong Wang 	mutex_lock(&aw88166->lock);
175494e412c2SWeidong Wang 	switch (event) {
175594e412c2SWeidong Wang 	case SND_SOC_DAPM_PRE_PMU:
175694e412c2SWeidong Wang 		aw88166_start(aw88166, AW88166_ASYNC_START);
175794e412c2SWeidong Wang 		break;
175894e412c2SWeidong Wang 	case SND_SOC_DAPM_POST_PMD:
175994e412c2SWeidong Wang 		aw88166_stop(aw88166->aw_pa);
176094e412c2SWeidong Wang 		break;
176194e412c2SWeidong Wang 	default:
176294e412c2SWeidong Wang 		break;
176394e412c2SWeidong Wang 	}
176494e412c2SWeidong Wang 	mutex_unlock(&aw88166->lock);
176594e412c2SWeidong Wang 
176694e412c2SWeidong Wang 	return 0;
176794e412c2SWeidong Wang }
176894e412c2SWeidong Wang 
176994e412c2SWeidong Wang static const struct snd_soc_dapm_widget aw88166_dapm_widgets[] = {
177094e412c2SWeidong Wang 	 /* playback */
177194e412c2SWeidong Wang 	SND_SOC_DAPM_AIF_IN_E("AIF_RX", "Speaker_Playback", 0, SND_SOC_NOPM, 0, 0,
177294e412c2SWeidong Wang 					aw88166_playback_event,
177394e412c2SWeidong Wang 					SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
177494e412c2SWeidong Wang 	SND_SOC_DAPM_OUTPUT("DAC Output"),
177594e412c2SWeidong Wang 
177694e412c2SWeidong Wang 	/* capture */
177794e412c2SWeidong Wang 	SND_SOC_DAPM_AIF_OUT("AIF_TX", "Speaker_Capture", 0, SND_SOC_NOPM, 0, 0),
177894e412c2SWeidong Wang 	SND_SOC_DAPM_INPUT("ADC Input"),
177994e412c2SWeidong Wang };
178094e412c2SWeidong Wang 
178194e412c2SWeidong Wang static const struct snd_soc_dapm_route aw88166_audio_map[] = {
178294e412c2SWeidong Wang 	{"DAC Output", NULL, "AIF_RX"},
178394e412c2SWeidong Wang 	{"AIF_TX", NULL, "ADC Input"},
178494e412c2SWeidong Wang };
178594e412c2SWeidong Wang 
aw88166_codec_probe(struct snd_soc_component * component)178694e412c2SWeidong Wang static int aw88166_codec_probe(struct snd_soc_component *component)
178794e412c2SWeidong Wang {
178894e412c2SWeidong Wang 	struct aw88166 *aw88166 = snd_soc_component_get_drvdata(component);
178994e412c2SWeidong Wang 	int ret;
179094e412c2SWeidong Wang 
179194e412c2SWeidong Wang 	INIT_DELAYED_WORK(&aw88166->start_work, aw88166_startup_work);
179294e412c2SWeidong Wang 
179394e412c2SWeidong Wang 	ret = aw88166_request_firmware_file(aw88166);
179494e412c2SWeidong Wang 	if (ret)
179594e412c2SWeidong Wang 		dev_err(aw88166->aw_pa->dev, "%s failed\n", __func__);
179694e412c2SWeidong Wang 
179794e412c2SWeidong Wang 	return ret;
179894e412c2SWeidong Wang }
179994e412c2SWeidong Wang 
aw88166_codec_remove(struct snd_soc_component * aw_codec)180094e412c2SWeidong Wang static void aw88166_codec_remove(struct snd_soc_component *aw_codec)
180194e412c2SWeidong Wang {
180294e412c2SWeidong Wang 	struct aw88166 *aw88166 = snd_soc_component_get_drvdata(aw_codec);
180394e412c2SWeidong Wang 
180494e412c2SWeidong Wang 	cancel_delayed_work_sync(&aw88166->start_work);
180594e412c2SWeidong Wang }
180694e412c2SWeidong Wang 
180794e412c2SWeidong Wang static const struct snd_soc_component_driver soc_codec_dev_aw88166 = {
180894e412c2SWeidong Wang 	.probe = aw88166_codec_probe,
180994e412c2SWeidong Wang 	.remove = aw88166_codec_remove,
181094e412c2SWeidong Wang 	.dapm_widgets = aw88166_dapm_widgets,
181194e412c2SWeidong Wang 	.num_dapm_widgets = ARRAY_SIZE(aw88166_dapm_widgets),
181294e412c2SWeidong Wang 	.dapm_routes = aw88166_audio_map,
181394e412c2SWeidong Wang 	.num_dapm_routes = ARRAY_SIZE(aw88166_audio_map),
181494e412c2SWeidong Wang 	.controls = aw88166_controls,
181594e412c2SWeidong Wang 	.num_controls = ARRAY_SIZE(aw88166_controls),
181694e412c2SWeidong Wang };
181794e412c2SWeidong Wang 
aw88166_hw_reset(struct aw88166 * aw88166)181894e412c2SWeidong Wang static void aw88166_hw_reset(struct aw88166 *aw88166)
181994e412c2SWeidong Wang {
182094e412c2SWeidong Wang 	if (aw88166->reset_gpio) {
182194e412c2SWeidong Wang 		gpiod_set_value_cansleep(aw88166->reset_gpio, 1);
182294e412c2SWeidong Wang 		usleep_range(AW88166_1000_US, AW88166_1000_US + 10);
182394e412c2SWeidong Wang 		gpiod_set_value_cansleep(aw88166->reset_gpio, 0);
182494e412c2SWeidong Wang 		usleep_range(AW88166_1000_US, AW88166_1000_US + 10);
182594e412c2SWeidong Wang 	}
182694e412c2SWeidong Wang }
182794e412c2SWeidong Wang 
aw88166_parse_channel_dt(struct aw88166 * aw88166)182894e412c2SWeidong Wang static void aw88166_parse_channel_dt(struct aw88166 *aw88166)
182994e412c2SWeidong Wang {
183094e412c2SWeidong Wang 	struct aw_device *aw_dev = aw88166->aw_pa;
183194e412c2SWeidong Wang 	struct device_node *np = aw_dev->dev->of_node;
183294e412c2SWeidong Wang 	u32 channel_value;
183394e412c2SWeidong Wang 
183494e412c2SWeidong Wang 	of_property_read_u32(np, "awinic,audio-channel", &channel_value);
183594e412c2SWeidong Wang 	aw_dev->channel = channel_value;
183694e412c2SWeidong Wang 	aw88166->phase_sync = of_property_read_bool(np, "awinic,sync-flag");
183794e412c2SWeidong Wang }
183894e412c2SWeidong Wang 
aw88166_init(struct aw88166 * aw88166,struct i2c_client * i2c,struct regmap * regmap)183994e412c2SWeidong Wang static int aw88166_init(struct aw88166 *aw88166, struct i2c_client *i2c, struct regmap *regmap)
184094e412c2SWeidong Wang {
184194e412c2SWeidong Wang 	struct aw_device *aw_dev;
184294e412c2SWeidong Wang 	unsigned int chip_id;
184394e412c2SWeidong Wang 	int ret;
184494e412c2SWeidong Wang 
184594e412c2SWeidong Wang 	ret = regmap_read(regmap, AW88166_ID_REG, &chip_id);
184694e412c2SWeidong Wang 	if (ret) {
184794e412c2SWeidong Wang 		dev_err(&i2c->dev, "%s read chipid error. ret = %d\n", __func__, ret);
184894e412c2SWeidong Wang 		return ret;
184994e412c2SWeidong Wang 	}
185094e412c2SWeidong Wang 
185194e412c2SWeidong Wang 	aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL);
185294e412c2SWeidong Wang 	if (!aw_dev)
185394e412c2SWeidong Wang 		return -ENOMEM;
185494e412c2SWeidong Wang 	aw88166->aw_pa = aw_dev;
185594e412c2SWeidong Wang 
185694e412c2SWeidong Wang 	aw_dev->i2c = i2c;
185794e412c2SWeidong Wang 	aw_dev->dev = &i2c->dev;
185894e412c2SWeidong Wang 	aw_dev->regmap = regmap;
185994e412c2SWeidong Wang 	mutex_init(&aw_dev->dsp_lock);
186094e412c2SWeidong Wang 
186194e412c2SWeidong Wang 	aw_dev->chip_id = chip_id;
186294e412c2SWeidong Wang 	aw_dev->acf = NULL;
186394e412c2SWeidong Wang 	aw_dev->prof_info.prof_desc = NULL;
186494e412c2SWeidong Wang 	aw_dev->prof_info.count = 0;
186594e412c2SWeidong Wang 	aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID;
186694e412c2SWeidong Wang 	aw_dev->channel = AW88166_DEV_DEFAULT_CH;
186794e412c2SWeidong Wang 	aw_dev->fw_status = AW88166_DEV_FW_FAILED;
186894e412c2SWeidong Wang 
186994e412c2SWeidong Wang 	aw_dev->fade_step = AW88166_VOLUME_STEP_DB;
187094e412c2SWeidong Wang 	aw_dev->volume_desc.ctl_volume = AW88166_VOL_DEFAULT_VALUE;
187194e412c2SWeidong Wang 
187294e412c2SWeidong Wang 	aw88166_parse_channel_dt(aw88166);
187394e412c2SWeidong Wang 
187494e412c2SWeidong Wang 	return 0;
187594e412c2SWeidong Wang }
187694e412c2SWeidong Wang 
aw88166_i2c_probe(struct i2c_client * i2c)187794e412c2SWeidong Wang static int aw88166_i2c_probe(struct i2c_client *i2c)
187894e412c2SWeidong Wang {
187994e412c2SWeidong Wang 	struct aw88166 *aw88166;
188094e412c2SWeidong Wang 	int ret;
188194e412c2SWeidong Wang 
188294e412c2SWeidong Wang 	if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C))
188394e412c2SWeidong Wang 		return dev_err_probe(&i2c->dev, -ENXIO, "check_functionality failed\n");
188494e412c2SWeidong Wang 
188594e412c2SWeidong Wang 	aw88166 = devm_kzalloc(&i2c->dev, sizeof(*aw88166), GFP_KERNEL);
188694e412c2SWeidong Wang 	if (!aw88166)
188794e412c2SWeidong Wang 		return -ENOMEM;
188894e412c2SWeidong Wang 
188994e412c2SWeidong Wang 	mutex_init(&aw88166->lock);
189094e412c2SWeidong Wang 
189194e412c2SWeidong Wang 	i2c_set_clientdata(i2c, aw88166);
189294e412c2SWeidong Wang 
189394e412c2SWeidong Wang 	aw88166->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_LOW);
189494e412c2SWeidong Wang 	if (IS_ERR(aw88166->reset_gpio))
189594e412c2SWeidong Wang 		return dev_err_probe(&i2c->dev, PTR_ERR(aw88166->reset_gpio),
189694e412c2SWeidong Wang 							"reset gpio not defined\n");
189794e412c2SWeidong Wang 	aw88166_hw_reset(aw88166);
189894e412c2SWeidong Wang 
189994e412c2SWeidong Wang 	aw88166->regmap = devm_regmap_init_i2c(i2c, &aw88166_remap_config);
190094e412c2SWeidong Wang 	if (IS_ERR(aw88166->regmap))
190194e412c2SWeidong Wang 		return dev_err_probe(&i2c->dev, PTR_ERR(aw88166->regmap),
190294e412c2SWeidong Wang 							"failed to init regmap\n");
190394e412c2SWeidong Wang 
190494e412c2SWeidong Wang 	/* aw pa init */
190594e412c2SWeidong Wang 	ret = aw88166_init(aw88166, i2c, aw88166->regmap);
190694e412c2SWeidong Wang 	if (ret)
190794e412c2SWeidong Wang 		return ret;
190894e412c2SWeidong Wang 
190994e412c2SWeidong Wang 	return devm_snd_soc_register_component(&i2c->dev,
191094e412c2SWeidong Wang 			&soc_codec_dev_aw88166,
191194e412c2SWeidong Wang 			aw88166_dai, ARRAY_SIZE(aw88166_dai));
191294e412c2SWeidong Wang }
191394e412c2SWeidong Wang 
191494e412c2SWeidong Wang static const struct i2c_device_id aw88166_i2c_id[] = {
191594e412c2SWeidong Wang 	{ AW88166_I2C_NAME },
191694e412c2SWeidong Wang 	{ }
191794e412c2SWeidong Wang };
191894e412c2SWeidong Wang MODULE_DEVICE_TABLE(i2c, aw88166_i2c_id);
191994e412c2SWeidong Wang 
192094e412c2SWeidong Wang static struct i2c_driver aw88166_i2c_driver = {
192194e412c2SWeidong Wang 	.driver = {
192294e412c2SWeidong Wang 		.name = AW88166_I2C_NAME,
192394e412c2SWeidong Wang 	},
192494e412c2SWeidong Wang 	.probe = aw88166_i2c_probe,
192594e412c2SWeidong Wang 	.id_table = aw88166_i2c_id,
192694e412c2SWeidong Wang };
192794e412c2SWeidong Wang module_i2c_driver(aw88166_i2c_driver);
192894e412c2SWeidong Wang 
192994e412c2SWeidong Wang MODULE_DESCRIPTION("ASoC AW88166 Smart PA Driver");
193094e412c2SWeidong Wang MODULE_LICENSE("GPL v2");
1931