From 8612b1897dabeddcb96f08cdb60d92e9ff01642a Mon Sep 17 00:00:00 2001 From: Sandy Huang Date: Sun, 4 Feb 2024 14:09:05 +0800 Subject: [PATCH 1/3] drm/rockchip: drv: Fix ROCKCHIP_BO_CACHABLE flag Invalid The ROCKCHIP_BO_CACHABLE flag first introduced at the following commit: commit 4d89a7383175 ("drm/rockchip: support cpu cache for drm memory") After the follwing commit, the vm_page_prot init be moved to rockchip drm gem driver: commit f8b5307074f8 ("drm/rockchip: Implement mmap as GEM object function") so add this commit to adapt this change. issues info: https://github.com/JeffyCN/mirrors/issues/18 Signed-off-by: Sandy Huang Change-Id: Ic7ae1279c157d02a1ae4758b45934a8506741f67 --- drivers/gpu/drm/rockchip/rockchip_drm_gem.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c index 3a32a03e91f8..d62534849a6f 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c @@ -546,10 +546,6 @@ static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj, int ret; struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj); - /* default is wc. */ - if (rk_obj->flags & ROCKCHIP_BO_CACHABLE) - vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); - /* * Set vm_pgoff (used as a fake buffer offset by DRM) to 0 and map the * whole buffer from the start. @@ -563,7 +559,11 @@ static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj, vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP; vma->vm_flags &= ~VM_PFNMAP; - vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); + /* default is wc. */ + if (rk_obj->flags & ROCKCHIP_BO_CACHABLE) + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); + else + vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); if (rk_obj->buf_type == ROCKCHIP_GEM_BUF_TYPE_SECURE) { From 97edf935a5585931093c248630f188728018d5c0 Mon Sep 17 00:00:00 2001 From: Jason Zhang Date: Mon, 29 Aug 2022 16:01:26 +0800 Subject: [PATCH 2/3] ASoC: codecs: add support for IT6621 The IT6621 is a transmitter designed for HDMI2.1 Enhanced Audio Return Channel (eARC) and it is also backward compatible to the HDMI1.4 Audio Return Channel (ARC). When operating in eARC mode, the Differential Mode Audio Channel (DMAC) bandwidth, i.e. 98.304Mbps, allows HDMI Sink to transmit 8-channel 192K audio to the HDMI Source. No video stream and CEC function is required when eARC link is active. The IT6621 adopts eight I2S and one SPDIF signals for the audio input interface. Eight I2S signals are used to transmit multi-channel L-PCM audio and the maximum 16-channel audio is supported by the IT6621. Change-Id: I50d969a3e08c89a65581671a43b7ae2132ca79ec Signed-off-by: Jason Zhang --- sound/soc/codecs/Kconfig | 1 + sound/soc/codecs/Makefile | 1 + sound/soc/codecs/it6621/Kconfig | 10 + sound/soc/codecs/it6621/Makefile | 3 + sound/soc/codecs/it6621/it6621-clk.c | 319 ++++++ sound/soc/codecs/it6621/it6621-clk.h | 18 + sound/soc/codecs/it6621/it6621-codec.c | 894 ++++++++++++++++ sound/soc/codecs/it6621/it6621-earc.c | 1092 ++++++++++++++++++++ sound/soc/codecs/it6621/it6621-earc.h | 62 ++ sound/soc/codecs/it6621/it6621-reg-bank0.h | 982 ++++++++++++++++++ sound/soc/codecs/it6621/it6621-reg-bank1.h | 147 +++ sound/soc/codecs/it6621/it6621-reg-cec.h | 246 +++++ sound/soc/codecs/it6621/it6621-uapi.c | 364 +++++++ sound/soc/codecs/it6621/it6621-uapi.h | 30 + sound/soc/codecs/it6621/it6621.h | 210 ++++ 15 files changed, 4379 insertions(+) create mode 100644 sound/soc/codecs/it6621/Kconfig create mode 100644 sound/soc/codecs/it6621/Makefile create mode 100644 sound/soc/codecs/it6621/it6621-clk.c create mode 100644 sound/soc/codecs/it6621/it6621-clk.h create mode 100644 sound/soc/codecs/it6621/it6621-codec.c create mode 100644 sound/soc/codecs/it6621/it6621-earc.c create mode 100644 sound/soc/codecs/it6621/it6621-earc.h create mode 100644 sound/soc/codecs/it6621/it6621-reg-bank0.h create mode 100644 sound/soc/codecs/it6621/it6621-reg-bank1.h create mode 100644 sound/soc/codecs/it6621/it6621-reg-cec.h create mode 100644 sound/soc/codecs/it6621/it6621-uapi.c create mode 100644 sound/soc/codecs/it6621/it6621-uapi.h create mode 100644 sound/soc/codecs/it6621/it6621.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a8225756e720..c75b1e9803dd 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -2273,4 +2273,5 @@ config SND_SOC_LPASS_TX_MACRO source "sound/soc/codecs/aw87xxx/Kconfig" source "sound/soc/codecs/aw883xx/Kconfig" +source "sound/soc/codecs/it6621/Kconfig" endmenu diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 3280820af716..b198d18d6209 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -747,6 +747,7 @@ obj-$(CONFIG_SND_SOC_ZL38060) += snd-soc-zl38060.o # Amp obj-$(CONFIG_SND_SOC_AW87XXX) += aw87xxx/ obj-$(CONFIG_SND_SOC_AW883XX) += aw883xx/ +obj-$(CONFIG_SND_SOC_IT6621) += it6621/ obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o obj-$(CONFIG_SND_SOC_MAX98504) += snd-soc-max98504.o obj-$(CONFIG_SND_SOC_SIMPLE_AMPLIFIER) += snd-soc-simple-amplifier.o diff --git a/sound/soc/codecs/it6621/Kconfig b/sound/soc/codecs/it6621/Kconfig new file mode 100644 index 000000000000..e64053b7719f --- /dev/null +++ b/sound/soc/codecs/it6621/Kconfig @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +config SND_SOC_IT6621 + tristate "IT6621 driver for HDMI2.1 enhanced audio return channel (eARC)" + depends on (I2C) + help + Say yes here to build support for ITE IT6621 eARC. + + To compile this driver as a module, choose M here: the module + will be called it6621. diff --git a/sound/soc/codecs/it6621/Makefile b/sound/soc/codecs/it6621/Makefile new file mode 100644 index 000000000000..f559bbcc30ef --- /dev/null +++ b/sound/soc/codecs/it6621/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +it6621-y := it6621-codec.o it6621-clk.o it6621-earc.o it6621-uapi.o +obj-$(CONFIG_SND_SOC_IT6621) += it6621.o diff --git a/sound/soc/codecs/it6621/it6621-clk.c b/sound/soc/codecs/it6621/it6621-clk.c new file mode 100644 index 000000000000..af6c0cecae20 --- /dev/null +++ b/sound/soc/codecs/it6621/it6621-clk.c @@ -0,0 +1,319 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Jason Zhang + */ + +#include "it6621.h" +#include "it6621-clk.h" +#include "it6621-earc.h" +#include "it6621-reg-bank0.h" +#include "it6621-reg-bank1.h" + +static int it6621_get_100ms_cnt(struct it6621_priv *priv, u32 *count) +{ + unsigned int val; + + regmap_write(priv->regmap, IT6621_REG_GEN0, IT6621_100MS_CNT_EN); + msleep(99); + regmap_write(priv->regmap, IT6621_REG_GEN0, IT6621_100MS_CNT_DIS); + regmap_read(priv->regmap, IT6621_REG_100MS_CNT_7_0, &val); + *count = (u32)val; + regmap_read(priv->regmap, IT6621_REG_100MS_CNT_15_8, &val); + *count += ((u32)(val) << 8); + regmap_read(priv->regmap, IT6621_REG_100MS_CNT_23_16, &val); + *count += ((u32)(val) << 16); + + return 0; +} + +static int it6621_get_lcf(struct it6621_priv *priv, unsigned int *lcf) +{ + unsigned int timer_1us_flt; + unsigned int lcf_high; + unsigned int lcf_low; + unsigned int tmp; + + if (priv->fixed_lcf) { + *lcf = priv->fixed_lcf; + dev_info(priv->dev, "lcf: %d\n", *lcf); + } else { + regmap_update_bits(priv->regmap, 0xa9, 0x0f, 0x00); + it6621_get_100ms_cnt(priv, &lcf_low); + + regmap_update_bits(priv->regmap, 0xa9, 0x0f, 0x0f); + it6621_get_100ms_cnt(priv, &lcf_high); + + if (!(lcf_high - lcf_low)) { + dev_err(priv->dev, "Invalid LCF"); + return -EINVAL; + } + + /* Get tenths */ + tmp = (1000000 - lcf_low) * 16 * 10 / (lcf_high - lcf_low); + timer_1us_flt = tmp % 10; + tmp = tmp / 10; + if (timer_1us_flt >= 5) + *lcf = tmp + 1; + else + *lcf = tmp; + + dev_info(priv->dev, "lcf low: %d, lcf high: %d, lcf: %d\n", + lcf_low, lcf_high, *lcf); + } + + if (*lcf > 15) + *lcf = 15; + + return 0; +} + +static int it6621_get_refclk(struct it6621_priv *priv, unsigned int *refclk) +{ + if (priv->rclk_sel == IT6621_RCLK_FREQ_REFCLK) + *refclk = priv->rclk / 2; + else if (priv->rclk_sel == IT6621_RCLK_FREQ_REFCLK_DIV_2) + *refclk = priv->rclk; + else if (priv->rclk_sel == IT6621_RCLK_FREQ_REFCLK_DIV_4) + *refclk = priv->rclk * 2; + else if (priv->rclk_sel == IT6621_RCLK_FREQ_REFCLK_DIV_8) + *refclk = priv->rclk * 4; + else + *refclk = 0; + + return 0; +} + +int it6621_calc_rclk(struct it6621_priv *priv) +{ + unsigned int timer_1us; + unsigned int timer_1us_int; + unsigned int timer_1us_flt; + unsigned int lcf; + unsigned int aclk_bnd_num; + unsigned int aclk_valid_num; + unsigned int sum; + int ret; + + ret = it6621_get_lcf(priv, &lcf); + if (ret) + return ret; + + regmap_update_bits(priv->regmap, 0xa9, 0x0f, lcf); + + it6621_get_100ms_cnt(priv, &sum); + priv->rclk = sum / 100; + dev_dbg(priv->dev, "RCLK: %uMHz\n", priv->rclk / 1000); + + /* Update 1us timer */ + timer_1us = sum / 100000; + timer_1us_int = timer_1us; + timer_1us_flt = sum % 100000; + timer_1us_flt <<= 8; + timer_1us_flt /= 100000; + regmap_write(priv->regmap, IT6621_REG_GEN4, timer_1us_int); + regmap_write(priv->regmap, IT6621_REG_1US_TIME_FLT, timer_1us_flt); + + if (priv->rclk_sel == IT6621_RCLK_FREQ_REFCLK) + sum /= 2; + else if (priv->rclk_sel == IT6621_RCLK_FREQ_REFCLK_DIV_4) + sum *= 2; + else if (priv->rclk_sel == IT6621_RCLK_FREQ_REFCLK_DIV_8) + sum *= 4; + + aclk_bnd_num = sum * 128 / 358400; + aclk_valid_num = sum * 128 / 200000; + regmap_write(priv->regmap, IT6621_REG_CLK_DET0, aclk_bnd_num & 0xff); + regmap_write(priv->regmap, IT6621_REG_CLK_DET1, + (aclk_bnd_num & 0x100) >> 8); + regmap_write(priv->regmap, IT6621_REG_CLK_DET2, + aclk_valid_num & 0xff); + regmap_write(priv->regmap, IT6621_REG_CLK_DET3, + (aclk_valid_num & 0x300) >> 8); + + return 0; +} + +/** + * it6621_force_pdiv() - If auto mode error , FW force to correct PLL's setting + * @priv: The priv device + * + * Returns zero if succeed. + */ +int it6621_force_pdiv(struct it6621_priv *priv) +{ + unsigned int tbclk_sel; + unsigned int xp_pdiv; + unsigned int xp_gain; + unsigned int val; + unsigned int expect; + + regmap_read(priv->regmap, IT6621_REG_CLK_CTRL1, &val); + tbclk_sel = val & IT6621_TBCLK_SEL; + + regmap_read(priv->regmap, IT6621_REG_TX_AFE1, &val); + xp_pdiv = val & IT6621_TX_XP_PDIV; + xp_gain = (val & IT6621_TX_XP_GAIN) >> 2; + + dev_dbg(priv->dev, "ACLK: %d\n", priv->aclk); + + expect = 0xff; + switch (tbclk_sel) { + case IT6621_TBCLK_AICLK_MUL_32: + if (xp_pdiv != 0) + expect = 0; + break; + case IT6621_TBCLK_AICLK_MUL_16: + if ((priv->aclk < 3584) && (xp_pdiv != 0)) + expect = 0; + else if ((priv->aclk > 3584) && (priv->aclk < 7168) && + (xp_pdiv != 1)) + expect = 1; + break; + case IT6621_TBCLK_AICLK_MUL_8: + if ((priv->aclk < 3584) && (xp_pdiv != 0)) + expect = 0; + else if ((priv->aclk > 3584) && (priv->aclk < 7168) && + (xp_pdiv != 1)) + expect = 1; + else if ((priv->aclk > 7168) && (priv->aclk < 14336) && + (xp_pdiv != 3)) + expect = 3; + break; + case IT6621_TBCLK_AICLK_MUL_4: + if ((priv->aclk < 7168) && xp_pdiv != 0) + expect = 0; + else if ((priv->aclk > 7168) && (priv->aclk < 14336) && + (xp_pdiv != 1)) + expect = 1; + else if ((priv->aclk > 14336) && (priv->aclk < 28672) && + (xp_pdiv != 3)) + expect = 3; + break; + case IT6621_TBCLK_AICLK_MUL_2: + if ((priv->aclk < 14336) && xp_pdiv != 0) + expect = 0; + else if ((priv->aclk > 14336) && (priv->aclk < 28672) && + (xp_pdiv != 1)) + expect = 1; + else if ((priv->aclk > 28672) && (priv->aclk < 57334) && + (xp_pdiv != 3)) + expect = 3; + break; + case IT6621_TBCLK_AICLK: + if ((priv->aclk < 28672) && (xp_pdiv != 0)) + expect = 0; + else if ((priv->aclk > 28672) && (priv->aclk < 57334) && + (xp_pdiv != 1)) + expect = 1; + else if ((priv->aclk > 57334) && (priv->aclk < 114668) && + (xp_pdiv != 3)) + expect = 3; + break; + default: + break; + } + + if (expect != 0xff) + dev_warn(priv->dev, "Wrong XP PDIV, detect %d, expected %d\n", + xp_pdiv, expect); + + expect = 0xff; + switch (tbclk_sel) { + case IT6621_TBCLK_AICLK: + if ((priv->aclk > 3584) && (priv->aclk < 7168) && + (xp_gain != 0)) + expect = 0; + break; + case IT6621_TBCLK_AICLK_MUL_2: + if ((priv->aclk < 3584) && (xp_gain != 0)) + expect = 0; + break; + default: + if (xp_gain != 1) + expect = 1; + break; + } + + if (expect != 0xff) + dev_warn(priv->dev, "Wrong XP GAIN, detect %d, expected %d\n", + xp_gain, expect); + + regmap_read(priv->regmap, IT6621_REG_TX_AFE1, &val); + xp_pdiv = val & IT6621_TX_XP_PDIV; + xp_gain = (val & IT6621_TX_XP_GAIN) >> 2; + dev_dbg(priv->dev, "TBCLK SEL: 0x%02X, XP PDIV: %d, XP GAIN: %d\n", + tbclk_sel, xp_pdiv, xp_gain); + + usleep_range(10000, 11000); + regmap_update_bits(priv->regmap, IT6621_REG_DMAC_CTRL1, + IT6621_TX_MANUAL_RESET_EN_SEL, + IT6621_TX_MANUAL_RESET_EN); + regmap_update_bits(priv->regmap, IT6621_REG_DMAC_CTRL1, + IT6621_TX_MANUAL_RESET_EN_SEL, + IT6621_TX_MANUAL_RESET_DIS); + + return 0; +} + +void it6621_get_aclk(struct it6621_priv *priv) +{ + unsigned int aclk_avg; + unsigned int aclk_pred2; + unsigned int aclk_pred4; + unsigned int aclk_valid; + unsigned int aclk_stb; + unsigned int refclk; + unsigned int tmp; + + it6621_get_refclk(priv, &refclk); + + regmap_read(priv->regmap, IT6621_REG_CLK_DET8, &aclk_avg); + regmap_read(priv->regmap, IT6621_REG_CLK_DET9, &tmp); + aclk_avg += ((tmp & IT6621_DET_ACLK_AVG_HIGH) << 8); + aclk_pred2 = (tmp & IT6621_DET_ACLK_PRE_DIV_2) >> 4; + aclk_pred4 = (tmp & IT6621_DET_ACLK_PRE_DIV_4) >> 5; + aclk_valid = (tmp & IT6621_DET_ACLK_FREQ_VALID) >> 6; + aclk_stb = (tmp & IT6621_DET_ACLK_FREQ_STB) >> 7; + + priv->aclk = refclk * 128 / aclk_avg; + + if (aclk_pred4) + priv->aclk *= 4; + else if (aclk_pred2) + priv->aclk *= 2; + + dev_dbg(priv->dev, "ACLK: %uMHz, valid: %d, stable: %d\n", + priv->aclk / 1000, aclk_valid, aclk_stb); +} + +void it6621_get_bclk(struct it6621_priv *priv) +{ + unsigned int bclk_avg; + unsigned int bclk_pred2; + unsigned int bclk_pred4; + unsigned int bclk_valid; + unsigned int bclk_stb; + unsigned int refclk; + unsigned int tmp; + + it6621_get_refclk(priv, &refclk); + + regmap_read(priv->regmap, IT6621_REG_CLK_DET10, &bclk_avg); + regmap_read(priv->regmap, IT6621_REG_CLK_DET11, &tmp); + bclk_avg += ((tmp & IT6621_DET_BCLK_AVG_HIGH) << 8); + bclk_pred2 = (tmp & IT6621_DET_BCLK_PRE_DIV_2) >> 4; + bclk_pred4 = (tmp & IT6621_DET_BCLK_PRE_DIV_4) >> 5; + bclk_valid = (tmp & IT6621_DET_BCLK_FREQ_VALID) >> 6; + bclk_stb = (tmp & IT6621_DET_BCLK_FREQ_STB) >> 7; + + priv->bclk = refclk * 128 / bclk_avg; + + if (bclk_pred4) + priv->bclk *= 4; + else if (bclk_pred2) + priv->bclk *= 2; + + dev_dbg(priv->dev, "BCLK: %uMHz, valid: %d, stable: %d\n", + priv->bclk / 1000, bclk_valid, bclk_stb); +} diff --git a/sound/soc/codecs/it6621/it6621-clk.h b/sound/soc/codecs/it6621/it6621-clk.h new file mode 100644 index 000000000000..58d825d806b3 --- /dev/null +++ b/sound/soc/codecs/it6621/it6621-clk.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Jason Zhang + */ + +#ifndef _IT6621_CLK_H +#define _IT6621_CLK_H + +#include "it6621.h" +#include "it6621-earc.h" + +int it6621_calc_rclk(struct it6621_priv *priv); +int it6621_force_pdiv(struct it6621_priv *priv); +void it6621_get_aclk(struct it6621_priv *priv); +void it6621_get_bclk(struct it6621_priv *priv); + +#endif /* _IT6621_CLK_H */ diff --git a/sound/soc/codecs/it6621/it6621-codec.c b/sound/soc/codecs/it6621/it6621-codec.c new file mode 100644 index 000000000000..58f236510013 --- /dev/null +++ b/sound/soc/codecs/it6621/it6621-codec.c @@ -0,0 +1,894 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * it6621-codec.c -- IT6621 ALSA SoC audio codec driver + * + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Jason Zhang + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "it6621.h" +#include "it6621-clk.h" +#include "it6621-earc.h" +#include "it6621-uapi.h" +#include "it6621-reg-bank0.h" +#include "it6621-reg-bank1.h" +#include "it6621-reg-cec.h" + +#define IT6621_I2C_NAME "it6621" + +static const struct regmap_range_cfg it6621_range = { + .range_min = IT6621_REG_VENDOR_ID_LOW, + .range_max = IT6621_REG_TX_PKT3_PB15, + .selector_reg = IT6621_REG_SYS_CTRL3, + .selector_mask = IT6621_BANK_SEL, + .selector_shift = 0, + .window_start = 0, + .window_len = 256, +}; + +static bool it6621_is_accessible_reg(struct device *dev, unsigned int reg) +{ + if (reg >= IT6621_REG_VENDOR_ID_LOW && reg <= IT6621_REG_TX_PKT3_PB15) + return true; + + return false; +} + +static const struct regmap_config it6621_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = IT6621_REG_TX_PKT3_PB15, + .readable_reg = it6621_is_accessible_reg, + .writeable_reg = it6621_is_accessible_reg, + .ranges = &it6621_range, + .num_ranges = 1, +}; + +static int it6621_set_audio_src(struct it6621_priv *priv) +{ + unsigned int src; + + if (priv->audio_ch >= 15) + src = IT6621_AUD_SRC7_SRC0_EN; + else if (priv->audio_ch >= 13) + src = IT6621_AUD_SRC6_SRC0_EN; + else if (priv->audio_ch >= 11) + src = IT6621_AUD_SRC5_SRC0_EN; + else if (priv->audio_ch >= 9) + src = IT6621_AUD_SRC4_SRC0_EN; + else if (priv->audio_ch >= 7 || priv->i2s_hbr) + src = IT6621_AUD_SRC3_SRC0_EN; + else if (priv->audio_ch >= 5) + src = IT6621_AUD_SRC2_SRC0_EN; + else if (priv->audio_ch >= 3) + src = IT6621_AUD_SRC1_SRC0_EN; + else + src = IT6621_AUD_SRC0_EN; + + /* Set input audio source */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_AUD_SRC_SEL, + IT6621_TX_AUD_SRC, priv->audio_src); + + /* Update source number */ + regmap_write(priv->regmap, IT6621_REG_TX_AUD_SRC_EN, src); + + /* Update ACLK detect after changing source number */ + regmap_update_bits(priv->regmap, IT6621_REG_CLK_DET7, + IT6621_ACLK_DET_EN_SEL, IT6621_ACLK_DET_DIS); + regmap_update_bits(priv->regmap, IT6621_REG_CLK_DET7, + IT6621_ACLK_DET_EN_SEL, IT6621_ACLK_DET_EN); + + return 0; +} + +static int it6621_set_i2s_tdm_fmt(struct it6621_priv *priv) +{ + unsigned int wl; + + if ((priv->i2s_wl == IEC958_AES4_CON_WORDLEN_24_20) || + (priv->i2s_wl == (IEC958_AES4_CON_WORDLEN_20_16 | + IEC958_AES4_CON_MAX_WORDLEN_24))) + wl = IT6621_I2S_TDM_20BIT; + else if (priv->i2s_wl == (IEC958_AES4_CON_WORDLEN_24_20 | + IEC958_AES4_CON_MAX_WORDLEN_24)) + wl = IT6621_I2S_TDM_24BIT; + else + wl = IT6621_I2S_TDM_16BIT; + + regmap_update_bits(priv->regmap, IT6621_REG_TX_I2S, + IT6621_I2S_TDM_WORD_LEN | IT6621_I2S_FMT, + wl | priv->i2s_fmt); + + regmap_update_bits(priv->regmap, IT6621_REG_TX_AUD_CTRL3, + IT6621_TX_I2S_HBR_EN_SEL | IT6621_TX_TDM_CH_NUM, + priv->i2s_hbr | ((priv->audio_ch / 2) - 1)); + + return 0; +} + +static int it6621_set_spdif_fmt(struct it6621_priv *priv) +{ + if (priv->audio_type == IT6621_AUD_TYPE_NLPCM) + regmap_update_bits(priv->regmap, IT6621_REG_DMAC_CTRL1, + IT6621_TX_V_BIT_VAL, IT6621_TX_V_BIT_NLPCM); + else + regmap_update_bits(priv->regmap, IT6621_REG_DMAC_CTRL1, + IT6621_TX_V_BIT_VAL, IT6621_TX_V_BIT_LPCM); + + return 0; +} + +static int it6621_set_auto_audio_fmt(struct it6621_priv *priv) +{ + unsigned int auto_fmt; + + if ((priv->audio_type == IT6621_AUD_TYPE_NLPCM) && + (priv->audio_ch == 8)) { + auto_fmt = IT6621_TX_AUTO_AUD_FMT_DIS; + } else { + /* NOTE: Disable auto audio format in SPDIF */ + if (priv->audio_src == IT6621_AUD_SRC_SPDIF) + auto_fmt = IT6621_TX_AUTO_AUD_FMT_DIS; + else + auto_fmt = IT6621_TX_AUTO_AUD_FMT_EN; + } + + regmap_update_bits(priv->regmap, IT6621_REG_TX_AUD_CTRL10, + IT6621_TX_AUTO_AUD_FMT_SEL, auto_fmt); + + return 0; +} + +static int it6621_set_audio_fmt(struct it6621_priv *priv) +{ + int ret; + + /* Set audio source */ + ret = it6621_set_audio_src(priv); + if (ret < 0) + return ret; + + /* RX I2S/TDM word length */ + ret = it6621_set_i2s_tdm_fmt(priv); + if (ret < 0) + return ret; + + /* SPDIF V bit */ + ret = it6621_set_spdif_fmt(priv); + if (ret < 0) + return ret; + + /* For Compress audio LayoutB */ + ret = it6621_set_auto_audio_fmt(priv); + if (ret < 0) + return ret; + + /* eARC TX Channel Status */ + ret = it6621_set_channel_status(priv); + if (ret < 0) + return ret; + + return 0; +} + +static int it6621_update_config(struct it6621_priv *priv) +{ + if (priv->force_16ch) + priv->audio_ch = 16; + + if ((priv->audio_fs == IT6621_AES3_CON_FS_256000) || + (priv->audio_fs == IT6621_AES3_CON_FS_352000) || + (priv->audio_fs == IT6621_AES3_CON_FS_384000) || + (priv->audio_fs == IT6621_AES3_CON_FS_512000) || + (priv->audio_fs == IT6621_AES3_CON_FS_705000) || + (priv->audio_fs == IEC958_AES3_CON_FS_768000) || + (priv->audio_fs == IT6621_AES3_CON_FS_1024000) || + (priv->audio_fs == IT6621_AES3_CON_FS_1411000) || + (priv->audio_fs == IT6621_AES3_CON_FS_1536000)) + priv->audio_hbr = 1; + else + priv->audio_hbr = 0; + + if (priv->audio_input_hbr == 1) + priv->audio_hbr = 1; + + if (priv->audio_hbr) + priv->audio_type = IT6621_AUD_TYPE_NLPCM; + + if ((priv->audio_src == IT6621_AUD_SRC_I2S) && + priv->audio_hbr && priv->i2s_hbr_enabled) + priv->i2s_hbr = IT6621_TX_I2S_HBR_EN; + else + priv->i2s_hbr = IT6621_TX_I2S_HBR_DIS; + + if ((priv->audio_src == IT6621_AUD_SRC_I2S) && + (priv->audio_type == IT6621_AUD_TYPE_NLPCM)) + priv->i2s_nlpcm_enabled = IT6621_TX_NLPCM_I2S_EN; + else + priv->i2s_nlpcm_enabled = IT6621_TX_NLPCM_I2S_DIS; + + /* NOTE: For Allion AC3 and Allion Astro VG849C test. */ + if ((priv->audio_ch > 2) && + (priv->audio_type == IT6621_AUD_TYPE_NLPCM)) + priv->audio_ch = 2; + + regmap_update_bits(priv->regmap, IT6621_REG_TX_AUD_CTRL10, + IT6621_TX_2CH_LAYOUT_SEL | IT6621_TX_NLPCM_I2S_SEL | + IT6621_TX_MCH_LPCM_SEL | IT6621_TX_EXT_MUTE_SEL, + IT6621_TX_2CH_LAYOUT_DIS | priv->i2s_nlpcm_enabled | + IT6621_TX_MCH_LPCM_DIS | IT6621_TX_EXT_MUTE_EN); + return 0; +} + +static int it6621_reconfig_aclk(struct it6621_priv *priv) +{ + if (((priv->audio_src == IT6621_AUD_SRC_I2S) && priv->sck_inv_enabled) || + ((priv->audio_src == IT6621_AUD_SRC_TDM) && priv->tck_inv_enabled) || + ((priv->audio_src == IT6621_AUD_SRC_SPDIF) && priv->mclk_inv_enabled) || + ((priv->audio_src == IT6621_AUD_SRC_DSD) && priv->dclk_inv_enabled)) + regmap_update_bits(priv->regmap, IT6621_REG_CLK_CTRL2, + IT6621_ACLK_INV_SEL, IT6621_ACLK_INV_EN); + else + regmap_update_bits(priv->regmap, IT6621_REG_CLK_CTRL2, + IT6621_ACLK_INV_SEL, IT6621_ACLK_INV_DIS); + + return 0; +} + +static int it6621_config_audio(struct it6621_priv *priv) +{ + int ret; + + ret = it6621_update_config(priv); + if (ret < 0) + return ret; + + ret = it6621_reconfig_aclk(priv); + if (ret < 0) + return ret; + + ret = it6621_set_audio_fmt(priv); + if (ret < 0) + return ret; + + return 0; +} + +static int it6621_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct it6621_priv *priv = snd_soc_component_get_drvdata(dai->component); + unsigned int state; + + if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) + return 0; + + set_bit(IT6621_AUDIO_START, &priv->audio_flag); + clear_bit(IT6621_AUDIO_TO_EN_DMAC, &priv->audio_flag); + + it6621_get_ddfsm_state(priv, &state); + + if ((state != IT6621_TX_EARC_MODE) && (state != IT6621_TX_ARC_MODE)) { + cancel_work_sync(&priv->hpdio_work); + schedule_work(&priv->hpdio_work); + } + + priv->config_audio = true; + + return 0; +} + +static int it6621_mute(struct snd_soc_dai *dai, int mute, int stream) +{ + struct it6621_priv *priv = snd_soc_component_get_drvdata(dai->component); + + if (stream != SNDRV_PCM_STREAM_PLAYBACK) + return 0; + + if (!priv->force_mute) + return 0; + + /* FIXME: Sometimes unmuting stream does not work */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_AUD_CTRL10, + IT6621_TX_FORCE_MUTE_SEL, + mute ? IT6621_TX_FORCE_MUTE_EN : + IT6621_TX_FORCE_MUTE_DIS); + + return 0; +} + +static void it6621_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct it6621_priv *priv = snd_soc_component_get_drvdata(dai->component); + + clear_bit(IT6621_AUDIO_START, &priv->audio_flag); + clear_bit(IT6621_AUDIO_TO_EN_DMAC, &priv->audio_flag); +} + +static int it6621_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct it6621_priv *priv = snd_soc_dai_get_drvdata(dai); + int ret = 0; + + if (!freq) + return 0; + + ret = clk_set_rate(priv->mclk, freq); + if (ret) + dev_err(priv->dev, "failed to set mclk\n"); + + return ret; +} + +static int it6621_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct it6621_priv *priv = snd_soc_dai_get_drvdata(dai); + unsigned int fs; + unsigned int wl; + unsigned int ch; + int ret; + + switch (snd_pcm_rate_to_rate_bit(params_rate(params))) { + case SNDRV_PCM_RATE_32000: + fs = IEC958_AES3_CON_FS_32000; + break; + case SNDRV_PCM_RATE_44100: + fs = IEC958_AES3_CON_FS_44100; + break; + case SNDRV_PCM_RATE_48000: + fs = IEC958_AES3_CON_FS_48000; + break; + case SNDRV_PCM_RATE_64000: + fs = IT6621_AES3_CON_FS_64000; + break; + case SNDRV_PCM_RATE_88200: + fs = IEC958_AES3_CON_FS_88200; + break; + case SNDRV_PCM_RATE_96000: + fs = IEC958_AES3_CON_FS_96000; + break; + case SNDRV_PCM_RATE_176400: + fs = IEC958_AES3_CON_FS_176400; + break; + case SNDRV_PCM_RATE_192000: + fs = IEC958_AES3_CON_FS_192000; + break; + case SNDRV_PCM_RATE_352800: + fs = IT6621_AES3_CON_FS_352000; + break; + case SNDRV_PCM_RATE_384000: + fs = IT6621_AES3_CON_FS_384000; + break; + default: + dev_err(priv->dev, "invalid rate: %d\n", params_rate(params)); + return -EINVAL; + } + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + wl = IEC958_AES4_CON_WORDLEN_20_16; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + wl = IEC958_AES4_CON_WORDLEN_24_20; + break; + case SNDRV_PCM_FORMAT_S24_LE: + wl = IEC958_AES4_CON_WORDLEN_24_20 | + IEC958_AES4_CON_MAX_WORDLEN_24; + break; + default: + dev_err(priv->dev, "invalid format: %d\n", + params_format(params)); + return -EINVAL; + } + + switch (params_channels(params)) { + case 32: + case 16: + case 8: + case 6: + case 2: + ch = params_channels(params); + break; + default: + dev_err(priv->dev, "invalid channel: %d\n", + params_channels(params)); + return -EINVAL; + } + + if (priv->config_audio || (priv->audio_fs != fs) || + (priv->i2s_wl != wl) || (priv->audio_ch != ch)) { + priv->audio_fs = fs; + priv->i2s_wl = wl; + priv->audio_ch = ch; + priv->config_audio = false; + + ret = it6621_config_audio(priv); + if (ret) + return ret; + } + + return 0; +} + +static int it6621_probe(struct snd_soc_component *component) +{ + struct it6621_priv *priv; + + priv = snd_soc_component_get_drvdata(component); + priv->mclk = devm_clk_get_optional(component->dev, "mclk"); + + if (IS_ERR(priv->mclk)) + return PTR_ERR(priv->mclk); + + clk_prepare_enable(priv->mclk); + + return 0; +} + +static int it6621_suspend(struct snd_soc_component *component) +{ + struct it6621_priv *priv = snd_soc_component_get_drvdata(component); + + clear_bit(IT6621_ARC_START, &priv->events); + clear_bit(IT6621_EARC_CAP_CHG, &priv->events); + clear_bit(IT6621_EARC_EDID_OK, &priv->events); + clear_bit(IT6621_EARC_BCLK_OK, &priv->events); + + return 0; +} + +static int it6621_resume(struct snd_soc_component *component) +{ + struct it6621_priv *priv = snd_soc_component_get_drvdata(component); + + return it6621_earc_init(priv); +} + +static int it6621_audio_cap_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = sizeof_field(struct it6621_priv, rxcap); + + return 0; +} + +static int it6621_audio_cap_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct it6621_priv *priv = snd_soc_component_get_drvdata(component); + + mutex_lock(&priv->rxcap_lock); + memcpy(ucontrol->value.bytes.data, priv->rxcap, sizeof(priv->rxcap)); + mutex_unlock(&priv->rxcap_lock); + + return 0; +} + +static const char *const it6621_ddfsm_enum[] = { "ARC", "eARC", "unknown" }; + +static int it6621_ddfsm_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = ARRAY_SIZE(it6621_ddfsm_enum); + + if (uinfo->value.enumerated.item >= ARRAY_SIZE(it6621_ddfsm_enum)) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + + strscpy(uinfo->value.enumerated.name, + it6621_ddfsm_enum[uinfo->value.enumerated.item], + sizeof(uinfo->value.enumerated.name)); + + return 0; +} + +static int it6621_ddfsm_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct it6621_priv *priv = snd_soc_component_get_drvdata(component); + unsigned int state; + + it6621_get_ddfsm_state(priv, &state); + + if (state == IT6621_TX_ARC_MODE) + ucontrol->value.enumerated.item[0] = 0; + else if (state == IT6621_TX_EARC_MODE) + ucontrol->value.enumerated.item[0] = 1; + else + ucontrol->value.enumerated.item[0] = 2; + + return 0; +} + +static int it6621_earc_switch_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + + return 0; +} + +static int it6621_earc_switch_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct it6621_priv *priv = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = (priv->earc_enabled == + IT6621_TX_EARC_EN) ? 1 : 0; + + return 0; +} + +static int it6621_earc_switch_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct it6621_priv *priv = snd_soc_component_get_drvdata(component); + + return it6621_set_earc_enabled(priv, !!ucontrol->value.integer.value[0]); +} + +static int it6621_arc_switch_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + + return 0; +} + +static int it6621_arc_switch_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct it6621_priv *priv = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = (priv->arc_enabled == + IT6621_TX_ARC_EN) ? 1 : 0; + + return 0; +} + +static int it6621_arc_switch_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct it6621_priv *priv = snd_soc_component_get_drvdata(component); + + return it6621_set_arc_enabled(priv, !!ucontrol->value.integer.value[0]); +} + +static const struct snd_kcontrol_new it6621_controls[] = { + { + .access = (SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE), + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "eARC Audio Capabilities", + .info = it6621_audio_cap_ctl_info, + .get = it6621_audio_cap_ctl_get, + }, + { + .access = (SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE), + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "eARC DD FSM", + .info = it6621_ddfsm_ctl_info, + .get = it6621_ddfsm_ctl_get, + }, + { + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_VOLATILE), + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "eARC Switch", + .info = it6621_earc_switch_ctl_info, + .get = it6621_earc_switch_ctl_get, + .put = it6621_earc_switch_ctl_put, + }, + { + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_VOLATILE), + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "ARC Switch", + .info = it6621_arc_switch_ctl_info, + .get = it6621_arc_switch_ctl_get, + .put = it6621_arc_switch_ctl_put, + }, +}; + +static const struct snd_soc_component_driver it6621_component = { + .probe = it6621_probe, + .suspend = it6621_suspend, + .resume = it6621_resume, + .controls = it6621_controls, + .num_controls = ARRAY_SIZE(it6621_controls), +}; + +static const struct snd_soc_dai_ops it6621_dai_ops = { + .startup = it6621_startup, + .set_sysclk = it6621_set_dai_sysclk, + .hw_params = it6621_hw_params, + .mute_stream = it6621_mute, + .shutdown = it6621_shutdown, +}; + +#define IT6621_RATES (SNDRV_PCM_RATE_32000 | \ + SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_64000 | \ + SNDRV_PCM_RATE_88200 | \ + SNDRV_PCM_RATE_96000 | \ + SNDRV_PCM_RATE_176400 | \ + SNDRV_PCM_RATE_192000 | \ + SNDRV_PCM_RATE_352800 | \ + SNDRV_PCM_RATE_384000) + +#define IT6621_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_driver it6621_dais[] = { + { + .name = "it6621-i2s", + .playback = { + .stream_name = "IT6621 I2S Playback", + .channels_min = 2, + .channels_max = 16, + .rates = IT6621_RATES, + .formats = IT6621_FORMATS, + }, + .ops = &it6621_dai_ops, + }, { + .name = "it6621-spdif", + .playback = { + .stream_name = "IT6621 SPDIF Playback", + .channels_min = 2, + .channels_max = 2, + .rates = IT6621_RATES, + .formats = IT6621_FORMATS, + }, + .ops = &it6621_dai_ops, + }, { + .name = "it6621-dsd", + .playback = { + .stream_name = "IT6621 DSD Playback", + .channels_min = 2, + .channels_max = 12, + .rates = IT6621_RATES, + .formats = IT6621_FORMATS, + }, + .ops = &it6621_dai_ops, + }, +}; + +static int it6621_check_dev(struct it6621_priv *priv) +{ + unsigned int val; + + regmap_bulk_read(priv->regmap, IT6621_REG_VENDOR_ID_LOW, &val, 2); + priv->vid = le16_to_cpu(val); + if (priv->vid != IT6621_VENDOR_ID) { + dev_err(priv->dev, "invalid vendor id %x\n", priv->vid); + return -ENODEV; + } + + regmap_bulk_read(priv->regmap, IT6621_REG_DEV_ID_LOW, &val, 2); + priv->devid = le16_to_cpu(val); + if (priv->devid != IT6621_DEVICE_ID) { + dev_err(priv->dev, "invalid device id %x\n", priv->devid); + return -ENODEV; + } + + regmap_read(priv->regmap, IT6621_REG_REV_ID, &val); + priv->revid = val; + + if ((priv->revid != IT6621_REVISION_VARIANT_B0) && + (priv->revid != IT6621_REVISION_VARIANT_C0) && + (priv->revid != IT6621_REVISION_VARIANT_D0)) { + dev_err(priv->dev, "invalid revision id %x\n", priv->revid); + return -ENODEV; + } + + return 0; +} + +static void it6621_toggle_hpdio(struct it6621_priv *priv) +{ + mutex_lock(&priv->hpdio_lock); + + dev_dbg(priv->dev, "toggle hpdio\n"); + gpiod_set_value_cansleep(priv->hpdio, 0); + /* + * NOTE: Toggle HPD signal at least 100ms (suggestion time is about + * 1 ~ 1.5 second). + */ + msleep(100); + gpiod_set_value_cansleep(priv->hpdio, 1); + + mutex_unlock(&priv->hpdio_lock); +} + +static void it6621_hpdio_work(struct work_struct *work) +{ + struct it6621_priv *priv = container_of(work, struct it6621_priv, + hpdio_work); + + it6621_toggle_hpdio(priv); +} + +static int it6621_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct it6621_priv *priv; + const char *source; + int ret; + + priv = devm_kzalloc(&client->dev, sizeof(struct it6621_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + dev_set_drvdata(&client->dev, priv); + + priv->client = client; + priv->dev = &client->dev; + priv->regmap = devm_regmap_init_i2c(client, &it6621_regmap_config); + if (IS_ERR(priv->regmap)) { + dev_err(priv->dev, "failed to initialize regmap\n"); + return PTR_ERR(priv->regmap); + } + + ret = it6621_check_dev(priv); + if (ret < 0) + return ret; + + priv->audio_type = IT6621_AUD_TYPE_LPCM; + priv->audio_ch = 0; + priv->audio_fs = IEC958_AES3_CON_FS_NOTID; + priv->i2s_wl = IEC958_AES4_CON_WORDLEN_NOTID; + priv->mch_lpcm_enabled = IT6621_TX_MCH_LPCM_DIS; + priv->layout_2ch_enabled = IT6621_TX_2CH_LAYOUT_DIS; + priv->vcm_sel = IT6621_TX_VCM0; + priv->i2s_fmt = IT6621_I2S_FMT_32BIT; + priv->rclk_sel = IT6621_RCLK_FREQ_REFCLK_DIV_2; + priv->update_avg_enabled = IT6621_UPDATE_AVG_EN; + priv->sck_inv_enabled = 0; + priv->tck_inv_enabled = 1; + priv->mclk_inv_enabled = 1; + priv->dclk_inv_enabled = 0; + priv->cmo_opt = IT6621_TX_CMO_NORMAL; + priv->force_cmo_enabled = IT6621_TX_FORCE_CMO_EN; + priv->resync_opt = IT6621_TX_RESYNC_NEW; + priv->pkt1_enabled = IT6621_TX_PKT1_DIS; + priv->pkt2_enabled = IT6621_TX_PKT2_DIS; + priv->pkt3_enabled = IT6621_TX_PKT3_DIS; + priv->i2s_hbr_enabled = 1; + priv->ubit_opt = IT6621_TX_U_BIT_1BIT_FRAME; + priv->c_ch_opt = IT6621_TX_C_CH_OPT1; + priv->ecc_opt = IT6621_TX_ECC_U_SWAP; + priv->enc_seed = 0xa5c3; + priv->enc_opt = IT6621_TX_ENC_OPT3; + priv->bclk_inv_enabled = IT6621_BCLK_INV_DIS; + priv->nxt_pkt_to_sel = IT6621_TX_NEXT_PKT_TIMEOUT_50US; + priv->turn_over_sel = IT6621_TX_TURN_OVER_16US; + priv->hb_retry_sel = IT6621_TX_HB_RETRY_0MS; + priv->hb_retry_enabled = IT6621_TX_HB_RETRY_EN; + priv->cmd_to_enabled = 0; + priv->enter_arc_now = IT6621_TX_ARC_NOW_DIS; + priv->arc_enabled = IT6621_TX_ARC_EN; + priv->earc_enabled = IT6621_TX_EARC_EN; + INIT_LIST_HEAD(&priv->fhs); + mutex_init(&priv->fhs_lock); + mutex_init(&priv->hpdio_lock); + mutex_init(&priv->rxcap_lock); + INIT_WORK(&priv->hpdio_work, it6621_hpdio_work); + + ret = it6621_uapi_init(priv); + if (ret) { + dev_err(priv->dev, "failed to initialize uapi\n"); + return ret; + } + + ret = devm_add_action_or_reset(priv->dev, + (void(*)(void *))it6621_uapi_remove, + priv); + if (ret) + return ret; + + ret = device_property_read_string(priv->dev, "ite,audio-source", + &source); + if (ret) { + dev_err(priv->dev, "no input audio source\n"); + return ret; + } + + if (!strcmp(source, "i2s")) + priv->audio_src = IT6621_AUD_SRC_I2S; + else if (!strcmp(source, "spdif")) + priv->audio_src = IT6621_AUD_SRC_SPDIF; + else if (!strcmp(source, "tdm")) + priv->audio_src = IT6621_AUD_SRC_TDM; + else if (!strcmp(source, "dsd")) + priv->audio_src = IT6621_AUD_SRC_DSD; + else + return -EINVAL; + + if (device_property_read_bool(priv->dev, "ite,force-arc")) + priv->force_arc = 1; + + if (device_property_read_bool(priv->dev, "ite,force-earc")) + priv->force_earc = 1; + + if (device_property_read_u32(priv->dev, "ite,fixed-lcf", + &priv->fixed_lcf)) + priv->fixed_lcf = 0x00; + + priv->hpdio = devm_gpiod_get_optional(&client->dev, "hpdio", + GPIOD_OUT_LOW); + + ret = it6621_earc_init(priv); + if (ret) + return ret; + + if (client->irq) { + ret = devm_request_threaded_irq(priv->dev, client->irq, NULL, + it6621_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "it6621", priv); + if (ret) + return ret; + } + + return devm_snd_soc_register_component(priv->dev, &it6621_component, + it6621_dais, + ARRAY_SIZE(it6621_dais)); +} + +static const struct i2c_device_id it6621_i2c_id[] = { + { IT6621_I2C_NAME, 0 }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(i2c, it6621_i2c_id); + +static const struct of_device_id it6621_dt_match[] = { + { .compatible = "ite,it6621" }, + { /* sentinel */ }, +}; + +static struct i2c_driver it6621_i2c_driver = { + .driver = { + .name = IT6621_I2C_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(it6621_dt_match), + }, + .probe = it6621_i2c_probe, + .id_table = it6621_i2c_id, +}; + +module_i2c_driver(it6621_i2c_driver); + +MODULE_AUTHOR("Jason Zhang "); +MODULE_DESCRIPTION("ASoC IT6621 eARC Driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/it6621/it6621-earc.c b/sound/soc/codecs/it6621/it6621-earc.c new file mode 100644 index 000000000000..56d5227f6dd1 --- /dev/null +++ b/sound/soc/codecs/it6621/it6621-earc.c @@ -0,0 +1,1092 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Jason Zhang + */ + +#include +#include + +#include "it6621.h" +#include "it6621-clk.h" +#include "it6621-earc.h" +#include "it6621-reg-bank0.h" +#include "it6621-reg-bank1.h" +#include "it6621-reg-cec.h" +#include "it6621-uapi.h" + +int it6621_set_channel_status(struct it6621_priv *priv) +{ + unsigned int layout = 0; + unsigned int ca = 0; + unsigned int fmt = 0; + unsigned int wl = 0; + unsigned int fs = 0; + + /* NOTE: Add for Category code */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_CH_ST1, 0xff, + IEC958_AES1_CON_PCM_CODER); + + /* Refer to HDMI2.1 spec table 9-23 and ICE60958-3 p9 */ + if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) && + (priv->audio_ch == 2) && (priv->audio_enc == 0) && + (priv->mch_lpcm_enabled == IT6621_TX_MCH_LPCM_DIS) && + (priv->i2s_nlpcm_enabled == IT6621_TX_NLPCM_I2S_DIS)) + fmt = HDMI_AUDIO_FMT_UN_2CH_LPCM; + else if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) && + (priv->audio_ch == 2) && (priv->audio_enc == 0) && + (priv->mch_lpcm_enabled == IT6621_TX_MCH_LPCM_EN)) + fmt = HDMI_AUDIO_FMT_UN_MCH_LPCM; + else if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) && + (priv->audio_ch > 2) && (priv->audio_enc == 0)) + fmt = HDMI_AUDIO_FMT_UN_MCH_LPCM; + else if ((priv->audio_type == IT6621_AUD_TYPE_DSD) && + (priv->audio_enc == 0)) + fmt = HDMI_AUDIO_FMT_UN_XCH_DSD; + else if ((priv->audio_type == IT6621_AUD_TYPE_NLPCM) && + (priv->audio_enc == 0)) + fmt = HDMI_AUDIO_FMT_UN_2CH_NLPCM; + else if ((priv->audio_type == IT6621_AUD_TYPE_NLPCM) && + (priv->audio_enc == 1)) + fmt = HDMI_AUDIO_FMT_EN_2CH_NLPCM; + else if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) && + (priv->audio_enc == 1)) + fmt = HDMI_AUDIO_FMT_EN_MCH_NLPCM; + else if ((priv->audio_type == IT6621_AUD_TYPE_DSD) && + (priv->audio_enc == 1)) + fmt = HDMI_AUDIO_FMT_EN_XCH_DSD; + else + dev_err(priv->dev, "invalid audio format\n"); + + /* + * NOTE: Software for which copyright is asserted, Channel status mode + * is set to mode 0, and audio format is set with fmt. + */ + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST0, + ((fmt & 0x1c) << 1) | (fmt & 0x03)); + + /* Refer to IEC60958-3 p12 */ + if (priv->audio_src == IT6621_AUD_SRC_DSD) + wl = IEC958_AES4_CON_WORDLEN_NOTID; + else if (priv->audio_type == IT6621_AUD_TYPE_NLPCM) + wl = IEC958_AES4_CON_WORDLEN_20_16; + else + wl = priv->i2s_wl; + + /* NOTE: Set sample word length */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_CH_ST4, 0x0f, wl); + + /* Refer to HDMI2.1 spec table 9-25 and IEC60958-3 p12 */ + if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) && + (priv->audio_ch <= 2)) + layout = HDMI_AUDIO_LAYOUT_LPCM_2CH; + else if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) && + (priv->audio_ch <= 8)) + layout = HDMI_AUDIO_LAYOUT_LPCM_8CH; + else if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) && + (priv->audio_ch <= 16)) + layout = HDMI_AUDIO_LAYOUT_LPCM_16CH; + else if ((priv->audio_type == IT6621_AUD_TYPE_NLPCM) && + (priv->audio_ch <= 2)) + layout = HDMI_AUDIO_LAYOUT_NLPCM_2CH; + else if ((priv->audio_type == IT6621_AUD_TYPE_NLPCM) && + (priv->audio_ch <= 8)) + layout = HDMI_AUDIO_LAYOUT_NLPCM_8CH; + else if ((priv->audio_type == IT6621_AUD_TYPE_DSD) && + (priv->audio_ch <= 6)) + layout = HDMI_AUDIO_LAYOUT_DSD_6CH; + else if ((priv->audio_type == IT6621_AUD_TYPE_DSD) && + (priv->audio_ch <= 12)) + layout = HDMI_AUDIO_LAYOUT_DSD_12CH; + else + dev_err(priv->dev, "invalid layout\n"); + + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST5, layout << 4); + + /* Refer to HDMI2.0 spec, IEC60958-3 p11 and p12 */ + if ((layout == HDMI_AUDIO_LAYOUT_LPCM_2CH) || + (layout == HDMI_AUDIO_LAYOUT_NLPCM_2CH)) { + fs = priv->audio_fs; + } else if ((layout == HDMI_AUDIO_LAYOUT_LPCM_8CH) || + (layout == HDMI_AUDIO_LAYOUT_NLPCM_8CH)) { + if (priv->audio_fs == IEC958_AES3_CON_FS_32000) + fs = IT6621_AES3_CON_FS_128000; + else if (priv->audio_fs == IEC958_AES3_CON_FS_44100) + fs = IEC958_AES3_CON_FS_176400; + else if (priv->audio_fs == IEC958_AES3_CON_FS_48000) + fs = IEC958_AES3_CON_FS_192000; + else if (priv->audio_fs == IT6621_AES3_CON_FS_64000) + fs = IT6621_AES3_CON_FS_256000; + else if (priv->audio_fs == IEC958_AES3_CON_FS_88200) + fs = IT6621_AES3_CON_FS_352000; + else if (priv->audio_fs == IEC958_AES3_CON_FS_96000) + fs = IT6621_AES3_CON_FS_384000; + else if (priv->audio_fs == IT6621_AES3_CON_FS_128000) + fs = IT6621_AES3_CON_FS_512000; + else if (priv->audio_fs == IEC958_AES3_CON_FS_176400) + fs = IT6621_AES3_CON_FS_705000; + else if (priv->audio_fs == IEC958_AES3_CON_FS_192000) + fs = IEC958_AES3_CON_FS_768000; + else + dev_err(priv->dev, "invalid fs and channel\n"); + } else if ((layout == HDMI_AUDIO_LAYOUT_LPCM_16CH) || + (layout == HDMI_AUDIO_LAYOUT_DSD_6CH)) { + if (priv->audio_fs == IEC958_AES3_CON_FS_32000) + fs = IT6621_AES3_CON_FS_256000; + else if (priv->audio_fs == IEC958_AES3_CON_FS_44100) + fs = IT6621_AES3_CON_FS_352000; + else if (priv->audio_fs == IEC958_AES3_CON_FS_48000) + fs = IT6621_AES3_CON_FS_384000; + else if (priv->audio_fs == IT6621_AES3_CON_FS_64000) + fs = IT6621_AES3_CON_FS_512000; + else if (priv->audio_fs == IEC958_AES3_CON_FS_88200) + fs = IT6621_AES3_CON_FS_705000; + else if (priv->audio_fs == IEC958_AES3_CON_FS_96000) + fs = IEC958_AES3_CON_FS_768000; + else + dev_err(priv->dev, "invalid fs and channel\n"); + } else if (layout == HDMI_AUDIO_LAYOUT_DSD_12CH) { + if (priv->audio_fs == IEC958_AES3_CON_FS_32000) + fs = IT6621_AES3_CON_FS_512000; + else if (priv->audio_fs == IEC958_AES3_CON_FS_44100) + fs = IT6621_AES3_CON_FS_705000; + else if (priv->audio_fs == IEC958_AES3_CON_FS_48000) + fs = IEC958_AES3_CON_FS_768000; + else + dev_err(priv->dev, "invalid fs and channel\n"); + } + + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST3, + ((fs & 0x30) << 2) + (fs & 0x0f)); + + /* Refer to HDMI2.1 spec table 9-28 and CTA861-G table 28~30 */ + /* Audio InfoFrame */ + if (priv->audio_ch > 8) { +#ifdef _1QD980ATC_ // for 5-1-60 + ca = 0x00; +#else + /* + * CTA-861-G spec. Section 6.6.3: Delivery According to the + * Speaker Mask (Byte 4 = 0xFE). + */ + ca = 0xfe; +#endif + } else if ((priv->audio_type == IT6621_AUD_TYPE_NLPCM) || + (priv->mch_lpcm_enabled == IT6621_TX_MCH_LPCM_EN) || + (priv->layout_2ch_enabled == IT6621_TX_2CH_LAYOUT_EN)) { + ca = 0x00; + } else { + /* + * CTA-861-G spec. Table 35 Audio InfoFrame Data Byte 4. + * 0x00: FR/FL + * 0x01: FR/FL/LFE1 + * 0x03: FR/FL/LFE1/FC + * 0x07: FR/FL/LFE1/FC/BC + * 0x0B: FR/FL/LFE1/FC/LS/RS + * 0x0F: FR/FL/LFE1/FC/LS/RS/BC + * 0x13: FR/FL/LFE1/FC/LS/RS/RLC/RRC + * 0xff: Channels delivered according to Channel Index + */ + + switch (priv->audio_ch) { + case 0: + ca = 0xff; + break; // no audio + case 2: + ca = 0x00; + break; + case 3: + ca = 0x01; + break; // 0x01,0x02,0x04 + case 4: + ca = 0x03; + break; // 0x03,0x05,0x06,0x08,0x14 + case 5: + ca = 0x07; + break; // 0x07,0x09,0x0A,0x0C,0x15,0x16,0x18 + case 6: + ca = 0x0B; + break; // 0x0B,0x0D,0x0E,0x10,0x17,0x19,0x1A,0x1C + case 7: + ca = 0x0f; + break; // 0x0F,0x11,0x12,0x1B,0x1D,0x1E + case 8: + ca = 0x13; + break; // 0x13,0x1F + default: + break; + } + } + + /* For allocation test 5-1-34, can't use on normal LPCM test */ + if (priv->force_ca & 0x80) { + switch (priv->force_ca) { + case 0x80: + ca = 0x00; + break; // 2ch + case 0x81: + ca = 0x01; + break; // 4ch + case 0x82: + ca = 0x0B; + break; // 6ch + case 0x83: + ca = 0x13; + break; // 8ch + default: + break; + } + + /* Clear for test */ + priv->force_ca = 0; + } + + /* NOTE: Set channel allocation. */ + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST9, ca); + + /* + * NOTE: DM_INH = 0, permitted or no information about any assertion + * of the down mixed stereo output. + * + * LSV3 = 0, LSV2 = 0, LSV1 = 0, LSV1 = 0, Level Shift Value is 0dB. + * + * LFEPBL1 = 0, LFEPBL0 = 0, unknown or refer to other information for + * LFE playback level comparing with other channel signal. + */ + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST10, 0x00); + + if (priv->audio_ch > 8) { + /* + * CTA-861-G spec. Table 29: Audio InfoFrame Format When Byte 4 + * is 0xFE. + * + * Byte 6: FLW/ RLC/ FLC/ BC BL/ FC LFE1 FL/ + * FRW RRC FRC BR FR + * Byte 7: TpSiL/ SiL/ TpBC LFE2 LS/ TpFC TpC TpFL/ + * TpSiR SiR RS TpFR + * Byte 8: F87=0 F86=0 F85=0 F84=0 TpLS/ BtFL/ BtFC TpBL/ + * TpRS BtFR TpBR + */ + /* Set HDMI2.1 channel status */ + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST11, 0x6f); + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST12, 0x0f); + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST13, 0x0c); + } else { + /* Reserved in CTA-861-G spec when Byte 4 is less than 0x32. */ + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST11, 0x00); + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST12, 0x00); + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST13, 0x00); + } + + /* Reserved in CTA-861-G spec. */ + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST14, 0x00); + regmap_write(priv->regmap, IT6621_REG_TX_CH_ST15, 0x00); + + return 0; +} + +int it6621_set_arc_enabled(struct it6621_priv *priv, bool enabled) +{ + priv->arc_enabled = enabled ? IT6621_TX_ARC_EN : IT6621_TX_ARC_DIS; + + regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0, IT6621_TX_ARC_SEL, + priv->arc_enabled); + + return 0; +} + +int it6621_set_earc_enabled(struct it6621_priv *priv, bool enabled) +{ + priv->earc_enabled = enabled ? IT6621_TX_EARC_EN : IT6621_TX_EARC_DIS; + + regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0, IT6621_TX_EARC_SEL, + priv->earc_enabled); + + return 0; +} + +int it6621_set_enter_arc(struct it6621_priv *priv, bool enabled) +{ + unsigned int state; + + if (enabled) { + regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0, + IT6621_TX_ARC_NOW_SEL, + IT6621_TX_ARC_NOW_EN); + it6621_get_ddfsm_state(priv, &state); + if (state != IT6621_TX_ARC_MODE) { + dev_err(priv->dev, "not in ARC mode\n"); + return -EAGAIN; + } + + /* NOTE: ARC only support SPDIF */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_AUD_SRC_SEL, + IT6621_TX_AUD_SRC, IT6621_AUD_SRC_SPDIF); + /* Common mode ARC */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3, + IT6621_TX_IN_ARC_MODE_SEL, + IT6621_TX_IN_ARC_COMMON_MODE); + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3, + IT6621_TX_DRV_CSW_SEL, IT6621_TX_DRV_CSW_7); + dev_dbg(priv->dev, "ARC now enabled\n"); + } else { + regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0, + IT6621_TX_ARC_NOW_SEL, + IT6621_TX_ARC_NOW_DIS); + /* Signal mode ARC */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3, + IT6621_TX_IN_ARC_MODE_SEL, + IT6621_TX_IN_ARC_SIGNAL_MODE); + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3, + IT6621_TX_DRV_CSW_SEL, IT6621_TX_DRV_CSW_4); + dev_dbg(priv->dev, "ARC now disabled\n"); + } + + return 0; +} + +static int it6621_toggle_real_hpd(struct it6621_priv *priv) +{ + /* toggle real HPD at least 100ms */ + /* Set HPDB low */ + regmap_update_bits(priv->regmap, IT6621_REG_SYS_CTRL1, + IT6621_TX_FORCE_HPDB_LOW_SEL, + IT6621_TX_FORCE_HPDB_LOW_EN); + msleep(120); + /* Set HPDB high */ + regmap_update_bits(priv->regmap, IT6621_REG_SYS_CTRL1, + IT6621_TX_FORCE_HPDB_LOW_SEL, + IT6621_TX_FORCE_HPDB_LOW_DIS); + + return 0; +} + +static int it6621_set_auto_mode(struct it6621_priv *priv) +{ + /* auto mode , eARC auto detect */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_DD3, + IT6621_TX_FORCE_ARC_MODE_SEL, + IT6621_TX_FORCE_ARC_MODE_DIS); + + it6621_set_enter_arc(priv, false); + + return it6621_toggle_real_hpd(priv); +} + +static int it6621_force_arc_mode(struct it6621_priv *priv) +{ + /* + * Force ARC mode , close eARC mode. + * Please recover to this HDMI RX's original EDID. + */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_DD3, + IT6621_TX_FORCE_ARC_MODE_SEL, + IT6621_TX_FORCE_ARC_MODE_EN); + + return it6621_toggle_real_hpd(priv); +} + +int it6621_get_ddfsm_state(struct it6621_priv *priv, unsigned int *state) +{ + int ret; + + ret = regmap_read(priv->regmap, IT6621_REG_TX_DD2, state); + *state &= IT6621_TX_DD_FSM_STATE; + + return ret; +} + +static int it6621_wait_cmdc_bus(struct it6621_priv *priv) +{ + unsigned int status; + unsigned int cmdc_state; + unsigned int dd_state; + unsigned int val; + int ret; + + ret = regmap_read_poll_timeout(priv->regmap, IT6621_REG_INT_STATUS1, + status, status & (IT6621_TX_CMD_FAIL | + IT6621_TX_CMD_DONE), + 1000, 10000); + if (ret) { + it6621_get_ddfsm_state(priv, &dd_state); + regmap_read(priv->regmap, IT6621_REG_CMDC1, &val); + cmdc_state = val & IT6621_TX_CMDC_STATE; + dev_err(priv->dev, "timeout! TXDDFSM: %d, TXCMDFSM: %d\n", + dd_state, cmdc_state); + } + + if (status & IT6621_TX_CMD_DONE) { + /* TX init done interrupt */ + regmap_write(priv->regmap, IT6621_REG_INT_STATUS1, + IT6621_TX_CMD_DONE); + return 0; + } + + if (status & IT6621_TX_CMD_FAIL) { + regmap_write(priv->regmap, IT6621_REG_INT_STATUS1, + IT6621_TX_CMD_FAIL); + dev_err(priv->dev, "TX CMD failed\n"); + + regmap_read(priv->regmap, IT6621_REG_CMDC1, &val); + + if (val & IT6621_TX_FAIL_STATE_NO_RESP) + dev_err(priv->dev, "no response\n"); + + if (val & IT6621_TX_FAIL_STATE_UNEXP_RESP) + dev_err(priv->dev, "unexpected response\n"); + + if (val & IT6621_TX_FAIL_STATE_ECC_ERR) + dev_err(priv->dev, "uncorrectable ECC error\n"); + + if (val & IT6621_TX_FAIL_STATE_TIMEOUT) { + if (priv->cmd_to_enabled) + dev_err(priv->dev, + "NACK/RETRY 256 times timeout\n"); + else + dev_err(priv->dev, "NACK command state\n"); + } + } + + return -EAGAIN; +} + +static int it6621_read_cmdc_cmd(struct it6621_priv *priv, unsigned int devid, + unsigned int offset, unsigned int *cmd) +{ + unsigned int state; + + it6621_get_ddfsm_state(priv, &state); + if (state != IT6621_TX_EARC_MODE) { + dev_err(priv->dev, "abort CMDC read\n"); + return -EAGAIN; + } + + /* Data FIFO Clear */ + regmap_update_bits(priv->regmap, IT6621_REG_CMDC3, + IT6621_TX_DATA_FIFO_CLEAR, + IT6621_TX_DATA_FIFO_CLEAR); + /* TxCmd DevID */ + regmap_write(priv->regmap, IT6621_REG_TX_DEV_ID, devid); + /* TxCmd Offset */ + regmap_write(priv->regmap, IT6621_REG_TX_OFFSET, offset); + /* Read Trigger (1-byte) */ + regmap_write(priv->regmap, IT6621_REG_CMDC2, IT6621_TX_READ_TRIGGER); + + it6621_wait_cmdc_bus(priv); + + return regmap_read(priv->regmap, IT6621_REG_TX_DATA_FIFO, cmd); +} + +static void it6621_write_cmdc_cmd(struct it6621_priv *priv, unsigned int devid, + unsigned int offset, unsigned int data) +{ + unsigned int state; + + it6621_get_ddfsm_state(priv, &state); + if (state != IT6621_TX_EARC_MODE) { + dev_err(priv->dev, "abort CMDC write\n"); + return; + } + + /* Data FIFO Clear */ + regmap_update_bits(priv->regmap, IT6621_REG_CMDC3, + IT6621_TX_DATA_FIFO_CLEAR, + IT6621_TX_DATA_FIFO_CLEAR); + /* TxCmd DevID */ + regmap_write(priv->regmap, IT6621_REG_TX_DEV_ID, devid); + /* TxCmd Offset */ + regmap_write(priv->regmap, IT6621_REG_TX_OFFSET, offset); + /* TxCmd WrData */ + regmap_write(priv->regmap, IT6621_REG_TX_DATA_FIFO, data); + /* Write Trigger (1-byte) */ + regmap_write(priv->regmap, IT6621_REG_CMDC2, IT6621_TX_WRITE_TRIGGER); + + it6621_wait_cmdc_bus(priv); +} + +static int it6621_read_cmdc_bulk(struct it6621_priv *priv, unsigned int devid, + unsigned int offset, size_t len, void *data) +{ + unsigned int state; + int ret; + + it6621_get_ddfsm_state(priv, &state); + if (state != IT6621_TX_EARC_MODE) { + dev_err(priv->dev, "abort CMDC bulk read\n"); + return -EAGAIN; + } + + /* Data FIFO Clear */ + regmap_update_bits(priv->regmap, IT6621_REG_CMDC3, + IT6621_TX_DATA_FIFO_CLEAR, + IT6621_TX_DATA_FIFO_CLEAR); + /* TxCmd DevID */ + regmap_write(priv->regmap, IT6621_REG_TX_DEV_ID, devid); + /* TxCmd Offset */ + regmap_write(priv->regmap, IT6621_REG_TX_OFFSET, offset); + /* Read Trigger & Read ByteNum[4:0] */ + regmap_write(priv->regmap, IT6621_REG_CMDC2, + IT6621_TX_READ_TRIGGER | (len - 1)); + + ret = it6621_wait_cmdc_bus(priv); + if (ret) + return ret; + + regmap_noinc_read(priv->regmap, IT6621_REG_TX_DATA_FIFO, data, len); + + return 0; +} + +/** + * it6621_set_latency - eARC TX Set latency request + * + * @latency: latency in marco second, range from 0 to 250 ms. + */ +static void it6621_set_latency(struct it6621_priv *priv, unsigned int latency) +{ + it6621_write_cmdc_cmd(priv, 0x74, 0xd3, latency); +} + +/** + * it6621_get_latency - Read eARC RX's Latency + * + * @latency: latency in marco second, range from 0 to 250 ms. + */ +static int it6621_get_latency(struct it6621_priv *priv, unsigned int *latency) +{ + return it6621_read_cmdc_cmd(priv, 0x74, 0xd2, latency); +} + +/** + * it6621_reset_driver - should be set power down in ARC mode + * + * @on: power on/down differential mode signal. + */ +static void it6621_reset_driver(struct it6621_priv *priv, bool enabled) +{ + dev_dbg(priv->dev, "set TX driver %s\n", enabled ? "on" : "off"); + + if (enabled) + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, + IT6621_TX_DRV_RESET_SEL, + IT6621_TX_DRV_RESET_DIS); + else + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, + IT6621_TX_DRV_RESET_SEL, + IT6621_TX_DRV_RESET_EN); +} + +static int it6621_check_audio(struct it6621_priv *priv) +{ + unsigned int val; + + if (test_bit(IT6621_AUDIO_TO_EN_DMAC, &priv->audio_flag) && + test_bit(IT6621_AUDIO_START, &priv->audio_flag)) { + if (test_bit(IT6621_EARC_BCLK_OK, &priv->events)) { + /* Need to be finetune at diff platform */ + msleep(50); + it6621_reset_driver(priv, true); + clear_bit(IT6621_EARC_BCLK_OK, &priv->events); + clear_bit(IT6621_AUDIO_TO_EN_DMAC, &priv->audio_flag); + regmap_read(priv->regmap, IT6621_REG_TX_AFE2, &val); + dev_dbg(priv->dev, "A2: 0x%02x\n", val); + } + + if (priv->force_arc) + it6621_set_enter_arc(priv, true); + } + + return 0; +} + +int it6621_earc_init(struct it6621_priv *priv) +{ + priv->state = IT6621_EARC_IDLE; + priv->rclk = 0; + priv->aclk = 0; + priv->bclk = 0; + + /* Enable GRCLK */ + regmap_update_bits(priv->regmap, IT6621_REG_CLK_CTRL0, + IT6621_GATE_RCLK_SEL, IT6621_GATE_RCLK_DIS); + + /* TXAFE PLL Reset */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE0, + IT6621_TX_XP_RESET_SEL, IT6621_TX_XP_RESET_ACTIVE); + + /* eARCTX Reset */ + regmap_update_bits(priv->regmap, IT6621_REG_SYS_RESET, + IT6621_SW_RCLK_RESET_SEL, IT6621_SW_RCLK_RESET_EN); + + regmap_update_bits(priv->regmap, IT6621_REG_CLK_CTRL0, + IT6621_RCLK_FREQ_SEL, priv->rclk_sel); + + regmap_update_bits(priv->regmap, IT6621_REG_CLK_DET7, + IT6621_ACLK_DET_EN_SEL, IT6621_ACLK_DET_DIS); + regmap_update_bits(priv->regmap, IT6621_REG_CLK_DET7, + IT6621_UPDATE_AVG_EN_SEL, priv->update_avg_enabled); + regmap_update_bits(priv->regmap, IT6621_REG_CMDC4, + IT6621_TX_HB_RETRY_TIME_SEL | + IT6621_TX_HB_RETRY_SEL, + priv->hb_retry_sel | priv->hb_retry_enabled); + /* NOTE: Disable to pass SL-870 HFR5-1-35/36/37 */ + regmap_update_bits(priv->regmap, IT6621_REG_CMDC5, + IT6621_TX_AUTO_WRITE_STATE_SEL, + IT6621_TX_AUTO_WRITE_STATE_DIS); + regmap_update_bits(priv->regmap, IT6621_REG_DMAC_CTRL0, + IT6621_TX_ENC_OPT | IT6621_TX_ENC_SEL | + IT6621_TX_ECC_OPT, + priv->enc_opt | (priv->audio_enc << 3) | + priv->ecc_opt); + regmap_write(priv->regmap, IT6621_REG_TX_ENC_SEED_LOW, + priv->enc_seed & 0xff); + regmap_write(priv->regmap, IT6621_REG_TX_ENC_SEED_HIGH, + (priv->enc_seed & 0xff00) >> 8); + regmap_update_bits(priv->regmap, IT6621_REG_DMAC_CTRL1, + IT6621_TX_U_BIT_OPT | IT6621_TX_C_CH_OPT | + IT6621_TX_PKT3_EN_SEL | IT6621_TX_PKT2_EN_SEL | + IT6621_TX_PKT1_EN_SEL, + priv->ubit_opt | priv->c_ch_opt | + priv->pkt3_enabled | priv->pkt2_enabled | + priv->pkt1_enabled); + regmap_update_bits(priv->regmap, IT6621_REG_CMDC6, + IT6621_TX_RESYNC_OPT | IT6621_TX_FORCE_CMO_OPT | + IT6621_TX_CMO_OPT, + priv->resync_opt | priv->force_cmo_enabled | + priv->cmo_opt); + regmap_update_bits(priv->regmap, IT6621_REG_CMDC0, + IT6621_TX_TURN_OVER_SEL | + IT6621_TX_NEXT_PKT_TIMEOUT_SEL, + priv->turn_over_sel | + priv->nxt_pkt_to_sel); + regmap_update_bits(priv->regmap, IT6621_REG_TX_AUD_CTRL10, + IT6621_TX_2CH_LAYOUT_SEL | IT6621_TX_NLPCM_I2S_SEL | + IT6621_TX_MCH_LPCM_SEL | IT6621_TX_EXT_MUTE_SEL, + priv->layout_2ch_enabled | priv->i2s_nlpcm_enabled | + priv->mch_lpcm_enabled | IT6621_TX_EXT_MUTE_DIS); + regmap_update_bits(priv->regmap, IT6621_REG_CLK_CTRL2, + IT6621_BCLK_INV_SEL | IT6621_ACLK_INV_SEL, + priv->bclk_inv_enabled | IT6621_ACLK_INV_DIS); + regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0, + IT6621_TX_ARC_NOW_SEL | IT6621_TX_ARC_SEL | + IT6621_TX_EARC_SEL, + priv->enter_arc_now | priv->arc_enabled | + priv->earc_enabled); + + if (priv->force_arc) + regmap_update_bits(priv->regmap, IT6621_REG_TX_DD3, + IT6621_TX_FORCE_ARC_MODE_SEL, + IT6621_TX_FORCE_ARC_MODE_EN); + else + regmap_update_bits(priv->regmap, IT6621_REG_TX_DD3, + IT6621_TX_FORCE_ARC_MODE_SEL, + IT6621_TX_FORCE_ARC_MODE_DIS); + + /* test to disable TxXPLOCKChgInt */ + regmap_write(priv->regmap, IT6621_REG_INT_EN0, + IT6621_TX_RESYNC_ERR_EN | IT6621_TX_NO_AUD_CHANGE_EN | + IT6621_TX_DISV_TIMEOUT_EN | IT6621_TX_HB_LOST_EN | + IT6621_TX_STATE3_CHANGE_EN | IT6621_TX_HPDIO_OFF_EN | + IT6621_TX_HPDIO_ON_EN); + regmap_write(priv->regmap, IT6621_REG_INT_EN1, + IT6621_TX_CMD_DONE_EN | IT6621_TX_CMD_FAIL_EN | + IT6621_TX_READ_STATE_CHG_EN | IT6621_TX_CMDC_BP_ERR_EN | + IT6621_TX_WRITE_STATE_CHG_EN | IT6621_TX_WRITE_CAP_CHG_EN | + IT6621_TX_HB_FAIL_EN); + regmap_write(priv->regmap, IT6621_REG_INT_EN2, + IT6621_TX_MUTE_CHANGE_EN | IT6621_TX_SPDIF_CHANGE_EN | + IT6621_TX_SPDIF_READY_EN | IT6621_TX_DEC_ERR_EN | + IT6621_TX_FIFO_ERR_EN); + /* enable RX HPD interrupt for HPDB interrupt */ + regmap_write(priv->regmap, IT6621_REG_INT_EN3, + IT6621_TX_HPDB_OFF_EN | IT6621_TX_HPDB_ON_EN); + regmap_write(priv->regmap, IT6621_REG_INT_EN4, + IT6621_DET_NO_BCLK_EN | IT6621_DET_BCLK_VALID_EN | + IT6621_DET_BCLK_STABLE_EN | IT6621_DET_ACLK_VALID_EN | + IT6621_DET_ACLK_STABLE_EN); + regmap_update_bits(priv->regmap, 0xa9, 0xFF, 0xFD); + it6621_calc_rclk(priv); + + /* enable ACLK detection */ + regmap_update_bits(priv->regmap, IT6621_REG_CLK_DET7, + IT6621_ACLK_DET_EN_SEL, IT6621_ACLK_DET_EN); + + /* RTxDbgFifoClr */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_DEBUG_FIFO2, + IT6621_TX_DEBUG_FIFO_CLEAR_SEL, + IT6621_TX_DEBUG_FIFO_CLEAR_EN); + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE1, + IT6621_TX_XP_ER0_SEL | IT6621_TX_XP_DEI_SEL, + IT6621_TX_XP_ER0_DIS | IT6621_TX_XP_DEI_DIS); + if (priv->revid == IT6621_REVISION_VARIANT_C0) { + /* + * NOTE: In eARC mode, change DMAC back to B0 version, + * DRV_OT_SEL set to 1 for C0,TX_HYS_SEL = 5 for C0 + */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, + IT6621_TX_DRV_OT_SEL | + IT6621_TX_DRV_DSW_SEL | + IT6621_TX_DRV_DC, + IT6621_TX_DRV_OT_EN | + IT6621_TX_DRV_DSW_4 | + IT6621_TX_DRV_DC_SEL_DIS | + IT6621_TX_DRV_DC_DIS); + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE4, + IT6621_TX_HYS_SEL | + IT6621_TX_VCM_SEL | + IT6621_TX_RC_CK_SEL, + IT6621_TX_HYS5 | + priv->vcm_sel | + IT6621_TX_RC_CK_DIS); + } else if (priv->revid == IT6621_REVISION_VARIANT_D0) { + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, + IT6621_TX_DRV_OT_SEL | + IT6621_TX_DRV_DSW_SEL | + IT6621_TX_DRV_DC, + IT6621_TX_DRV_OT_EN | + IT6621_TX_DRV_DSW_7 | + IT6621_TX_DRV_DC_SEL_DIS | + IT6621_TX_DRV_DC_DIS); + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE4, + IT6621_TX_HYS_SEL | + IT6621_TX_VCM_SEL | + IT6621_TX_RC_CK_SEL, + IT6621_TX_HYS5 | + priv->vcm_sel | + IT6621_TX_RC_CK_DIS); + } else { + /* + * NOTE: DRV_OT_SEL set to 0 force TM tri-state in + * ARC single mode (B0). + */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, + IT6621_TX_DRV_OT_SEL | + IT6621_TX_DRV_DSW_SEL, + IT6621_TX_DRV_OT_DIS | + IT6621_TX_DRV_DSW_4); + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE4, + IT6621_TX_HYS_SEL | + IT6621_TX_VCM_SEL | + IT6621_TX_RC_CK_SEL, + IT6621_TX_HYS6 | + priv->vcm_sel | + IT6621_TX_RC_CK_DIS); + } + + /* For D0 TX_DRV_CSR */ + if (priv->revid == IT6621_REVISION_VARIANT_D0) + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3, + IT6621_TX_DRV_CSW_SEL | + IT6621_TX_DRV_CSR_SEL, + IT6621_TX_DRV_CSW_4 | + IT6621_TX_DRV_CSR_2); + else + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3, + IT6621_TX_DRV_CSW_SEL | + IT6621_TX_DRV_CSR_SEL, + IT6621_TX_DRV_CSW_4 | + IT6621_TX_DRV_CSR_4); + + regmap_update_bits(priv->regmap, IT6621_REG_SYS_RESET, + IT6621_SW_RCCLK_RESET_SEL | + IT6621_SW_TCCLK_RESET_SEL | + IT6621_SW_BCLK_RESET_SEL | + IT6621_SW_ACLK_RESET_SEL, + IT6621_SW_RCCLK_RESET_DIS | + IT6621_SW_TCCLK_RESET_DIS | + IT6621_SW_BCLK_RESET_DIS | + IT6621_SW_ACLK_RESET_DIS); + + /* Enable eARC TX Discovery and Disconnect FSM */ + regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0, + IT6621_TX_DD_FSM_SEL, IT6621_TX_DD_FSM_EN); + + if (priv->force_arc) { + dev_info(priv->dev, "force ARC mode\n"); + it6621_force_arc_mode(priv); + } + + if (priv->force_earc) { + dev_info(priv->dev, "force eARC mode\n"); + it6621_set_auto_mode(priv); + } + + return 0; +} + +static int it6621_read_rxcap(struct it6621_priv *priv) +{ + u8 rxcap[IT6621_RX_CAP_MAX_LEN]; + int i; + int ret; + + /* Enable eARC TX Command Done/Fail Interrupt */ + regmap_update_bits(priv->regmap, IT6621_REG_INT_EN1, + IT6621_TX_CMD_FAIL_SEL | IT6621_TX_CMD_DONE_SEL, + IT6621_TX_CMD_FAIL_EN | IT6621_TX_CMD_DONE_EN); + + for (i = 0; i < 255; i += IT6621_RXCAP_BULK_LEN) { + ret = it6621_read_cmdc_bulk(priv, 0xa0, i, + IT6621_RXCAP_BULK_LEN, &rxcap[i]); + if (ret) { + dev_err(priv->dev, "failed to read eARC RX Cap\n"); + return ret; + } + } + + mutex_lock(&priv->rxcap_lock); + + if (memcmp(rxcap, priv->rxcap, sizeof(priv->rxcap))) { + memcpy(priv->rxcap, rxcap, sizeof(priv->rxcap)); + set_bit(IT6621_EARC_CAP_CHG, &priv->events); + } + + mutex_unlock(&priv->rxcap_lock); + + return 0; +} + +static void it6621_set_state(struct it6621_priv *priv, unsigned int state) +{ + if (priv->state != state) { + priv->state = state; + it6621_uapi_msg(priv, IT6621_EVENT_STATE_CHANGE, &priv->state, + sizeof(priv->state)); + } +} + +static int it6621_check_rxcap(struct it6621_priv *priv) +{ + if (test_bit(IT6621_EARC_CAP_CHG, &priv->events)) { + clear_bit(IT6621_EARC_CAP_CHG, &priv->events); + it6621_uapi_msg(priv, IT6621_EVENT_AUDIO_CAP_CHANGE, + priv->rxcap, sizeof(priv->rxcap)); + cancel_work_sync(&priv->hpdio_work); + schedule_work(&priv->hpdio_work); + } + + return 0; +} + +static int it6621_earc_irq(struct it6621_priv *priv) +{ + unsigned int status0; + unsigned int status1; + unsigned int status2; + unsigned int status3; + unsigned int status4; + unsigned int state; + unsigned int val; + unsigned int latency = 0; + + regmap_read(priv->regmap, IT6621_REG_INT_STATUS0, &status0); + regmap_read(priv->regmap, IT6621_REG_INT_STATUS1, &status1); + regmap_read(priv->regmap, IT6621_REG_INT_STATUS2, &status2); + regmap_read(priv->regmap, IT6621_REG_INT_STATUS3, &status3); + regmap_read(priv->regmap, IT6621_REG_INT_STATUS4, &status4); + regmap_write(priv->regmap, IT6621_REG_INT_STATUS0, status0); + regmap_write(priv->regmap, IT6621_REG_INT_STATUS1, status1); + regmap_write(priv->regmap, IT6621_REG_INT_STATUS2, status2); + status3 &= IT6621_TX_HPDB_OFF | IT6621_TX_HPDB_ON; + regmap_write(priv->regmap, IT6621_REG_INT_STATUS3, status3); + regmap_write(priv->regmap, IT6621_REG_INT_STATUS4, status4); + + /* Interrupt status0 */ + if (status0 & IT6621_TX_HPDIO_ON) { + dev_dbg(priv->dev, "HPD IO on\n"); + /* Set HPDB low clear */ + regmap_update_bits(priv->regmap, IT6621_REG_SYS_CTRL1, + IT6621_TX_FORCE_HPDB_LOW_SEL, + IT6621_TX_FORCE_HPDB_LOW_DIS); + } + + if (status0 & IT6621_TX_HPDIO_OFF) { + dev_dbg(priv->dev, "HPD IO off\n"); + + if (test_bit(IT6621_ARC_START, &priv->events)) + it6621_set_enter_arc(priv, false); + + /* Set HPDB low */ + if (!priv->toggle_by_edid) + regmap_update_bits(priv->regmap, + IT6621_REG_SYS_CTRL1, + IT6621_TX_FORCE_HPDB_LOW_SEL, + IT6621_TX_FORCE_HPDB_LOW_EN); + else + priv->toggle_by_edid = 0; + + clear_bit(IT6621_ARC_START, &priv->events); + } + + if (status0 & IT6621_TX_STATE3_CHANGE) { + dev_dbg(priv->dev, "eARC enable\n"); + + it6621_get_ddfsm_state(priv, &state); + dev_dbg(priv->dev, "eARC stat3 change to %d\n", + state & IT6621_TX_EARC_MODE ? 1 : 0); + clear_bit(IT6621_ARC_START, &priv->events); + + if (state & IT6621_TX_EARC_MODE) + it6621_set_state(priv, IT6621_EARC_CONNECTED); + else + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, + IT6621_TX_DRV_RESET_SEL, + IT6621_TX_DRV_RESET_EN); + } + + if (status0 & IT6621_TX_HB_LOST) { + dev_dbg(priv->dev, "heartbeat lost\n"); + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, + IT6621_TX_DRV_RESET_SEL, + IT6621_TX_DRV_RESET_EN); + } + + if (status0 & IT6621_TX_DISV_TIMEOUT) { + dev_dbg(priv->dev, "discovery timeout\n"); + + priv->events = 0; + set_bit(IT6621_ARC_START, &priv->events); + it6621_set_state(priv, IT6621_ARC_PENDING); + } + + if (status0 & IT6621_TX_NO_AUD_CHANGE) { + regmap_read(priv->regmap, IT6621_REG_SYS_STATUS, &val); + val &= IT6621_TX_NO_AUDIO; + dev_dbg(priv->dev, "TX has %s audio stream\n", val ? "no" : ""); + } + + if (status0 & IT6621_TX_XP_LOCK_CHANGE) { + regmap_read(priv->regmap, IT6621_REG_SYS_STATUS, &val); + val &= IT6621_TX_XP_LOCK; + dev_dbg(priv->dev, "XP lock: %d\n", val >> 2); + } + + if (status0 & IT6621_TX_RESYNC_ERR) + dev_err(priv->dev, "CMDC resync error\n"); + + /* Interrupt status1 */ + if (status1 & IT6621_TX_CMD_DONE) + dev_dbg(priv->dev, "Cmd Done\n"); + + if (status1 & IT6621_TX_HB_DONE) + dev_dbg(priv->dev, "heartbeat done\n"); + + if (status1 & IT6621_TX_READ_STATE_CHANGE) { + regmap_read(priv->regmap, IT6621_REG_TX_READ_STATE, &val); + dev_dbg(priv->dev, "RX state change to 0x%02X\n", val); + val &= 0x18; + regmap_update_bits(priv->regmap, IT6621_REG_CMDC5, 0x18, val); + } + + if (status1 & IT6621_TX_CMDC_BP_ERR) + dev_err(priv->dev, "CMDC bi-phase error\n"); + + if (status1 & IT6621_TX_WRITE_STATE_CHANGE) { + it6621_get_latency(priv, &latency); + dev_dbg(priv->dev, "auto write STAT_CHNG 1->0 done\n"); + dev_dbg(priv->dev, "latency: 0x%02X ms\n", latency); + } + + if (status1 & IT6621_TX_WRITE_CAP_CHANGE) { + dev_dbg(priv->dev, "auto write CAP_CHNG 1->0 done\n"); + it6621_read_rxcap(priv); + + if (priv->audio_enc) { + it6621_write_cmdc_cmd(priv, 0x9c, 0x10, + priv->enc_opt >> 4); + it6621_write_cmdc_cmd(priv, 0x9c, 0x11, + priv->enc_seed & 0xff); + it6621_write_cmdc_cmd(priv, 0x9c, 0x12, + (priv->enc_seed & 0xff00) >> 8); + } + + /* Write 140ms to ERX_LATENCY_REQ */ + it6621_set_latency(priv, 140); + regmap_read(priv->regmap, IT6621_REG_TX_AFE2, &val); + val &= IT6621_TX_DRV_RESET_SEL; + dev_dbg(priv->dev, "TX driver reset: %d\n", val >> 1); + } + + if (status1 & IT6621_TX_HB_FAIL) + dev_dbg(priv->dev, "heartbeat fail\n"); + + /* Interrupt status2 */ + if (status2 & IT6621_TX_FIFO_ERR) + dev_dbg(priv->dev, "audio FIFO error\n"); + + if (status2 & IT6621_TX_DEC_ERR) + dev_dbg(priv->dev, "audio decode error\n"); + + if (status2 & IT6621_TX_SPDIF_READY) + dev_dbg(priv->dev, "SPDIF channel status is ready\n"); + + if (status2 & IT6621_TX_SPDIF_CHANGE) + dev_dbg(priv->dev, "SPDIF channel status is changed\n"); + + if (status2 & IT6621_TX_MUTE_CHANGE) { + regmap_read(priv->regmap, IT6621_REG_SYS_STATUS, &val); + val &= IT6621_TX_MUTE; + dev_dbg(priv->dev, "input is %s\n", val ? "muted" : "unmuted"); + } + + /* Interrupt status3 */ + if (status3 & IT6621_TX_HPDB_ON) { + dev_dbg(priv->dev, "HPD bus on\n"); + it6621_set_state(priv, IT6621_EARC_PENDING); + } + + if (status3 & IT6621_TX_HPDB_OFF) { + dev_dbg(priv->dev, "HPD bus off\n"); + regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, + IT6621_TX_DRV_RESET_SEL, + IT6621_TX_DRV_RESET_EN); + + if (test_bit(IT6621_ARC_START, &priv->events)) + it6621_set_enter_arc(priv, false); + + clear_bit(IT6621_ARC_START, &priv->events); + it6621_set_state(priv, IT6621_EARC_IDLE); + } + + /* Interrupt status4 */ + if (status4 & IT6621_DET_ACLK_STABLE) { + dev_dbg(priv->dev, "ACLK is stable\n"); + it6621_get_aclk(priv); + it6621_force_pdiv(priv); + } + + if (status4 & IT6621_DET_ACLK_VALID) + dev_dbg(priv->dev, "ACLK is valid\n"); + + if (status4 & IT6621_DET_NO_BCLK) { + dev_dbg(priv->dev, "BCLK is not present\n"); + clear_bit(IT6621_EARC_BCLK_OK, &priv->events); + it6621_reset_driver(priv, false); + } + + if (status4 & IT6621_DET_BCLK_STABLE) { + dev_dbg(priv->dev, "BCLK is stable\n"); + it6621_get_bclk(priv); + set_bit(IT6621_EARC_BCLK_OK, &priv->events); + if (test_bit(IT6621_AUDIO_START, &priv->audio_flag)) + set_bit(IT6621_AUDIO_TO_EN_DMAC, &priv->audio_flag); + } + + if (status4 & IT6621_DET_BCLK_VALID) + dev_dbg(priv->dev, "BCLK is valid\n"); + + return 0; +} + +irqreturn_t it6621_irq(int irq, void *data) +{ + struct it6621_priv *priv = data; + + it6621_earc_irq(priv); + + it6621_check_audio(priv); + it6621_check_rxcap(priv); + + return IRQ_HANDLED; +} diff --git a/sound/soc/codecs/it6621/it6621-earc.h b/sound/soc/codecs/it6621/it6621-earc.h new file mode 100644 index 000000000000..c4f0f430e1b0 --- /dev/null +++ b/sound/soc/codecs/it6621/it6621-earc.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Jason Zhang + */ + +#ifndef _IT6621_EARC_H +#define _IT6621_EARC_H + +#include "it6621.h" + +#define IT6621_AES3_CON_FS_64000 0x0b +#define IT6621_AES3_CON_FS_128000 0x2b +#define IT6621_AES3_CON_FS_256000 0x1b +#define IT6621_AES3_CON_FS_352000 0x0d +#define IT6621_AES3_CON_FS_384000 0x05 +#define IT6621_AES3_CON_FS_512000 0x3b +#define IT6621_AES3_CON_FS_705000 0x2d +#define IT6621_AES3_CON_FS_1024000 0x35 +#define IT6621_AES3_CON_FS_1411000 0x1d +#define IT6621_AES3_CON_FS_1536000 0x15 + +#define IT6621_AUD_TYPE_LPCM 0 +#define IT6621_AUD_TYPE_NLPCM 1 +#define IT6621_AUD_TYPE_HBR 2 +#define IT6621_AUD_TYPE_DSD 3 + +/* HDMI2.1 spec. Table 9-23: Channel Status Bits 0, 1, 3, 4, and 5 */ +#define HDMI_AUDIO_FMT_UN_2CH_LPCM 0x00 /* Unencrypted 2-channel LPCM */ +#define HDMI_AUDIO_FMT_UN_MCH_LPCM 0x10 /* Unencrypted multi-channel LPCM */ +#define HDMI_AUDIO_FMT_UN_XCH_DSD 0x18 /* Unencrypted One Bit Audio */ +#define HDMI_AUDIO_FMT_UN_2CH_NLPCM 0x02 /* Unencrypted IEC 61937 */ +#define HDMI_AUDIO_FMT_EN_2CH_NLPCM 0x06 /* Encrypted IEC 61937 */ +#define HDMI_AUDIO_FMT_EN_MCH_NLPCM 0x16 /* Encrypted multi-channel LPCM */ +#define HDMI_AUDIO_FMT_EN_XCH_DSD 0x1e /* Encrypted One Bit Audio */ + +/* + * HDMI2.1 spec. + * Table 9-25: Channel Status Bits 44 to 47 When Multi-Channel L-PCM is + * Transmitted. + * Table 9-26: Channel Status Bits 44 to 47 When One Bit Audio is Transmitted. + * Table 9-27: Channel Status Bits 44 to 47 When IEC 61937 (Compressed) Audio + * is Transmitted. + */ +#define HDMI_AUDIO_LAYOUT_LPCM_2CH 0x00 +#define HDMI_AUDIO_LAYOUT_LPCM_8CH 0x07 +#define HDMI_AUDIO_LAYOUT_LPCM_16CH 0x0b +#define HDMI_AUDIO_LAYOUT_LPCM_32CH 0x03 +#define HDMI_AUDIO_LAYOUT_NLPCM_2CH 0x00 +#define HDMI_AUDIO_LAYOUT_NLPCM_8CH 0x07 +#define HDMI_AUDIO_LAYOUT_DSD_6CH 0x05 +#define HDMI_AUDIO_LAYOUT_DSD_12CH 0x09 + +int it6621_set_arc_enabled(struct it6621_priv *priv, bool enabled); +int it6621_set_earc_enabled(struct it6621_priv *priv, bool enabled); +int it6621_set_enter_arc(struct it6621_priv *priv, bool enabled); +int it6621_get_ddfsm_state(struct it6621_priv *priv, unsigned int *state); +int it6621_set_channel_status(struct it6621_priv *priv); +int it6621_earc_init(struct it6621_priv *priv); +irqreturn_t it6621_irq(int irq, void *data); + +#endif /* _IT6621_EARC_H */ diff --git a/sound/soc/codecs/it6621/it6621-reg-bank0.h b/sound/soc/codecs/it6621/it6621-reg-bank0.h new file mode 100644 index 000000000000..b447ede66df0 --- /dev/null +++ b/sound/soc/codecs/it6621/it6621-reg-bank0.h @@ -0,0 +1,982 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Jason Zhang + */ + +#ifndef _IT6621_REG_BANK0_H +#define _IT6621_REG_BANK0_H + +/* Bank 0 */ + +/* General Registers */ +#define IT6621_REG_VENDOR_ID_LOW 0x00 /* Vendor ID low */ +#define IT6621_REG_VENDOR_ID_HIGH 0x01 /* Vendor ID high */ +#define IT6621_REG_DEV_ID_LOW 0x02 /* Device ID low */ +#define IT6621_REG_DEV_ID_HIGH 0x03 /* Device ID high */ +#define IT6621_REG_REV_ID 0x04 /* Revision ID */ + +/* System Reset */ +#define IT6621_REG_SYS_RESET 0x05 +#define IT6621_SW_ACLK_RESET_SEL BIT(0) /* Software ACLK clock domain reset */ +#define IT6621_SW_ACLK_RESET_DIS (0x00 << 0) +#define IT6621_SW_ACLK_RESET_EN (0x01 << 0) +#define IT6621_SW_BCLK_RESET_SEL BIT(1) /* Software BCLK clock domain reset */ +#define IT6621_SW_BCLK_RESET_DIS (0x00 << 1) +#define IT6621_SW_BCLK_RESET_EN (0x01 << 1) +#define IT6621_SW_TCCLK_RESET_SEL BIT(2) /* Software TCCLK clock domain reset */ +#define IT6621_SW_TCCLK_RESET_DIS (0x00 << 2) +#define IT6621_SW_TCCLK_RESET_EN (0x01 << 2) +#define IT6621_SW_RCCLK_RESET_SEL BIT(3) /* Software RCCLK clock domain reset */ +#define IT6621_SW_RCCLK_RESET_DIS (0x00 << 3) +#define IT6621_SW_RCCLK_RESET_EN (0x01 << 3) +#define IT6621_SW_RCLK_RESET_SEL BIT(7) /* Software RCLK clock domain reset */ +#define IT6621_SW_RCLK_RESET_DIS (0x00 << 7) +#define IT6621_SW_RCLK_RESET_EN (0x01 << 7) + +/* System Status */ +#define IT6621_REG_SYS_STATUS 0x07 +#define IT6621_HPDIO_STATUS BIT(0) /* eARC HPDIO status */ +#define IT6621_HPDB_STATUS BIT(1) /* eARC HPDB status */ +#define IT6621_TX_XP_LOCK BIT(2) /* eARC TX XP lock indicator of PLL, 1: locked */ +#define IT6621_TX_NO_AUDIO BIT(4) /* 1: eARC TX no input audio */ +#define IT6621_TX_MUTE BIT(6) /* eARC TX input mute status */ + +#define IT6621_REG_EARC_TX_AUD_FREQ_NUM 0x0a + +/* System Control Registers */ +#define IT6621_REG_SYS_CTRL0 0x0c +#define IT6621_EXT_INT_EN BIT(1) /* External INT pin, 0: Disable, 1: Enable */ +#define IT6621_INT_IO_MODE BIT(2) /* External INT pin mode selection, + * 0: Push-Pull Mode, + * 1: Open-Drain mode + */ +#define IT6621_INT_IO_POL BIT(3) /* External INT pin active selection, + * 0: INT active low, + * 1: INT active high + */ +#define IT6621_FORCE_WRITE_UPDATE BIT(4) /* 1: force write update in non-idle state */ + +#define IT6621_REG_SYS_CTRL1 0x0d +#define IT6621_TX_AUD_FREQ_OPT BIT(0) /* eARC TX audio sampling frequency option */ +#define IT6621_TX_AUD_FREQ_DIV1 (0x00 << 0) /* div 1 */ +#define IT6621_TX_AUD_FREQ_DIV4 (0x01 << 0) /* div 4 */ +#define IT6621_TX_FORCE_HPDB_LOW_SEL BIT(4) /* eARC TX force HPDB low */ +#define IT6621_TX_FORCE_HPDB_LOW_DIS (0x00 << 4) +#define IT6621_TX_FORCE_HPDB_LOW_EN (0x01 << 4) + +#define IT6621_REG_SYS_CTRL3 0x0f +#define IT6621_BANK_SEL GENMASK(1, 0) /* Bank selection */ +#define IT6621_BANK0 (0x00 << 0) /* Reg00h~ Regffh */ +#define IT6621_BANK1 (0x01 << 0) /* Reg110h ~ Reg1ffh */ +#define IT6621_BANK2 (0x02 << 0) /* Reg210h ~ Reg2ffh */ +#define IT6621_TX_INT_STATUS BIT(2) /* eARC TX interrupt status */ +#define IT6621_CEC_INT_STATUS BIT(4) /* eARC CEC interrupt status */ + +/* Interrupt Status Registers */ +#define IT6621_REG_INT_STATUS0 0x10 +#define IT6621_TX_HPDIO_ON BIT(0) /* eARC TX HPDIO on interrupt */ +#define IT6621_TX_HPDIO_OFF BIT(1) /* eARC TX HPDIO off interrupt */ +#define IT6621_TX_STATE3_CHANGE BIT(2) /* eARC TX state3 change interrupt */ +#define IT6621_TX_HB_LOST BIT(3) /* eARC TX HeartBeat lost interrupt */ +#define IT6621_TX_DISV_TIMEOUT BIT(4) /* eARC TX discovery timeout interrupt */ +#define IT6621_TX_NO_AUD_CHANGE BIT(5) /* eARC TX no audio change interrupt */ +#define IT6621_TX_XP_LOCK_CHANGE BIT(6) /* eARC TX XP_LOCK change interrupt */ +#define IT6621_TX_RESYNC_ERR BIT(7) /* eARC TX ReSync error interrupt */ + +#define IT6621_REG_INT_STATUS1 0x11 +#define IT6621_TX_CMD_DONE BIT(0) /* eARC TX command done interrupt */ +#define IT6621_TX_CMD_FAIL BIT(1) /* eARC TX command fail interrupt */ +#define IT6621_TX_HB_DONE BIT(2) /* eARC TX HeartBeat done interrupt */ +#define IT6621_TX_READ_STATE_CHANGE BIT(3) /* eARC TX read EARC_RX_STAT change interrupt */ +#define IT6621_TX_CMDC_BP_ERR BIT(4) /* eARC TX CMDC bi-phase error interrupt */ +#define IT6621_TX_WRITE_STATE_CHANGE BIT(5) /* eARC TX auto write STAT_CHNG + * from '1' to '0' done + */ +#define IT6621_TX_WRITE_CAP_CHANGE BIT(6) /* eARC TX auto write CAP_CHNG + * from '1' to '0' done + */ +#define IT6621_TX_HB_FAIL BIT(7) /* eARC TX HeartBeat fail interrupt */ + +#define IT6621_REG_INT_STATUS2 0x12 +#define IT6621_TX_FIFO_ERR BIT(0) /* eARC TX FIFO error interrupt */ +#define IT6621_TX_DEC_ERR BIT(1) /* eARC TX input audio decode error interrupt */ +#define IT6621_TX_SPDIF_READY BIT(2) /* eARC TX input SPDIF channel + * status ready interrupt + */ +#define IT6621_TX_SPDIF_CHANGE BIT(3) /* eARC TX input SPDIF channel + * status change interrupt + */ +#define IT6621_TX_MUTE_CHANGE BIT(4) /* eARC TX input MUTE change interrupt */ + +#define IT6621_REG_INT_STATUS3 0x13 +#define IT6621_TX_HPDB_ON BIT(0) /* eARC TX HPDB on interrupt */ +#define IT6621_TX_HPDB_OFF BIT(1) /* eARC TX HPDB off interrupt */ + +#define IT6621_REG_INT_STATUS4 0x19 +#define IT6621_DET_ACLK_STABLE BIT(0) /* Detect ACLK stable interrupt */ +#define IT6621_DET_ACLK_VALID BIT(1) /* Detect ACLK valid interrupt */ +#define IT6621_DET_BCLK_STABLE BIT(2) /* Detect BCLK stable interrupt */ +#define IT6621_DET_BCLK_VALID BIT(3) /* Detect BCLK valid interrupt */ +#define IT6621_DET_NO_BCLK BIT(4) /* Detect no BCLK interrupt */ +#define IT6621_DET_NO_DMAC BIT(5) /* Detect no DMAC interrupt */ + +/* Interrupt Enable Registers */ +#define IT6621_REG_INT_EN0 0x1c +#define IT6621_TX_HPDIO_ON_EN BIT(0) /* Enable eARC TX HPDIO on interrupt */ +#define IT6621_TX_HPDIO_OFF_EN BIT(1) /* Enable eARC TX HPDIO off interrupt */ +#define IT6621_TX_STATE3_CHANGE_EN BIT(2) /* Enable eARC TX state3 change interrupt */ +#define IT6621_TX_HB_LOST_EN BIT(3) /* Enable eARC TX HeartBeat lost interrupt */ +#define IT6621_TX_DISV_TIMEOUT_EN BIT(4) /* Enable eARC TX discovery timeout interrupt */ +#define IT6621_TX_NO_AUD_CHANGE_EN BIT(5) /* Enable eARC TX no audio change interrupt */ +#define IT6621_TX_XP_LOCK_CHANGE_EN BIT(6) /* Enable eARC TX XP_LOCK change interrupt */ +#define IT6621_TX_RESYNC_ERR_EN BIT(7) /* Enable eARC TX ReSync error interrupt */ + +#define IT6621_REG_INT_EN1 0x1d +#define IT6621_TX_CMD_DONE_SEL BIT(0) /* Enable eARC TX command done interrupt */ +#define IT6621_TX_CMD_DONE_DIS (0x00 << 0) +#define IT6621_TX_CMD_DONE_EN (0x01 << 0) +#define IT6621_TX_CMD_FAIL_SEL BIT(1) /* Enable eARC TX command fail interrupt */ +#define IT6621_TX_CMD_FAIL_DIS (0x00 << 1) +#define IT6621_TX_CMD_FAIL_EN (0x01 << 1) +#define IT6621_TX_HB_DONE_SEL BIT(2) /* Enable eARC TX HeartBeat done interrupt */ +#define IT6621_TX_HB_DONE_DIS (0x00 << 2) +#define IT6621_TX_HB_DONE_EN (0x01 << 2) +#define IT6621_TX_READ_STATE_CHG_SEL BIT(3) /* Enable eARC TX read + * EARC_RX_STAT change interrupt + */ +#define IT6621_TX_READ_STATE_CHG_DIS (0x00 << 3) +#define IT6621_TX_READ_STATE_CHG_EN (0x01 << 3) +#define IT6621_TX_CMDC_BP_ERR_SEL BIT(4) /* Enable eARC TX CMDC bi-phase error interrupt */ +#define IT6621_TX_CMDC_BP_ERR_DIS (0x00 << 4) +#define IT6621_TX_CMDC_BP_ERR_EN (0x01 << 4) +#define IT6621_TX_WRITE_STATE_CHG_SEL BIT(5) /* Enable eARC TX auto write + * state change interrupt + */ +#define IT6621_TX_WRITE_STATE_CHG_DIS (0x00 << 5) +#define IT6621_TX_WRITE_STATE_CHG_EN (0x01 << 5) +#define IT6621_TX_WRITE_CAP_CHG_SEL BIT(6) /* Enable eARC TX auto write cap change interrupt */ +#define IT6621_TX_WRITE_CAP_CHG_DIS (0x00 << 6) +#define IT6621_TX_WRITE_CAP_CHG_EN (0x01 << 6) +#define IT6621_TX_HB_FAIL_SEL BIT(7) /* Enable eARC TX HeartBeat fail interrupt */ +#define IT6621_TX_HB_FAIL_DIS (0x00 << 7) +#define IT6621_TX_HB_FAIL_EN (0x01 << 7) + +#define IT6621_REG_INT_EN2 0x1e +#define IT6621_TX_FIFO_ERR_EN BIT(0) /* Enable eARC TX FIFO error interrupt */ +#define IT6621_TX_DEC_ERR_EN BIT(1) /* Enable eARC TX input audio + * decode error interrupt + */ +#define IT6621_TX_SPDIF_READY_EN BIT(2) /* Enable eARC TX input SPDIF + * channel status ready interrupt + */ +#define IT6621_TX_SPDIF_CHANGE_EN BIT(3) /* Enable eARC TX input SPDIF + * channel status change interrupt + */ +#define IT6621_TX_MUTE_CHANGE_EN BIT(4) /* Enable eARC TX input MUTE change interrupt */ + +#define IT6621_REG_INT_EN3 0x1f +#define IT6621_TX_HPDB_ON_EN BIT(0) /* Enable eARC TX HPDB on interrupt */ +#define IT6621_TX_HPDB_OFF_EN BIT(1) /* Enable eARC TX HPDB off interrupt */ + +#define IT6621_REG_INT_EN4 0x25 +#define IT6621_DET_ACLK_STABLE_EN BIT(0) /* Enable detect ACLK stable interrupt */ +#define IT6621_DET_ACLK_VALID_EN BIT(1) /* Enable detect ACLK valid interrupt */ +#define IT6621_DET_BCLK_STABLE_EN BIT(2) /* Enable detect BCLK stable interrupt */ +#define IT6621_DET_BCLK_VALID_EN BIT(3) /* Enable detect BCLK valid interrupt */ +#define IT6621_DET_NO_BCLK_EN BIT(4) /* Enable detect no BCLK interrupt */ +#define IT6621_DET_NO_DMAC_EN BIT(5) /* Enable detect no DMAC interrupt */ + +/* Clock Control Registers */ +#define IT6621_REG_CLK_CTRL0 0x28 +#define IT6621_RCLK_FREQ_SEL GENMASK(1, 0) /* RCLK frequency selection */ +#define IT6621_RCLK_FREQ_REFCLK (0x00 << 0) /* RCLK = REFCLK, 20MHz */ +#define IT6621_RCLK_FREQ_REFCLK_DIV_2 (0x01 << 0) /* RCLK = REFCLK/2, 10Mhz */ +#define IT6621_RCLK_FREQ_REFCLK_DIV_4 (0x02 << 0) /* RCLK = REFCLK/4, 5Mhz */ +#define IT6621_RCLK_FREQ_REFCLK_DIV_8 (0x03 << 0) /* RCLK = REFCLK/8, 2.5Mhz */ +#define IT6621_RCLK_PWD_SEL BIT(2) /* Enable RCLK power-down when IDDQ mode */ +#define IT6621_RCLK_PWD_DIS (0x00 << 2) /* disable */ +#define IT6621_RCLK_PWD_EN (0x01 << 2) /* enable */ +#define IT6621_GATE_RCLK_SEL BIT(4) /* Gating GRCLK clock domain */ +#define IT6621_GATE_RCLK_DIS (0x00 << 4) /* disable */ +#define IT6621_GATE_RCLK_EN (0x01 << 4) /* enable */ +#define IT6621_DMAC_PWD_SEL BIT(6) /* Enable DMAC power-down */ +#define IT6621_DMAC_PWD_DIS (0x00 << 6) /* disable */ +#define IT6621_DMAC_PWD_EN (0x01 << 6) /* enable */ +#define IT6621_CMDC_PWD_SEL BIT(7) /* Enable CMDC power-down */ +#define IT6621_CMDC_PWD_DIS (0x00 << 7) /* disable */ +#define IT6621_CMDC_PWD_EN (0x01 << 7) /* enable */ + +#define IT6621_REG_CLK_CTRL1 0x29 +#define IT6621_TBCLK_SEL GENMASK(2, 0) /* TBCLK selection */ +#define IT6621_TBCLK_AICLK (0x00 << 0) /* TBCLK = AICLK x 1 */ +#define IT6621_TBCLK_AICLK_MUL_2 (0x01 << 0) /* TBCLK = AICLK x 2 */ +#define IT6621_TBCLK_AICLK_MUL_4 (0x02 << 0) /* TBCLK = AICLK x 4 */ +#define IT6621_TBCLK_AICLK_MUL_8 (0x03 << 0) /* TBCLK = AICLK x 8 */ +#define IT6621_TBCLK_AICLK_MUL_16 (0x04 << 0) /* TBCLK = AICLK x 16 */ +#define IT6621_TBCLK_AICLK_MUL_32 (0x05 << 0) /* TBCLK = AICLK x 32 */ +#define IT6621_TBCLK_AUTO BIT(3) /* 1: TBCLK auto mode */ +#define IT6621_AOCLK_SEL GENMASK(6, 4) /* AOCLK selection */ +#define IT6621_AOCLK_RBCLK (0x00 << 4) /* AOCLK = RBCLK / 1 */ +#define IT6621_AOCLK_RBCLK_DIV_2 (0x01 << 4) /* AOCLK = RBCLK / 2 */ +#define IT6621_AOCLK_RBCLK_DIV_4 (0x02 << 4) /* AOCLK = RBCLK / 4 */ +#define IT6621_AOCLK_RBCLK_DIV_8 (0x03 << 4) /* AOCLK = RBCLK / 8 */ +#define IT6621_AOCLK_RBCLK_DIV_16 (0x04 << 4) /* AOCLK = RBCLK / 16 */ +#define IT6621_AOCLK_RBCLK_DIV_32 (0x05 << 4) /* AOCLK = RBCLK / 32 */ +#define IT6621_AOCLK_LCCLK (0x06 << 4) /* AOCLK = LCCLK */ +#define IT6621_AOCLK_AUTO BIT(7) /* 1: AOCLK auto mode */ + +#define IT6621_REG_CLK_CTRL2 0x2a +#define IT6621_ACLK_INV_SEL BIT(0) /* eARC ACLK inversion */ +#define IT6621_ACLK_INV_DIS (0x00 << 0) /* disable */ +#define IT6621_ACLK_INV_EN (0x01 << 0) /* enable */ +#define IT6621_BCLK_INV_SEL BIT(1) /* eARC BCLK inversion */ +#define IT6621_BCLK_INV_DIS (0x00 << 1) /* disable */ +#define IT6621_BCLK_INV_EN (0x01 << 1) /* enable */ +#define IT6621_RCCLK_OPT BIT(2) /* RCCLK option */ +#define IT6621_MCLKX2_SEL GENMASK(6, 4) /* MCLKX2 selection */ +#define IT6621_MCLKX2_RBCLKX2 (0x00 << 4) /* MCLKX2 = RBCLKX2 / 1 */ +#define IT6621_MCLKX2_RBCLKX2_DIV_2 (0x01 << 4) /* MCLKX2 = RBCLKX2 / 2 */ +#define IT6621_MCLKX2_RBCLKX2_DIV_4 (0x02 << 4) /* MCLKX2 = RBCLKX2 / 4 */ +#define IT6621_MCLKX2_RBCLKX2_DIV_8 (0x03 << 4) /* MCLKX2 = RBCLKX2 / 8 */ +#define IT6621_MCLKX2_RBCLKX2_DIV_16 (0x04 << 4) /* MCLKX2 = RBCLKX2 / 16 */ +#define IT6621_MCLKX2_RBCLKX2_DIV_32 (0x05 << 4) /* MCLKX2 = RBCLKX2 / 32 */ +#define IT6621_MCLKX2_LCCLK (0x06 << 4) /* MCLKX2 = LCCLK */ +#define IT6621_MCLKX2_AUTO BIT(7) /* 1: MCLKX2 auto mode */ + +/* eARC TX Discovery and Disconnect Registers */ +#define IT6621_REG_TX_DD0 0x30 +#define IT6621_TX_DD_FSM_SEL BIT(0) /* 1: eARC TX enable discovery and disconnect FSM */ +#define IT6621_TX_DD_FSM_DIS (0x00 << 0) +#define IT6621_TX_DD_FSM_EN (0x01 << 0) +#define IT6621_TX_EARC_SEL BIT(1) /* 1: enable eARC TX function */ +#define IT6621_TX_EARC_DIS (0x00 << 1) +#define IT6621_TX_EARC_EN (0x01 << 1) +#define IT6621_TX_ARC_SEL BIT(2) /* 1: enable ARC TX function */ +#define IT6621_TX_ARC_DIS (0x00 << 2) +#define IT6621_TX_ARC_EN (0x01 << 2) +#define IT6621_TX_ARC_NOW_SEL BIT(3) /* 1: ARC TX function is enabled now */ +#define IT6621_TX_ARC_NOW_DIS (0x00 << 3) +#define IT6621_TX_ARC_NOW_EN (0x01 << 3) +#define IT6621_TX_DISV_TIMEOUT_SEL GENMASK(5, 4) /* eARC TX discovery + * timeout selection + * (No COMMA) + */ +#define IT6621_TX_DISV_TIMEOUT_450MS (0x00 << 4) /* 450ms */ +#define IT6621_TX_DISV_TIMEOUT_475MS (0x01 << 4) /* 475ms */ +#define IT6621_TX_DISV_TIMEOUT_500MS (0x02 << 4) /* 500ms */ +#define IT6621_TX_DISV_TIMEOUT_600MS (0x03 << 4) /* 600ms */ +#define IT6621_TX_HB_POS_SEL GENMASK(7, 6) /* eARC TX HeartBeat position selection */ +#define IT6621_TX_HB_POS_1MS (0x00 << 6) /* 1ms */ +#define IT6621_TX_HB_POS_3MS (0x01 << 6) /* 3ms */ +#define IT6621_TX_HB_POS_5MS (0x02 << 6) /* 5ms */ +#define IT6621_TX_HB_POS_7MS (0x03 << 6) /* 7ms */ + +#define IT6621_REG_TX_DD1 0x31 +#define IT6621_TX_COMMA_SEL GENMASK(1, 0) /* eARC TX valid COMMA selection */ +#define IT6621_TX_COMMA_8_12MS (0x00 << 0) /* 8~12ms */ +#define IT6621_TX_COMMA_7_13MS (0x01 << 0) /* 7~13ms */ +#define IT6621_TX_COMMA_6_14MS (0x02 << 0) /* 6~14ms */ +#define IT6621_TX_COMMA_5_15MS (0x03 << 0) /* 5~15ms */ +#define IT6621_TX_COMMA_OPT BIT(2) /* eARC TX COMMA bit error + * tolerance, 0: no tolerance, + * 1: 1-bit tolerance + */ + +#define IT6621_REG_TX_DD2 0x32 +#define IT6621_TX_DD_FSM_STATE GENMASK(5, 0) /* eARC TX discovery and + * disconnect FSM state + */ +#define IT6621_TX_EARC_MODE (0x08 << 0) +#define IT6621_TX_ARC_MODE (0x20 << 0) + +#define IT6621_REG_TX_DD3 0x33 +#define IT6621_TX_FORCE_ARC_MODE_SEL BIT(0) /* force TX ARC mode */ +#define IT6621_TX_FORCE_ARC_MODE_DIS (0x00 << 0) +#define IT6621_TX_FORCE_ARC_MODE_EN (0x01 << 0) + +/* eARC TX CMDC Registers */ +#define IT6621_REG_CMDC0 0x40 +#define IT6621_TX_CMD_TIMEOUT_EN BIT(0) /* 1: eARC TX enable NACK/RETRY timeout (256-time) */ +#define IT6621_TX_NACK_DELAY_EN BIT(1) /* 1: eARC TX enable NACK delay */ +#define IT6621_TX_DEBUG_FIFO_EN BIT(2) /* 1: eARC TX enable debug FIFO */ +#define IT6621_TX_NEXT_PKT_TIMEOUT_SEL BIT(3) /* eARC TX next packet timeout selection */ +#define IT6621_TX_NEXT_PKT_TIMEOUT_30US (0x00 << 3) /* 30us */ +#define IT6621_TX_NEXT_PKT_TIMEOUT_50US (0x01 << 3) /* 50us */ +#define IT6621_TX_NACK_DELAY_SEL GENMASK(5, 4) /* eARC TX NACK packet delay time selection */ +#define IT6621_TX_NACK_DELAY_500US (0x00 << 4) /* 500us */ +#define IT6621_TX_NACK_DELAY_1MS (0x01 << 4) /* 1ms */ +#define IT6621_TX_NACK_DELAY_2MS (0x02 << 4) /* 2ms */ +#define IT6621_TX_NACK_DELAY_4MS (0x03 << 4) /* 4ms */ +#define IT6621_TX_TURN_OVER_SEL GENMASK(7, 6) /* eARC TX turn-over time + * selection before + * transmitting packet + */ +#define IT6621_TX_TURN_OVER_8US (0x00 << 6) /* 8us */ +#define IT6621_TX_TURN_OVER_16US (0x01 << 6) /* 16us */ +#define IT6621_TX_TURN_OVER_24US (0x02 << 6) /* 24us */ + +#define IT6621_REG_CMDC1 0x41 +#define IT6621_TX_CMDC_STATE GENMASK(3, 0) /* eARC TX CMDC state */ +#define IT6621_TX_CMDC_STATE_IDLE (0x00 << 0) /* IDLE */ +#define IT6621_TX_CMDC_STATE_CMD (0x01 << 0) /* TX Cmd */ +#define IT6621_TX_CMDC_STATE_DEVID (0x02 << 0) /* TX DevID */ +#define IT6621_TX_CMDC_STATE_OFFSET (0x03 << 0) /* TX Offset */ +#define IT6621_TX_CMDC_STATE_CONT1 (0x04 << 0) /* TX Cont1 */ +#define IT6621_TX_CMDC_STATE_CONT2 (0x05 << 0) /* TX Cont2 */ +#define IT6621_TX_CMDC_STATE_RETRY (0x06 << 0) /* TX Retry */ +#define IT6621_TX_CMDC_STATE_DATA1 (0x07 << 0) /* TX Data1 */ +#define IT6621_TX_CMDC_STATE_DATA2 (0x08 << 0) /* TX Data2 */ +#define IT6621_TX_CMDC_STATE_STOP (0x09 << 0) /* TX Stop */ +#define IT6621_TX_FAIL_STATE GENMASK(7, 4) +#define IT6621_TX_FAIL_STATE_NO_RESP BIT(4) /* No response */ +#define IT6621_TX_FAIL_STATE_UNEXP_RESP BIT(5) /* Unexpected response */ +#define IT6621_TX_FAIL_STATE_ECC_ERR BIT(6) /* Uncorrectable ECC error */ +#define IT6621_TX_FAIL_STATE_TIMEOUT BIT(7) /* NACK/RETRY 256 times timeout */ + +#define IT6621_REG_TX_DEV_ID 0x42 /* eARC TX device ID */ +#define IT6621_REG_TX_OFFSET 0x43 /* eARC TX offset value */ + +#define IT6621_REG_CMDC2 0x44 +#define IT6621_TX_BYTE_NO GENMASK(4, 0) /* eARC TX byte number (1~32 bytes) */ +#define IT6621_TX_CMD_BUSY BIT(5) /* 1: eARC TX command busy */ +#define IT6621_TX_WRITE_TRIGGER BIT(6) /* eARC TX write trigger */ +#define IT6621_TX_READ_TRIGGER BIT(7) /* eARC TX read trigger */ + +#define IT6621_REG_TX_DATA_FIFO 0x45 /* eARC TX data FIFO of read/write + * data (32-stage FIFO) + */ + +#define IT6621_REG_CMDC3 0x46 +#define IT6621_TX_DATA_FIFO_STAGE GENMASK(5, 0) /* eARC TX data FIFO stage */ +#define IT6621_TX_DATA_FIFO_EMPTY (0x00 << 0) /* FIFO empty */ +#define IT6621_TX_DATA_FIFO_FULL (0x20 << 0) /* FIFO full */ +#define IT6621_TX_DATA_FIFO_ERR BIT(6) /* eARC TX data FIFO error */ +#define IT6621_TX_DATA_FIFO_CLEAR BIT(7) /* eARC TX data FIFO clear */ + +#define IT6621_REG_CMDC4 0x47 +#define IT6621_TX_AUTO_HB_EN BIT(0) /* eARC TX auto HeartBeat, 0: disable, 1: enable */ +#define IT6621_TX_AUTO_HB_BUSY BIT(1) /* 1: eARC TX auto HeartBeat busy */ +#define IT6621_TX_HB_TIME_SEL GENMASK(3, 2) /* eARC TX auto HeartBeat time selection */ +#define IT6621_TX_HB_TIME_35MS (0x00 << 2) /* 35ms */ +#define IT6621_TX_HB_TIME_40MS (0x01 << 2) /* 40ms */ +#define IT6621_TX_HB_TIME_45MS (0x02 << 2) /* 45ms */ +#define IT6621_TX_HB_TIME_50MS (0x03 << 2) /* 50ms */ +#define IT6621_TX_HB_RETRY_SEL BIT(4) /* eARC TX auto HeartBeat retry, + * 0: disable, 1: enable + */ +#define IT6621_TX_HB_RETRY_DIS (0x00 << 4) +#define IT6621_TX_HB_RETRY_EN (0x01 << 4) +#define IT6621_TX_HB_TRIGGER BIT(5) /* eARC TX HeartBeat trigger */ +#define IT6621_TX_HB_RETRY_TIME_SEL GENMASK(7, 6) /* eARC TX HeartBeat retry time selection */ +#define IT6621_TX_HB_RETRY_0MS (0x00 << 6) /* 0ms */ +#define IT6621_TX_HB_RETRY_4MS (0x01 << 6) /* 4ms */ +#define IT6621_TX_HB_RETRY_8MS (0x02 << 6) /* 8ms */ +#define IT6621_TX_HB_RETRY_16MS (0x03 << 6) /* 16ms */ + +#define IT6621_REG_TX_READ_STATE 0x48 /* eARC TX read back value of EARC_RX_STAT */ +#define IT6621_EARC_RX_STAT_EARC_HPD BIT(0) +#define IT6621_EARC_RX_STAT_CAP_CHNG BIT(3) +#define IT6621_EARC_RX_STAT_STAT_CHNG BIT(4) + +#define IT6621_REG_CMDC5 0x49 +#define IT6621_TX_AUTO_WRITE_STATE_SEL BIT(0) /* 1: eARC TX auto write EARC_TX_STAT[7:1] */ +#define IT6621_TX_AUTO_WRITE_STATE_DIS (0x00 << 0) /* to pass SL-870 HFR5-1-35/36/37 */ +#define IT6621_TX_AUTO_WRITE_STATE_EN (0x01 << 0) +#define IT6621_TX_WRITE_STATE GENMASK(7, 1) /* eARC TX write value of EARC_TX_STAT[7:1] */ + +#define IT6621_REG_CMDC6 0x4a +#define IT6621_TX_CMO_OPT BIT(0) /* eARC TX common mode output enable option */ +#define IT6621_TX_CMO_NORMAL (0x00 << 0) /* normal */ +#define IT6621_TX_CMO_PRE_1BIT (0x01 << 0) /* 1-bit before normal */ +#define IT6621_TX_FORCE_CMO_OPT BIT(1) /* eARC TX common mode output enable option */ +#define IT6621_TX_FORCE_CMO_NORMAL (0x00 << 1) /* normal */ +#define IT6621_TX_FORCE_CMO_EN (0x01 << 1) /* force output enable */ +#define IT6621_TX_RESYNC_OPT BIT(2) /* eARC TX common mode resync option */ +#define IT6621_TX_RESYNC_OLD (0x00 << 2) /* old */ +#define IT6621_TX_RESYNC_NEW (0x01 << 2) /* new */ + +#define IT6621_REG_TX_DEBUG_FIFO0 0x4d /* eARC TX debug FIFO (32-stage + * FIFO), Cmd[7:0]/Data[7:0] + */ + +#define IT6621_REG_TX_DEBUG_FIFO1 0x4e +#define IT6621_TX_DEBUG_FIFO_CD BIT(0) /* C/D */ +#define IT6621_TX_DEBUG_FIFO_DATA (0x00 << 0) /* Data */ +#define IT6621_TX_DEBUG_FIFO_CMD (0x01 << 0) /* Cmd */ +#define IT6621_TX_DEBUG_FIFO_IO BIT(1) /* I/O */ +#define IT6621_TX_DEBUG_FIFO_INPUT_PKT (0x00 << 1) /* input packet */ +#define IT6621_TX_DEBUG_FIFO_OUTPUT_PKT (0x01 << 1) /* output packet */ +#define IT6621_TX_DEBUG_FIFO_ECC_ERR BIT(2) /* 1: ECC error */ + +#define IT6621_REG_TX_DEBUG_FIFO2 0x4f +#define IT6621_TX_DEBUG_FIFO_STAGE GENMASK(5, 0) /* eARC TX debug FIFO stage */ +#define IT6621_TX_DEBUG_FIFO_EMPTY (0x00 << 0) /* FIFO empty */ +#define IT6621_TX_DEBUG_FIFO_FULL (0x20 << 0) /* FIFO full */ +#define IT6621_TX_DEBUG_FIFO_ERR BIT(6) /* eARC TX debug FIFO error */ +#define IT6621_TX_DEBUG_FIFO_CLEAR_SEL BIT(7) /* eARC TX debug FIFO clear */ +#define IT6621_TX_DEBUG_FIFO_CLEAR_DIS (0x00 << 7) /* FIFO empty */ +#define IT6621_TX_DEBUG_FIFO_CLEAR_EN (0x01 << 7) + +/* eARC TX DMAC Control Registers */ +#define IT6621_REG_DMAC_CTRL0 0x60 +#define IT6621_TX_ECC_EN BIT(0) /* eARC TX ECC, 0: disable, 1: enable */ +#define IT6621_TX_AUTO_ECC BIT(1) /* 1: eARC TX auto ECC */ +#define IT6621_TX_ECC_OPT BIT(2) /* eARC TX ECC option */ +#define IT6621_TX_ECC_VC_SWAP (0x00 << 2) /* vc swap */ +#define IT6621_TX_ECC_U_SWAP (0x01 << 2) /* u swap */ +#define IT6621_TX_ENC_SEL BIT(3) /* eARC TX encryption, 0: disable, 1: enable */ +#define IT6621_TX_ENC_DIS (0x00 << 3) /* disable */ +#define IT6621_TX_ENC_EN (0x01 << 3) /* enable */ +#define IT6621_TX_ENC_OPT GENMASK(5, 4) /* eARC TX encryption option */ +#define IT6621_TX_ENC_OPT0 (0x00 << 4) +#define IT6621_TX_ENC_OPT1 (0x01 << 4) +#define IT6621_TX_ENC_OPT2 (0x02 << 4) +#define IT6621_TX_ENC_OPT3 (0x03 << 4) + +#define IT6621_REG_TX_ENC_SEED_LOW 0x61 /* eARC TX encryption seed */ +#define IT6621_REG_TX_ENC_SEED_HIGH 0x62 /* eARC TX encryption seed */ + +#define IT6621_REG_DMAC_CTRL1 0x63 +#define IT6621_TX_MANUAL_RESET_EN_SEL BIT(0) /* 1: enable eARC TX audio FIFO manual reset */ +#define IT6621_TX_MANUAL_RESET_DIS (0x00 << 0) +#define IT6621_TX_MANUAL_RESET_EN (0x01 << 0) +#define IT6621_TX_AUTO_RESET_EN BIT(1) /* 1: enable eARC TX audio FIFO auto reset */ +#define IT6621_TX_PKT1_EN_SEL BIT(2) /* 1: enable eARC TX packet 1 using U-bit */ +#define IT6621_TX_PKT1_DIS (0x00 << 2) +#define IT6621_TX_PKT1_EN (0x01 << 2) +#define IT6621_TX_PKT2_EN_SEL BIT(3) /* 1: enable eARC TX packet 2 using U-bit */ +#define IT6621_TX_PKT2_DIS (0x00 << 3) +#define IT6621_TX_PKT2_EN (0x01 << 3) +#define IT6621_TX_PKT3_EN_SEL BIT(4) /* 1: enable eARC TX packet 3 using U-bit */ +#define IT6621_TX_PKT3_DIS (0x00 << 4) +#define IT6621_TX_PKT3_EN (0x01 << 4) +#define IT6621_TX_C_CH_OPT BIT(5) /* 1: eARC TX U-bit C-Ch option */ +#define IT6621_TX_C_CH_OPT1 (0x00 << 5) /* use RegTxChSt[14:8] for + * C-Ch[14:8] and + * RegTxPktCH[7:0] is for + * CH[7:0] which should be + * set 0x00 + */ +#define IT6621_TX_C_CH_OPT2 (0x01 << 5) /* use RegTxPktCH[6:0] for + * C-Ch[14:8] and CH[7:0] + * is set 0x00 + */ +#define IT6621_TX_U_BIT_OPT BIT(6) /* U-bit option */ +#define IT6621_TX_U_BIT_1BIT_FRAME (0x00 << 6) /* 1-bit/frame */ +#define IT6621_TX_U_BIT_1BIT_SUB_FRAME (0x01 << 6) /* 1-bit/sub-frame */ +#define IT6621_TX_V_BIT_VAL BIT(7) /* V-bit value */ +#define IT6621_TX_V_BIT_LPCM (0x00 << 7) /* LPCM */ +#define IT6621_TX_V_BIT_NLPCM (0x01 << 7) /* NLPCM */ + +/* Input Audio Control Registers */ +#define IT6621_REG_TX_AUD_SRC_EN 0x80 /* Enable input audio source */ +#define IT6621_AUD_SRC0_EN BIT(0) /* for audio source 0 */ +#define IT6621_AUD_SRC1_EN BIT(1) /* for audio source 1 */ +#define IT6621_AUD_SRC2_EN BIT(2) /* for audio source 2 */ +#define IT6621_AUD_SRC3_EN BIT(3) /* for audio source 3 */ +#define IT6621_AUD_SRC4_EN BIT(4) /* for audio source 4 */ +#define IT6621_AUD_SRC5_EN BIT(5) /* for audio source 5 */ +#define IT6621_AUD_SRC6_EN BIT(6) /* for audio source 6 */ +#define IT6621_AUD_SRC7_EN BIT(7) /* for audio source 7 */ +#define IT6621_AUD_SRC7_SRC0_EN (IT6621_AUD_SRC7_EN | \ + IT6621_AUD_SRC6_EN | \ + IT6621_AUD_SRC5_EN | \ + IT6621_AUD_SRC4_EN | \ + IT6621_AUD_SRC3_EN | \ + IT6621_AUD_SRC2_EN | \ + IT6621_AUD_SRC1_EN | \ + IT6621_AUD_SRC0_EN) +#define IT6621_AUD_SRC6_SRC0_EN (IT6621_AUD_SRC6_EN | \ + IT6621_AUD_SRC5_EN | \ + IT6621_AUD_SRC4_EN | \ + IT6621_AUD_SRC3_EN | \ + IT6621_AUD_SRC2_EN | \ + IT6621_AUD_SRC1_EN | \ + IT6621_AUD_SRC0_EN) +#define IT6621_AUD_SRC5_SRC0_EN (IT6621_AUD_SRC5_EN | \ + IT6621_AUD_SRC4_EN | \ + IT6621_AUD_SRC3_EN | \ + IT6621_AUD_SRC2_EN | \ + IT6621_AUD_SRC1_EN | \ + IT6621_AUD_SRC0_EN) +#define IT6621_AUD_SRC4_SRC0_EN (IT6621_AUD_SRC4_EN | \ + IT6621_AUD_SRC3_EN | \ + IT6621_AUD_SRC2_EN | \ + IT6621_AUD_SRC1_EN | \ + IT6621_AUD_SRC0_EN) +#define IT6621_AUD_SRC3_SRC0_EN (IT6621_AUD_SRC3_EN | \ + IT6621_AUD_SRC2_EN | \ + IT6621_AUD_SRC1_EN | \ + IT6621_AUD_SRC0_EN) +#define IT6621_AUD_SRC2_SRC0_EN (IT6621_AUD_SRC2_EN | \ + IT6621_AUD_SRC1_EN | \ + IT6621_AUD_SRC0_EN) +#define IT6621_AUD_SRC1_SRC0_EN (IT6621_AUD_SRC1_EN | \ + IT6621_AUD_SRC0_EN) + +#define IT6621_REG_TX_AUD_SRC_SEL 0x81 /* Input audio source selection */ +#define IT6621_TX_AUD_SRC GENMASK(1, 0) /* eARC TX encryption option */ +#define IT6621_AUD_SRC_I2S (0x00 << 0) /* I2S */ +#define IT6621_AUD_SRC_SPDIF (0x01 << 0) /* SPDIF */ +#define IT6621_AUD_SRC_TDM (0x02 << 0) /* TDM */ +#define IT6621_AUD_SRC_DSD (0x03 << 0) /* DSD */ + +#define IT6621_REG_TX_I2S 0x82 +#define IT6621_I2S_FMT GENMASK(4, 0) /* TX I2S/TDM format */ +#define IT6621_I2S_FMT_STANDARD (0x00 << 0) /* Standard I2S */ +#define IT6621_I2S_FMT_32BIT (0x01 << 0) /* 32-bit I2S */ +#define IT6621_I2S_FMT_LEFT_JUSTIFIED (0x00 << 1) /* Left-justified */ +#define IT6621_I2S_FMT_RIGHT_JUSTIFIED (0x01 << 1) /* Right-justified */ +#define IT6621_I2S_FMT_DATA_DELAY (0x00 << 2) /* Data delay 1T correspond to WS */ +#define IT6621_I2S_FMT_NO_DATA_DELAY (0x01 << 2) /* No data delay correspond to WS */ +#define IT6621_I2S_FMT_WS_0_LEFT_CH (0x00 << 3) /* WS=0 is left channel */ +#define IT6621_I2S_FMT_WS_0_RIGHT_CH (0x01 << 3) /* WS=0 is right channel */ +#define IT6621_I2S_FMT_MSB_FIRST (0x00 << 4) /* MSB shift first */ +#define IT6621_I2S_FMT_LSB_FIRST (0x01 << 4) /* LSB shift first */ +#define IT6621_I2S_TDM_WORD_LEN GENMASK(6, 5) /* TX I2S/TDM word length */ +#define IT6621_I2S_TDM_16BIT (0x00 << 5) /* 16 bits */ +#define IT6621_I2S_TDM_18BIT (0x01 << 5) /* 18 bits */ +#define IT6621_I2S_TDM_20BIT (0x02 << 5) /* 20 bits */ +#define IT6621_I2S_TDM_24BIT (0x03 << 5) /* 24 bits */ + +#define IT6621_REG_TX_AUD_CTRL3 0x83 +#define IT6621_TX_TDM_CH_NUM GENMASK(2, 0) /* TX TDM interface channel number */ +#define IT6621_TX_TDM_2CH (0x00 << 0) /* 2-ch */ +#define IT6621_TX_TDM_4CH (0x01 << 0) /* 4-ch */ +#define IT6621_TX_TDM_8CH (0x03 << 0) /* 8-ch */ +#define IT6621_TX_TDM_16CH (0x07 << 0) /* 16-ch */ +#define IT6621_TX_I2S_HBR_EN_SEL BIT(3) /* enable TX I2S HBR input */ +#define IT6621_TX_I2S_HBR_DIS (0x00 << 3) +#define IT6621_TX_I2S_HBR_EN (0x01 << 3) +#define IT6621_TX_DSD_MODE BIT(4) /* TX DSD mode */ +#define IT6621_TX_DSD_MODE_NORMAL (0x00 << 4) /* normal mode */ +#define IT6621_TX_DSD_MODE_PHASE (0x01 << 4) /* phase mode */ +#define IT6621_TX_DSD_BIT_INV_SEL BIT(5) /* TX DSD data inversion */ +#define IT6621_TX_DSD_BIT_NO_INV (0x00 << 5) /* not inverse */ +#define IT6621_TX_DSD_BIT_INV (0x01 << 5) /* inverse */ +#define IT6621_TX_DSD_LM_SWAP_SEL BIT(6) /* TX DSD LSB/MSB swap */ +#define IT6621_TX_DSD_LM_NO_SWAP (0x00 << 6) /* no swap */ +#define IT6621_TX_DSD_LM_SWAP (0x01 << 6) /* swap */ +#define IT6621_TX_DSD_LR_SWAP_SEL BIT(7) /* TX DSD L/R swap */ +#define IT6621_TX_DSD_LR_NO_SWAP (0x00 << 7) /* no swap */ +#define IT6621_TX_DSD_LR_SWAP (0x01 << 7) /* swap */ + +#define IT6621_REG_TX_AUD_SEL1 0x84 +#define IT6621_TX_AUD0_SEL GENMASK(2, 0) /* TX audio 0 input selection */ +#define IT6621_TX_AUD0_FROM_SRC0 (0x00 << 0) /* from audio source 0 */ +#define IT6621_TX_AUD0_FROM_SRC1 (0x01 << 0) /* from audio source 1 */ +#define IT6621_TX_AUD0_FROM_SRC2 (0x02 << 0) /* from audio source 2 */ +#define IT6621_TX_AUD0_FROM_SRC3 (0x03 << 0) /* from audio source 3 */ +#define IT6621_TX_AUD0_FROM_SRC4 (0x04 << 0) /* from audio source 4 */ +#define IT6621_TX_AUD0_FROM_SRC5 (0x05 << 0) /* from audio source 5 */ +#define IT6621_TX_AUD0_FROM_SRC6 (0x06 << 0) /* from audio source 6 */ +#define IT6621_TX_AUD0_FROM_SRC7 (0x07 << 0) /* from audio source 7 */ +#define IT6621_TX_AUD1_SEL GENMASK(6, 4) /* TX audio 1 input selection */ +#define IT6621_TX_AUD1_FROM_SRC0 (0x00 << 4) /* from audio source 0 */ +#define IT6621_TX_AUD1_FROM_SRC1 (0x01 << 4) /* from audio source 1 */ +#define IT6621_TX_AUD1_FROM_SRC2 (0x02 << 4) /* from audio source 2 */ +#define IT6621_TX_AUD1_FROM_SRC3 (0x03 << 4) /* from audio source 3 */ +#define IT6621_TX_AUD1_FROM_SRC4 (0x04 << 4) /* from audio source 4 */ +#define IT6621_TX_AUD1_FROM_SRC5 (0x05 << 4) /* from audio source 5 */ +#define IT6621_TX_AUD1_FROM_SRC6 (0x06 << 4) /* from audio source 6 */ +#define IT6621_TX_AUD1_FROM_SRC7 (0x07 << 4) /* from audio source 7 */ + +#define IT6621_REG_TX_AUD_SEL2 0x85 +#define IT6621_TX_AUD2_SEL GENMASK(2, 0) /* TX audio 2 input selection */ +#define IT6621_TX_AUD2_FROM_SRC0 (0x00 << 0) /* from audio source 0 */ +#define IT6621_TX_AUD2_FROM_SRC1 (0x01 << 0) /* from audio source 1 */ +#define IT6621_TX_AUD2_FROM_SRC2 (0x02 << 0) /* from audio source 2 */ +#define IT6621_TX_AUD2_FROM_SRC3 (0x03 << 0) /* from audio source 3 */ +#define IT6621_TX_AUD2_FROM_SRC4 (0x04 << 0) /* from audio source 4 */ +#define IT6621_TX_AUD2_FROM_SRC5 (0x05 << 0) /* from audio source 5 */ +#define IT6621_TX_AUD2_FROM_SRC6 (0x06 << 0) /* from audio source 6 */ +#define IT6621_TX_AUD2_FROM_SRC7 (0x07 << 0) /* from audio source 7 */ +#define IT6621_TX_AUD3_SEL GENMASK(6, 4) /* TX audio 3 input selection */ +#define IT6621_TX_AUD3_FROM_SRC0 (0x00 << 4) /* from audio source 0 */ +#define IT6621_TX_AUD3_FROM_SRC1 (0x01 << 4) /* from audio source 1 */ +#define IT6621_TX_AUD3_FROM_SRC2 (0x02 << 4) /* from audio source 2 */ +#define IT6621_TX_AUD3_FROM_SRC3 (0x03 << 4) /* from audio source 3 */ +#define IT6621_TX_AUD3_FROM_SRC4 (0x04 << 4) /* from audio source 4 */ +#define IT6621_TX_AUD3_FROM_SRC5 (0x05 << 4) /* from audio source 5 */ +#define IT6621_TX_AUD3_FROM_SRC6 (0x06 << 4) /* from audio source 6 */ +#define IT6621_TX_AUD3_FROM_SRC7 (0x07 << 4) /* from audio source 7 */ + +#define IT6621_REG_TX_AUD_SEL3 0x86 +#define IT6621_TX_AUD4_SEL GENMASK(2, 0) /* TX audio 4 input selection */ +#define IT6621_TX_AUD4_FROM_SRC0 (0x00 << 0) /* from audio source 0 */ +#define IT6621_TX_AUD4_FROM_SRC1 (0x01 << 0) /* from audio source 1 */ +#define IT6621_TX_AUD4_FROM_SRC2 (0x02 << 0) /* from audio source 2 */ +#define IT6621_TX_AUD4_FROM_SRC3 (0x03 << 0) /* from audio source 3 */ +#define IT6621_TX_AUD4_FROM_SRC4 (0x04 << 0) /* from audio source 4 */ +#define IT6621_TX_AUD4_FROM_SRC5 (0x05 << 0) /* from audio source 5 */ +#define IT6621_TX_AUD4_FROM_SRC6 (0x06 << 0) /* from audio source 6 */ +#define IT6621_TX_AUD4_FROM_SRC7 (0x07 << 0) /* from audio source 7 */ +#define IT6621_TX_AUD5_SEL GENMASK(6, 4) /* TX audio 5 input selection */ +#define IT6621_TX_AUD5_FROM_SRC0 (0x00 << 4) /* from audio source 0 */ +#define IT6621_TX_AUD5_FROM_SRC1 (0x01 << 4) /* from audio source 1 */ +#define IT6621_TX_AUD5_FROM_SRC2 (0x02 << 4) /* from audio source 2 */ +#define IT6621_TX_AUD5_FROM_SRC3 (0x03 << 4) /* from audio source 3 */ +#define IT6621_TX_AUD5_FROM_SRC4 (0x04 << 4) /* from audio source 4 */ +#define IT6621_TX_AUD5_FROM_SRC5 (0x05 << 4) /* from audio source 5 */ +#define IT6621_TX_AUD5_FROM_SRC6 (0x06 << 4) /* from audio source 6 */ +#define IT6621_TX_AUD5_FROM_SRC7 (0x07 << 4) /* from audio source 7 */ + +#define IT6621_REG_TX_AUD_SEL4 0x87 +#define IT6621_TX_AUD6_SEL GENMASK(2, 0) /* TX audio 6 input selection */ +#define IT6621_TX_AUD6_FROM_SRC0 (0x00 << 0) /* from audio source 0 */ +#define IT6621_TX_AUD6_FROM_SRC1 (0x01 << 0) /* from audio source 1 */ +#define IT6621_TX_AUD6_FROM_SRC2 (0x02 << 0) /* from audio source 2 */ +#define IT6621_TX_AUD6_FROM_SRC3 (0x03 << 0) /* from audio source 3 */ +#define IT6621_TX_AUD6_FROM_SRC4 (0x04 << 0) /* from audio source 4 */ +#define IT6621_TX_AUD6_FROM_SRC5 (0x05 << 0) /* from audio source 5 */ +#define IT6621_TX_AUD6_FROM_SRC6 (0x06 << 0) /* from audio source 6 */ +#define IT6621_TX_AUD6_FROM_SRC7 (0x07 << 0) /* from audio source 7 */ +#define IT6621_TX_AUD7_SEL GENMASK(6, 4) /* TX audio 7 input selection */ +#define IT6621_TX_AUD7_FROM_SRC0 (0x00 << 4) /* from audio source 0 */ +#define IT6621_TX_AUD7_FROM_SRC1 (0x01 << 4) /* from audio source 1 */ +#define IT6621_TX_AUD7_FROM_SRC2 (0x02 << 4) /* from audio source 2 */ +#define IT6621_TX_AUD7_FROM_SRC3 (0x03 << 4) /* from audio source 3 */ +#define IT6621_TX_AUD7_FROM_SRC4 (0x04 << 4) /* from audio source 4 */ +#define IT6621_TX_AUD7_FROM_SRC5 (0x05 << 4) /* from audio source 5 */ +#define IT6621_TX_AUD7_FROM_SRC6 (0x06 << 4) /* from audio source 6 */ +#define IT6621_TX_AUD7_FROM_SRC7 (0x07 << 4) /* from audio source 7 */ + +#define IT6621_REG_TX_AUD_FORCE_OUTPUT 0x88 /* 1: force output data to 24-bit '0' */ + +#define IT6621_REG_TX_AUD_CTRL9 0x89 +#define IT6621_TX_SPDIF_REC_EN BIT(0) /* 1: enable SPDIF input record channel status */ +#define IT6621_TX_SPDIF_ERR_DET_EN BIT(1) /* 1: enable SPDIF input channel + * status error detection + */ +#define IT6621_TX_MCLK_FREQ GENMASK(3, 2) /* Input MCLK frequency selection */ +#define IT6621_TX_MCLK_FREQ_128FS (0x00 << 2) /* 128FS */ +#define IT6621_TX_MCLK_FREQ_256FS (0x01 << 2) /* 256FS */ +#define IT6621_TX_MCLK_FREQ_512FS (0x02 << 2) /* 512FS */ +#define IT6621_TX_MCLK_FREQ_1024FS (0x03 << 2) /* 1024FS */ +#define IT6621_TX_MUTE_TO_OFF_EN BIT(4) /* 1: enable TXMUTE to audio off */ +#define IT6621_TX_FIFO_ERR_TO_MUTE_EN BIT(5) /* 1: enable FIFO error to audio mute */ +#define IT6621_TX_NO_CLK_TO_MUTE_EN BIT(6) /* 1: enable no TBCLK to audio mute */ +#define IT6621_TX_UNSTB_CLK_TO_MUTE_EN BIT(7) /* 1: enable TBCLK unstable to audio mute */ + +#define IT6621_REG_TX_AUD_CTRL10 0x8a +#define IT6621_TX_EXT_MUTE_SEL BIT(0) /* external MUTE input + * RegEnTxMute=RegF0[1] at FPGA + * register (SlvAddr=0x88) + */ +#define IT6621_TX_EXT_MUTE_EN (0x00 << 0) /* enable */ +#define IT6621_TX_EXT_MUTE_DIS (0x01 << 0) /* disable */ +#define IT6621_TX_AUTO_CH_STAT_MUTE_SEL BIT(1) /* eARC TX channel status MUTE auto mode */ +#define IT6621_TX_AUTO_CH_STAT_MUTE_DIS (0x00 << 1) /* disable */ +#define IT6621_TX_AUTO_CH_STAT_MUTE_EN (0x01 << 1) /* enable */ +#define IT6621_TX_AUTO_AUD_FMT_SEL BIT(2) /* eARC TX channel status audio format auto mode */ +#define IT6621_TX_AUTO_AUD_FMT_DIS (0x00 << 2) /* disable */ +#define IT6621_TX_AUTO_AUD_FMT_EN (0x01 << 2) /* enable */ +#define IT6621_TX_AUTO_LAYOUT_SEL BIT(3) /* eARC TX channel status layout auto mode */ +#define IT6621_TX_AUTO_LAYOUT_DIS (0x00 << 3) /* disable */ +#define IT6621_TX_AUTO_LAYOUT_EN (0x01 << 3) /* enable */ +#define IT6621_TX_MCH_LPCM_SEL BIT(4) /* eARC TX force multi-channel LPCM */ +#define IT6621_TX_MCH_LPCM_DIS (0x00 << 4) /* disable */ +#define IT6621_TX_MCH_LPCM_EN (0x01 << 4) /* enable */ +#define IT6621_TX_NLPCM_I2S_SEL BIT(5) /* eARC TX force NLPCM from I2S interface */ +#define IT6621_TX_NLPCM_I2S_DIS (0x00 << 5) /* disable */ +#define IT6621_TX_NLPCM_I2S_EN (0x01 << 5) /* enable */ +#define IT6621_TX_2CH_LAYOUT_SEL BIT(6) /* eARC TX force 2-channel layout */ +#define IT6621_TX_2CH_LAYOUT_DIS (0x00 << 6) /* disable */ +#define IT6621_TX_2CH_LAYOUT_EN (0x01 << 6) /* enable */ +#define IT6621_TX_FORCE_MUTE_SEL BIT(7) /* force TXMUTE */ +#define IT6621_TX_FORCE_MUTE_DIS (0x00 << 7) /* disable */ +#define IT6621_TX_FORCE_MUTE_EN (0x01 << 7) /* enable */ + +/* eARC TX AFE Registers */ +#define IT6621_REG_TX_AFE0 0xa0 +#define IT6621_TX_XP_RESET_SEL BIT(0) /* Reset PLL, low active */ +#define IT6621_TX_XP_RESET_ACTIVE (0x00 << 0) /* active */ +#define IT6621_TX_XP_RESET_INACTIVE (0x01 << 0) /* inactive */ +#define IT6621_TX_XP_PWD BIT(1) /* Power down PLL, low active */ +#define IT6621_TX_XP_IPWD BIT(2) /* Power down the bias for PLL and LC, low active */ + +#define IT6621_REG_TX_AFE1 0xa1 +#define IT6621_TX_XP_PDIV GENMASK(1, 0) /* Set PDIV[1:0] by + * TBCLKSEL[2:0] and the + * frequency of AICLK. + * When TBCLKSEL=101, set 00 + * When TBCLKSEL=100 + * 2.048MHz~3.072MHz: set 00 + * 4.096MHz~6.144MHz: set 01 + * When TBCLKSEL=011 + * 2.048MHz~3.072MHz: set 00 + * 4.096MHz~6.144MHz: set 01 + * 8.192MHz~12.288MHz: set 10 or 11 + * When TBCLKSEL=010 + * 4.096MHz~6.144MHz: set 00 + * 8.192MHz~12.288MHz: set 01 + * 16.384MHz~24.576MHz: set 10 or 11 + * When TBCLKSEL=001 + * 2.048MHz~12.288MHz: set 00 + * 16.384MHz~24.576MHz: set 01 + * 32.768MHz~49.152MHz: set 10 or 11 + * When TBCLKSEL=000 + * 4.096MHz~24.576MHz: set 00 + * 32.768MHz~49.152MHz: set 01 + * 65.536MHz~98.304MHz: set 10 or 11 + */ +#define IT6621_TX_XP_GAIN BIT(2) /* Set GAIN by TBCLKSEL[2:0] and + * the frequency of AICLK + * When TBCLK=000, 4.096MHz~6.144MHz: set 0 + * When TBCLK=001, 2.048MHz~3.072MHz: set 0 + * When others set1 + */ +#define IT6621_TX_XP_DEI_SEL BIT(3) +#define IT6621_TX_XP_DEI_DIS (0x00 << 3) +#define IT6621_TX_XP_DEI_EN (0x01 << 3) +#define IT6621_TX_XP_ER0_SEL BIT(4) +#define IT6621_TX_XP_ER0_DIS (0x00 << 4) +#define IT6621_TX_XP_ER0_EN (0x01 << 4) +#define IT6621_TX_AUTO_XP_GAIN_SEL BIT(6) /* 1: XP_GAIN auto mode */ +#define IT6621_TX_AUTO_XP_GAIN_DIS (0x00 << 6) +#define IT6621_TX_AUTO_XP_GAIN_EN (0x01 << 6) +#define IT6621_TX_AUTO_XP_PDIV_SEL BIT(7) /* 1: XP_PDIV[1:0] auto mode */ +#define IT6621_TX_AUTO_XP_PDIV_DIS (0x00 << 7) +#define IT6621_TX_AUTO_XP_PDIV_EN (0x01 << 7) + +#define IT6621_REG_TX_AFE2 0xa2 +#define IT6621_TX_DRV_DPWD BIT(0) /* Power down the differential + * mode driver, high active. + * NOTE: Set 1 in ARC mode. + */ +#define IT6621_TX_DRV_RESET_SEL BIT(1) /* Reset the differential mode + * driver, high active. + * NOTE: Set 1 in ARC mode. + */ +#define IT6621_TX_DRV_RESET_DIS (0x00 << 1) +#define IT6621_TX_DRV_RESET_EN (0x01 << 1) +#define IT6621_TX_DRV_DC GENMASK(3, 2) +#define IT6621_TX_DRV_DC_DIS (0x00 << 2) +#define IT6621_TX_DRV_DC_EN (0x01 << 2) +#define IT6621_TX_DRV_DC_SEL_DIS (0x00 << 3) +#define IT6621_TX_DRV_DC_SEL_EN (0x01 << 3) +#define IT6621_TX_DRV_DSW_SEL GENMASK(6, 4) +#define IT6621_TX_DRV_DSW_4 (0x04 << 4) +#define IT6621_TX_DRV_DSW_7 (0x07 << 4) +#define IT6621_TX_DRV_OT_SEL BIT(7) +#define IT6621_TX_DRV_OT_DIS (0x00 << 7) +#define IT6621_TX_DRV_OT_EN (0x01 << 7) + +#define IT6621_REG_TX_AFE3 0xa3 +#define IT6621_TX_DRV_CPWD BIT(0) /* Power down the common mode driver, high active */ +#define IT6621_TX_DRV_CSR_SEL GENMASK(3, 1) /* 0: fastest, 7: slowest */ +#define IT6621_TX_DRV_CSR_2 (0x02 << 1) +#define IT6621_TX_DRV_CSR_4 (0x04 << 1) +#define IT6621_TX_DRV_CSW_SEL GENMASK(6, 4) /* 0: minimum, 7: maximum */ +#define IT6621_TX_DRV_CSW_4 (0x04 << 4) +#define IT6621_TX_DRV_CSW_7 (0x07 << 4) +#define IT6621_TX_IN_ARC_MODE_SEL BIT(7) /* In ARC mode */ +#define IT6621_TX_IN_ARC_SIGNAL_MODE (0x00 << 7) /* signal mode */ +#define IT6621_TX_IN_ARC_COMMON_MODE (0x01 << 7) /* common mode */ + +#define IT6621_REG_TX_AFE4 0xa4 +#define IT6621_TX_RC_PWD BIT(0) /* Power down common receiver, + * high active. + * NOTE: Set 1 in ARC mode. + */ +#define IT6621_TX_RC_CK_SEL BIT(1) +#define IT6621_TX_RC_CK_DIS (0x00 << 1) +#define IT6621_TX_RC_CK_EN (0x01 << 1) +#define IT6621_TX_VCM_SEL GENMASK(3, 2) +#define IT6621_TX_VCM0 (0x00 << 2) +#define IT6621_TX_VCM1 (0x01 << 2) +#define IT6621_TX_VCM2 (0x02 << 2) +#define IT6621_TX_VCM3 (0x03 << 2) +#define IT6621_TX_HYS_SEL GENMASK(6, 4) +#define IT6621_TX_HYS5 (0x05 << 4) +#define IT6621_TX_HYS6 (0x06 << 4) + +#define IT6621_REG_TX_AFE5 0xa5 +#define IT6621_TX_LC_PWD BIT(4) /* PWD=0, LCVCO is at power down */ +#define IT6621_TX_LC_ICTP_PWD BIT(5) /* ICTP_PWD=0, ICTP block is at power down */ +#define IT6621_TX_LC_RESET BIT(6) /* RESET=0, LCVCO is at reset */ + +#define IT6621_REG_TX_AFE15 0xaf +#define IT6621_TX_AUTO_DPWD_SEL BIT(0) /* 1: enable auto power down + * differential mode TX AFE + */ +#define IT6621_TX_AUTO_DPWD_DIS (0x00 << 0) +#define IT6621_TX_AUTO_DPWD_EN (0x01 << 0) +#define IT6621_TX_AUTO_DRST_SEL BIT(1) /* 1: enable auto reset differential mode TX AFE */ +#define IT6621_TX_AUTO_DRST_DIS (0x00 << 1) +#define IT6621_TX_AUTO_DRST_EN (0x01 << 1) +#define IT6621_TX_AUTO_CPWD_SEL BIT(2) /* 1: enable auto power down common mode TX AFE */ +#define IT6621_TX_AUTO_CPWD_DIS (0x00 << 2) +#define IT6621_TX_AUTO_CPWD_EN (0x01 << 2) + +/* eARC Clock Detection Registers */ +#define IT6621_REG_CLK_DET0 0xc0 +#define IT6621_ACLK_BND_NUM_LOW GENMASK(7, 0) /* ACLK frequency boundary + * for XP_PDIV auto setting. + * 128T@3.584MHz count by 10MHz RCLK. + */ + +#define IT6621_REG_CLK_DET1 0xc1 +#define IT6621_ACLK_BND_NUM_HIGH BIT(0) + +#define IT6621_REG_CLK_DET2 0xc2 +#define IT6621_ACLK_VALID_NUM_LOW GENMASK(7, 0) /* ACLK frequency valid for + * XP_PDIV auto setting. + * 128T@2MHz count by 10MHz RCLK. + */ + +#define IT6621_REG_CLK_DET3 0xc3 +#define IT6621_ACLK_VALID_NUM_HIGH GENMASK(1, 0) + +#define IT6621_REG_CLK_DET4 0xc4 +#define IT6621_BCLK_BND_NUM GENMASK(7, 0) /* BCLK frequency boundary + * for FSEL auto setting. + * 128T@6.25MHz count by 10MHz RCLK. + */ + +#define IT6621_REG_CLK_DET5 0xc5 +#define IT6621_BCLK_VALID_NUM_LOW GENMASK(7, 0) /* BCLK frequency valid for + * FSEL auto setting. + * 128T@4MHz count by 10MHz RCLK. + */ + +#define IT6621_REG_CLK_DET6 0xc6 +#define IT6621_BCLK_VALID_NUM_HIGH BIT(0) + +#define IT6621_REG_CLK_DET7 0xc7 +#define IT6621_ACLK_DET_EN_SEL BIT(0) /* enable ACLK clock detection */ +#define IT6621_ACLK_DET_DIS (0x00 << 0) +#define IT6621_ACLK_DET_EN (0x01 << 0) +#define IT6621_BCLK_DET_EN_SEL BIT(1) /* 1: enable BCLK clock detection */ +#define IT6621_UPDATE_AVG_EN_SEL BIT(4) /* enable update average clock detection value */ +#define IT6621_UPDATE_AVG_DIS (0x00 << 4) +#define IT6621_UPDATE_AVG_EN (0x01 << 4) +#define IT6621_CLK_DIFF_MIN_EN BIT(5) +#define IT6621_CLK_ORG_DELTA_EN (0x00 << 5) /* 0: Original delta */ +#define IT6621_CLK_FIX_MIN_DELTA_EN (0x01 << 5) /* 1: Fix minimum delta */ +#define IT6621_RCLK_DELTA_SEL GENMASK(7, 6) /* RCLK deviation selection */ +#define IT6621_RCLK_DELTA1 (0x00 << 6) /* +/-1% */ +#define IT6621_RCLK_DELTA2 (0x01 << 6) /* +/-2% */ +#define IT6621_RCLK_DELTA3 (0x02 << 6) /* +/-3% */ +#define IT6621_RCLK_DELTA5 (0x03 << 6) /* +/-5% */ + +#define IT6621_REG_CLK_DET8 0xc8 +#define IT6621_DET_ACLK_AVG_LOW GENMASK(7, 0) /* ACLK frequency detection */ + +#define IT6621_REG_CLK_DET9 0xc9 +#define IT6621_DET_ACLK_AVG_HIGH GENMASK(3, 0) +#define IT6621_DET_ACLK_PRE_DIV_2 BIT(4) /* 1: ACLK is pre-divided by 2 */ +#define IT6621_DET_ACLK_PRE_DIV_4 BIT(5) /* 1: ACLK is pre-divided by 4 */ +#define IT6621_DET_ACLK_FREQ_VALID BIT(6) /* 1: ACLK frequency is valid */ +#define IT6621_DET_ACLK_FREQ_STB BIT(7) /* 1: ACLK frequency detection */ + +#define IT6621_REG_CLK_DET10 0xca +#define IT6621_DET_BCLK_AVG_LOW GENMASK(7, 0) /* BCLK frequency detection */ + +#define IT6621_REG_CLK_DET11 0xcb +#define IT6621_DET_BCLK_AVG_HIGH GENMASK(2, 0) +#define IT6621_DET_BCLK_PRE_DIV_2 BIT(4) /* 1: BCLK is pre-divided by 2 */ +#define IT6621_DET_BCLK_PRE_DIV_4 BIT(5) /* 1: BCLK is pre-divided by 4 */ +#define IT6621_DET_BCLK_FREQ_VALID BIT(6) /* 1: BCLK frequency is valid */ +#define IT6621_DET_BCLK_FREQ_STB BIT(7) /* 1: BCLK frequency detection */ + +/* GPIO Control Registers */ +#define IT6621_REG_GPIO_CTRL0 0xe8 +#define IT6621_I2S0_GPIO_MODE_EN BIT(0) /* 1: enable I2S0 GPIO mode */ +#define IT6621_I2S0_GPIO_OUTPUT_EN BIT(1) /* 1: enable I2S0 output enable */ +#define IT6621_I2S0_GPIO_OUTPUT_VAL BIT(2) /* I2S0 GPIO output value */ +#define IT6621_I2S0_GPIO_INPUT_VAL BIT(3) /* I2S0 GPIO input value */ +#define IT6621_I2S1_GPIO_MODE_EN BIT(4) /* 1: enable I2S1 GPIO mode */ +#define IT6621_I2S1_GPIO_OUTPUT_EN BIT(5) /* 1: enable I2S1 output enable */ +#define IT6621_I2S1_GPIO_OUTPUT_VAL BIT(6) /* I2S1 GPIO output value */ +#define IT6621_I2S1_GPIO_INPUT_VAL BIT(7) /* I2S1 GPIO input value */ + +#define IT6621_REG_GPIO_CTRL1 0xe9 +#define IT6621_I2S2_GPIO_MODE_EN BIT(0) /* 1: enable I2S2 GPIO mode */ +#define IT6621_I2S2_GPIO_OUTPUT_EN BIT(1) /* 1: enable I2S2 output enable */ +#define IT6621_I2S2_GPIO_OUTPUT_VAL BIT(2) /* I2S2 GPIO output value */ +#define IT6621_I2S2_GPIO_INPUT_VAL BIT(3) /* I2S2 GPIO input value */ +#define IT6621_I2S3_GPIO_MODE_EN BIT(4) /* 1: enable I2S3 GPIO mode */ +#define IT6621_I2S3_GPIO_OUTPUT_EN BIT(5) /* 1: enable I2S3 output enable */ +#define IT6621_I2S3_GPIO_OUTPUT_VAL BIT(6) /* I2S3 GPIO output value */ +#define IT6621_I2S3_GPIO_INPUT_VAL BIT(7) /* I2S3 GPIO input value */ + +#define IT6621_REG_GPIO_CTRL2 0xea +#define IT6621_I2S4_GPIO_MODE_EN BIT(0) /* 1: enable I2S4 GPIO mode */ +#define IT6621_I2S4_GPIO_OUTPUT_EN BIT(1) /* 1: enable I2S4 output enable */ +#define IT6621_I2S4_GPIO_OUTPUT_VAL BIT(2) /* I2S4 GPIO output value */ +#define IT6621_I2S4_GPIO_INPUT_VAL BIT(3) /* I2S4 GPIO input value */ +#define IT6621_I2S5_GPIO_MODE_EN BIT(4) /* 1: enable I2S5 GPIO mode */ +#define IT6621_I2S5_GPIO_OUTPUT_EN BIT(5) /* 1: enable I2S5 output enable */ +#define IT6621_I2S5_GPIO_OUTPUT_VAL BIT(6) /* I2S5 GPIO output value */ +#define IT6621_I2S5_GPIO_INPUT_VAL BIT(7) /* I2S5 GPIO input value */ + +#define IT6621_REG_GPIO_CTRL3 0xeb +#define IT6621_I2S6_GPIO_MODE_EN BIT(0) /* 1: enable I2S6 GPIO mode */ +#define IT6621_I2S6_GPIO_OUTPUT_EN BIT(1) /* 1: enable I2S6 output enable */ +#define IT6621_I2S6_GPIO_OUTPUT_VAL BIT(2) /* I2S6 GPIO output value */ +#define IT6621_I2S6_GPIO_INPUT_VAL BIT(3) /* I2S6 GPIO input value */ +#define IT6621_I2S7_GPIO_MODE_EN BIT(4) /* 1: enable I2S7 GPIO mode */ +#define IT6621_I2S7_GPIO_OUTPUT_EN BIT(5) /* 1: enable I2S7 output enable */ +#define IT6621_I2S7_GPIO_OUTPUT_VAL BIT(6) /* I2S7 GPIO output value */ +#define IT6621_I2S7_GPIO_INPUT_VAL BIT(7) /* I2S7 GPIO input value */ + +#define IT6621_REG_GPIO_CTRL4 0xec +#define IT6621_MCLK_GPIO_MODE_EN BIT(0) /* 1: enable MCLK GPIO mode */ +#define IT6621_MCLK_GPIO_OUTPUT_EN BIT(1) /* 1: enable MCLK output enable */ +#define IT6621_MCLK_GPIO_OUTPUT_VAL BIT(2) /* MCLK GPIO output value */ +#define IT6621_MCLK_GPIO_INPUT_VAL BIT(3) /* MCLK GPIO input value */ +#define IT6621_SPDIF_GPIO_MODE_EN BIT(4) /* 1: enable SPDIF GPIO mode */ +#define IT6621_SPDIF_GPIO_OUTPUT_EN BIT(5) /* 1: enable SPDIF output enable */ +#define IT6621_SPDIF_GPIO_OUTPUT_VAL BIT(6) /* SPDIF GPIO output value */ +#define IT6621_SPDIF_GPIO_INPUT_VAL BIT(7) /* SPDIF GPIO input value */ + +#define IT6621_REG_GPIO_CTRL5 0xed +#define IT6621_MUTE_GPIO_MODE_EN BIT(0) /* 1: enable MUTE GPIO mode */ +#define IT6621_MUTE_GPIO_OUTPUT_EN BIT(1) /* 1: enable MUTE output enable */ +#define IT6621_MUTE_GPIO_OUTPUT_VAL BIT(2) /* MUTE GPIO output value */ +#define IT6621_MUTE_GPIO_INPUT_VAL BIT(3) /* MUTE GPIO input value */ +#define IT6621_HPDB_GPIO_MODE_EN BIT(4) /* 1: enable HPDB GPIO mode */ +#define IT6621_HPDB_GPIO_OUTPUT_EN BIT(5) /* 1: enable HPDB output enable */ +#define IT6621_HPDB_GPIO_OUTPUT_VAL BIT(6) /* HPDB GPIO output value */ +#define IT6621_HPDB_GPIO_INPUT_VAL BIT(7) /* HPDB GPIO input value */ + +/* Misc Registers */ +#define IT6621_REG_MISC0 0xf0 +#define IT6621_DEBUG_SEL GENMASK(2, 0) /* Select one of the 8 debug groups */ +#define IT6621_DEBUG_EN BIT(3) /* 1: enable debug output */ +#define IT6621_AUD_DEBUG_EN BIT(5) /* 1: Enable audio signal debug output */ + +#define IT6621_REG_MISC1 0xf1 +#define IT6621_HPD_DG_TIME_SEL GENMASK(1, 0) /* HPD de-glitch time selection */ +#define IT6621_HPD_DG_TIME_10US (0x00 << 0) /* 10us */ +#define IT6621_HPD_DG_TIME_100US (0x01 << 0) /* 100us */ +#define IT6621_HPD_DG_TIME_1MS (0x02 << 0) /* 1ms */ +#define IT6621_HPD_DG_TIME_10MS (0x03 << 0) /* 10ms */ +#define IT6621_CMD_HOLD_TIME GENMASK(7, 4) /* PCI2C hold time */ + +#define IT6621_REG_MISC2 0xf2 +#define IT6621_CMD_DRV GENMASK(1, 0) /* Driving setting for PCSCL and PCSDA */ +#define IT6621_HPD_DRV GENMASK(3, 2) /* Driving setting for HPD signals */ +#define IT6621_I2S_DRV GENMASK(5, 4) /* Driving setting for I2S signals */ +#define IT6621_SPDIF_DRV GENMASK(7, 6) /* Driving setting for SPDIF signals */ + +#define IT6621_REG_MISC3 0xf3 +#define IT6621_CMD_SMT BIT(0) /* PCSCL/PCSDA Schmitt trigger option */ +#define IT6621_SCK_SMT BIT(2) /* SCK/DCLK Schmitt trigger option */ +#define IT6621_MCLK_SMT BIT(3) /* MCLK Schmitt trigger option */ +#define IT6621_SPDIFSMT BIT(4) /* SPDIF Schmitt trigger option */ + +#define IT6621_REG_MISC12 0xfc +#define IT6621_CRCLK_SEL_EN BIT(0) +#define IT6621_PWD_CRCLK (0x00 << 0) /* power-down CRCLK and disable CEC function */ +#define IT6621_CRCLK_EN (0x01 << 0) /* enable CRCLK for CEC function */ +#define IT6621_CEC_SLAVE_ADDR GENMASK(7, 1) /* CEC slave address */ + +#define IT6621_REG_PASS_WORD 0xff /* 0xC3/0xA5 on, 0xFF off */ +#define IT6621_PASS_WORD_ON1 0xc3 +#define IT6621_PASS_WORD_ON2 0xa5 +#define IT6621_PASS_WORD_OFF 0xff + +#endif /* _IT6621_REG_BANK0_H */ diff --git a/sound/soc/codecs/it6621/it6621-reg-bank1.h b/sound/soc/codecs/it6621/it6621-reg-bank1.h new file mode 100644 index 000000000000..f75174ff0e36 --- /dev/null +++ b/sound/soc/codecs/it6621/it6621-reg-bank1.h @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Jason Zhang + */ + +#ifndef _IT6621_REG_BANK1_H +#define _IT6621_REG_BANK1_H + +/* Bank 1 */ + +/* General Registers */ +#define IT6621_REG_GEN0 0x110 +#define IT6621_100MS_CNT_SEL BIT(7) /* Enable 100ms calibration counter */ +#define IT6621_100MS_CNT_DIS (0x00 << 7) +#define IT6621_100MS_CNT_EN (0x01 << 7) + +#define IT6621_REG_100MS_CNT_7_0 0x111 /* 100ms counter value */ +#define IT6621_REG_100MS_CNT_15_8 0x112 +#define IT6621_REG_100MS_CNT_23_16 0x113 + +#define IT6621_REG_GEN4 0x114 +#define IT6621_1US_TIME_INT GENMASK(5, 0) /* 1us time base integer number. + * Note: default value is + * calculated by 10MHz RCLK. + */ + +#define IT6621_REG_1US_TIME_FLT 0x115 /* 1us time base floating number */ + +#define IT6621_REG_GEN6 0x116 +#define IT6621_TIMER_INT_NUM GENMASK(6, 0) /* User defined timer + * interrupt count number + */ +#define IT6621_TIMER_INT_UNIT BIT(7) +#define IT6621_TIMER_INT_UNIT_10MS (0x00 << 7) /* unit=10ms */ +#define IT6621_TIMER_INT_UNIT_100MS (0x01 << 7) /* unit=100ms */ + +#define IT6621_REG_GEN7 0x117 +#define IT6621_TIME_STAMP_EN_SEL GENMASK(6, 0) /* Time stamp for firmware */ +#define IT6621_TIME_STAMP_EN BIT(7) /* 1: Enable time stamp */ + +/* Input SPDIF Channel Status Registers */ +#define IT6621_REG_AI_TX_CH_ST_7_0 0x120 +#define IT6621_REG_AI_TX_CH_ST_15_8 0x121 +#define IT6621_REG_AI_TX_CH_ST_23_16 0x122 +#define IT6621_REG_AI_TX_CH_ST_31_24 0x123 +#define IT6621_REG_AI_TX_CH_ST_39_32 0x124 + +/* eARC TX Channel Status Registers */ +#define IT6621_REG_TX_CH_ST0 0x130 +#define IT6621_REG_TX_CH_ST1 0x131 +#define IT6621_REG_TX_CH_ST2 0x132 +#define IT6621_REG_TX_CH_ST3 0x133 +#define IT6621_REG_TX_CH_ST4 0x134 +#define IT6621_REG_TX_CH_ST5 0x135 +#define IT6621_REG_TX_CH_ST9 0x139 +#define IT6621_REG_TX_CH_ST10 0x13a +#define IT6621_REG_TX_CH_ST11 0x13b +#define IT6621_REG_TX_CH_ST12 0x13c +#define IT6621_REG_TX_CH_ST13 0x13d +#define IT6621_REG_TX_CH_ST14 0x13e +#define IT6621_REG_TX_CH_ST15 0x13f + +/* eARC TX U-bit Packet Registers */ + +/* Packet Type 1 */ +#define IT6621_REG_TX_PKT1_CRC 0x150 /* eARC TX packet CRC */ +#define IT6621_REG_TX_PKT1_CH 0x151 /* eARC TX packet CH */ +#define IT6621_REG_TX_PKT1_HB0 0x152 /* eARC TX packet HB0 */ +#define IT6621_REG_TX_PKT1_HB1 0x153 /* eARC TX packet HB1 */ +#define IT6621_REG_TX_PKT1_HB2 0x154 /* eARC TX packet HB2 */ +#define IT6621_REG_TX_PKT1_PB0 0x155 /* eARC TX packet PB0 */ +#define IT6621_REG_TX_PKT1_PB1 0x156 /* eARC TX packet PB1 */ +#define IT6621_REG_TX_PKT1_PB2 0x157 /* eARC TX packet PB2 */ +#define IT6621_REG_TX_PKT1_PB3 0x158 /* eARC TX packet PB3 */ +#define IT6621_REG_TX_PKT1_PB4 0x159 /* eARC TX packet PB4 */ +#define IT6621_REG_TX_PKT1_PB5 0x15a /* eARC TX packet PB5 */ +#define IT6621_REG_TX_PKT1_PB6 0x15b /* eARC TX packet PB6 */ +#define IT6621_REG_TX_PKT1_PB7 0x15c /* eARC TX packet PB7 */ +#define IT6621_REG_TX_PKT1_PB8 0x15d /* eARC TX packet PB8 */ +#define IT6621_REG_TX_PKT1_PB9 0x15e /* eARC TX packet PB9 */ +#define IT6621_REG_TX_PKT1_PB10 0x15f /* eARC TX packet PB10 */ +#define IT6621_REG_TX_PKT1_PB11 0x160 /* eARC TX packet PB11 */ +#define IT6621_REG_TX_PKT1_PB12 0x161 /* eARC TX packet PB12 */ +#define IT6621_REG_TX_PKT1_PB13 0x162 /* eARC TX packet PB13 */ +#define IT6621_REG_TX_PKT1_PB14 0x163 /* eARC TX packet PB14 */ +#define IT6621_REG_TX_PKT1_PB15 0x164 /* eARC TX packet PB15 */ +#define IT6621_REG_TX_PKT1_PB16 0x165 /* eARC TX packet PB16 */ +#define IT6621_REG_TX_PKT1_PB17 0x166 /* eARC TX packet PB17 */ +#define IT6621_REG_TX_PKT1_PB18 0x167 /* eARC TX packet PB18 */ +#define IT6621_REG_TX_PKT1_PB19 0x168 /* eARC TX packet PB19 */ +#define IT6621_REG_TX_PKT1_PB20 0x169 /* eARC TX packet PB20 */ +#define IT6621_REG_TX_PKT1_PB21 0x16a /* eARC TX packet PB21 */ +#define IT6621_REG_TX_PKT1_PB22 0x16b /* eARC TX packet PB22 */ +#define IT6621_REG_TX_PKT1_PB23 0x16c /* eARC TX packet PB23 */ +#define IT6621_REG_TX_PKT1_PB24 0x16d /* eARC TX packet PB24 */ +#define IT6621_REG_TX_PKT1_PB25 0x16e /* eARC TX packet PB25 */ +#define IT6621_REG_TX_PKT1_PB26 0x16f /* eARC TX packet PB26 */ +#define IT6621_REG_TX_PKT1_PB27 0x170 /* eARC TX packet PB27 */ + +/* Packet Type 2 */ +#define IT6621_REG_TX_PKT2_CRC 0x171 /* eARC TX packet CRC */ +#define IT6621_REG_TX_PKT2_CH 0x172 /* eARC TX packet CH */ +#define IT6621_REG_TX_PKT2_HB0 0x173 /* eARC TX packet HB0 */ +#define IT6621_REG_TX_PKT2_HB1 0x174 /* eARC TX packet HB1 */ +#define IT6621_REG_TX_PKT2_HB2 0x175 /* eARC TX packet HB2 */ +#define IT6621_REG_TX_PKT2_PB0 0x176 /* eARC TX packet PB0 */ +#define IT6621_REG_TX_PKT2_PB1 0x177 /* eARC TX packet PB1 */ +#define IT6621_REG_TX_PKT2_PB2 0x178 /* eARC TX packet PB2 */ +#define IT6621_REG_TX_PKT2_PB3 0x179 /* eARC TX packet PB3 */ +#define IT6621_REG_TX_PKT2_PB4 0x17a /* eARC TX packet PB4 */ +#define IT6621_REG_TX_PKT2_PB5 0x17b /* eARC TX packet PB5 */ +#define IT6621_REG_TX_PKT2_PB6 0x17c /* eARC TX packet PB6 */ +#define IT6621_REG_TX_PKT2_PB7 0x17d /* eARC TX packet PB7 */ +#define IT6621_REG_TX_PKT2_PB8 0x17e /* eARC TX packet PB8 */ +#define IT6621_REG_TX_PKT2_PB9 0x17f /* eARC TX packet PB9 */ +#define IT6621_REG_TX_PKT2_PB10 0x180 /* eARC TX packet PB10 */ +#define IT6621_REG_TX_PKT2_PB11 0x181 /* eARC TX packet PB11 */ +#define IT6621_REG_TX_PKT2_PB12 0x182 /* eARC TX packet PB12 */ +#define IT6621_REG_TX_PKT2_PB13 0x183 /* eARC TX packet PB13 */ +#define IT6621_REG_TX_PKT2_PB14 0x184 /* eARC TX packet PB14 */ +#define IT6621_REG_TX_PKT2_PB15 0x185 /* eARC TX packet PB15 */ + +/* Packet Type 3 */ +#define IT6621_REG_TX_PKT3_CRC 0x186 /* eARC TX packet CRC */ +#define IT6621_REG_TX_PKT3_CH 0x187 /* eARC TX packet CH */ +#define IT6621_REG_TX_PKT3_HB0 0x188 /* eARC TX packet HB0 */ +#define IT6621_REG_TX_PKT3_HB1 0x189 /* eARC TX packet HB1 */ +#define IT6621_REG_TX_PKT3_HB2 0x18a /* eARC TX packet HB2 */ +#define IT6621_REG_TX_PKT3_PB0 0x18b /* eARC TX packet PB0 */ +#define IT6621_REG_TX_PKT3_PB1 0x18c /* eARC TX packet PB1 */ +#define IT6621_REG_TX_PKT3_PB2 0x18d /* eARC TX packet PB2 */ +#define IT6621_REG_TX_PKT3_PB3 0x18e /* eARC TX packet PB3 */ +#define IT6621_REG_TX_PKT3_PB4 0x18f /* eARC TX packet PB4 */ +#define IT6621_REG_TX_PKT3_PB5 0x190 /* eARC TX packet PB5 */ +#define IT6621_REG_TX_PKT3_PB6 0x191 /* eARC TX packet PB6 */ +#define IT6621_REG_TX_PKT3_PB7 0x192 /* eARC TX packet PB7 */ +#define IT6621_REG_TX_PKT3_PB8 0x193 /* eARC TX packet PB8 */ +#define IT6621_REG_TX_PKT3_PB9 0x194 /* eARC TX packet PB9 */ +#define IT6621_REG_TX_PKT3_PB10 0x195 /* eARC TX packet PB10 */ +#define IT6621_REG_TX_PKT3_PB11 0x196 /* eARC TX packet PB11 */ +#define IT6621_REG_TX_PKT3_PB12 0x197 /* eARC TX packet PB12 */ +#define IT6621_REG_TX_PKT3_PB13 0x198 /* eARC TX packet PB13 */ +#define IT6621_REG_TX_PKT3_PB14 0x199 /* eARC TX packet PB14 */ +#define IT6621_REG_TX_PKT3_PB15 0x19a /* eARC TX packet PB15 */ + +#endif /* _IT6621_REG_BANK1_H */ diff --git a/sound/soc/codecs/it6621/it6621-reg-cec.h b/sound/soc/codecs/it6621/it6621-reg-cec.h new file mode 100644 index 000000000000..4ce8865bdc6b --- /dev/null +++ b/sound/soc/codecs/it6621/it6621-reg-cec.h @@ -0,0 +1,246 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Jason Zhang + */ + +#ifndef _IT6621_REG_CEC_H +#define _IT6621_REG_CEC_H + +/* CEC Control Registers */ +#define IT6621_REG_CEC_CTRL6 0x06 /* 0: Interrupt Enable, 1: Interrupt Mask */ +#define IT6621_TX_INT_MASK BIT(0) +#define IT6621_RX_INT_MASK BIT(1) +#define IT6621_RX_FAIL_INT_MASK BIT(2) +#define IT6621_TX_DONE_INT_MASK BIT(3) +#define IT6621_RX_DONE_INT_MASK BIT(4) +#define IT6621_TX_FAIL_INT_MASK BIT(5) +#define IT6621_CMD_OVERFLOW_INT_MASK BIT(6) +#define IT6621_DATA_OVERFLOW_INT_MASK BIT(7) + +#define IT6621_REG_CEC_CTRL7 0x07 +#define IT6621_DBG_CEC_SEL GENMASK(4, 2) +#define IT6621_CEC_INT_STS_SEL BIT(5) + +#define IT6621_REG_CEC_CTRL8 0x08 +#define IT6621_CEC_INT_SEL BIT(0) /* CEC interrupt enable, + * 1: Enable, 0: Disable + */ +#define IT6621_CEC_INT_DIS (0x00 << 0) +#define IT6621_CEC_INT_EN (0x01 << 0) +#define IT6621_CEC_RESET_SEL BIT(2) /* Reset CEC block, + * 1: Enable, 0: Disable + */ +#define IT6621_CEC_RESET_DIS (0x00 << 2) +#define IT6621_CEC_RESET_EN (0x01 << 2) +#define IT6621_CEC_SMT BIT(3) /* Schmitt trigger of CEC IO, + * 1: Enable, 0: Disable + */ +#define IT6621_CEC_FORCE BIT(4) /* Force CEC output regardless of normal function */ +#define IT6621_CEC_OE BIT(5) /* Force CEC output value */ +#define IT6621_DBG_CEC_CLR BIT(6) /* For debug only */ +#define IT6621_FIRE_FRAME BIT(7) /* 1: Fire CEC command out */ + +#define IT6621_REG_CEC_CTRL9 0x09 +#define IT6621_EN_100MS_CNT BIT(0) /* Used as a reference 100ms + * time interval for CEC calibration + */ +#define IT6621_NACK_SEL BIT(1) /* Acknowledge from follower to initiator */ +#define IT6621_ACK_EN (0x00 << 1) /* ACK */ +#define IT6621_NACK_EN (0x01 << 1) /* NACK */ +#define IT6621_PULSE_SEL BIT(2) /* Select illegal bit as error bit */ +#define IT6621_PULSE_DIS (0x00 << 2) /* Disable */ +#define IT6621_PULSE_EN (0x01 << 2) /* Enable */ +#define IT6621_ACK_TRIG_SEL BIT(3) /* Acknowledge for broadcast mode */ +#define IT6621_ACK_TRIG_NACK (0x00 << 3) /* NACK */ +#define IT6621_ACK_TRIG_ACK (0x01 << 3) /* ACK */ +#define IT6621_REFIRE_SEL BIT(4) /* Retry to fire CEC command */ +#define IT6621_REFIRE_DIS (0x00 << 4) /* Disable */ +#define IT6621_REFIRE_EN (0x01 << 4) /* Enable */ +#define IT6621_RX_SELF_SEL BIT(5) /* Initiator received CEC bus data */ +#define IT6621_RX_SELF_EN (0x00 << 5) /* Enable */ +#define IT6621_RX_SELF_DIS (0x01 << 5) /* Disable */ +#define IT6621_REGION_SEL BIT(6) /* Select region for error bit */ +#define IT6621_REGION_START_TO_IDLE (0x00 << 6) /* Region form state Start to IDLE */ +#define IT6621_REGION_WHOLE (0x01 << 6) /* Whole region */ +#define IT6621_DATA_BIT_SEL BIT(7) /* Select data bit */ +#define IT6621_DATA_BIT_NORMAL (0x00 << 7) /* Normal */ +#define IT6621_DATA_BIT_INC_0P1MS (0x01 << 7) /* Increase 0.1ms */ + +#define IT6621_REG_CEC_CTRL10 0x0a +#define IT6621_BUS_FREE_SEL GENMASK(1, 0) /* Select bus free bit time */ +#define IT6621_BUS_FREE_AUTO (0x00 << 0) /* Automatic */ +#define IT6621_BUS_FREE_3BIT_TIME (0x01 << 0) /* 3 bit time */ +#define IT6621_BUS_FREE_5BIT_TIME (0x02 << 0) /* 5 bit time */ +#define IT6621_BUS_FREE_7BIT_TIME (0x03 << 0) /* 7 bit time */ +#define IT6621_BIT_END_SEL GENMASK(3, 2) /* Select logic 0 and + * logic 1 output bit time + */ +#define IT6621_BIT_END_STD (0x00 << 2) /* Standard */ +#define IT6621_BIT_END_MAX0_MIN1 (0x01 << 2) /* Logic 0 maximum and logic 1 minimum */ +#define IT6621_BIT_END_MAX1_MIN0 (0x02 << 2) /* Logic 1 maximum and logic 0 minimum */ +#define IT6621_AR_BIT_SEL BIT(4) /* Select bit time for arbitration lose */ +#define IT6621_AR_BIT_5BIT_TIME (0x00 << 4) /* 5 bit time */ +#define IT6621_AR_BIT_3BIT_TIME (0x01 << 4) /* 3 bit time */ +#define IT6621_HW_RTY_SEL BIT(5) /* HW 5 times Retry of TX */ +#define IT6621_HW_RTY_EN (0x00 << 5) +#define IT6621_HW_RTY_DIS (0x01 << 5) +#define IT6621_CEC_RX_EN_SEL BIT(6) /* CEC RX function */ +#define IT6621_CEC_RX_DIS (0x00 << 6) +#define IT6621_CEC_RX_EN (0x01 << 6) + +#define IT6621_REG_DATA_MIN 0x0b /* Minimum data bit time */ +#define IT6621_REG_TIMER_UNIT 0x0c /* CEC timer unit, nominally + * 100us. This value should be + * decided from MS_Count. + */ + +#define IT6621_REG_CEC_CTRL13 0x0d +#define IT6621_CEC_IO_PU_SEL BIT(4) +#define IT6621_CEC_IO_NORMAL (0x00 << 4) /* Normal */ +#define IT6621_CEC_IO_PU (0x01 << 4) /* Pull-up */ +#define IT6621_CEC_IO_SR BIT(5) /* CEC IO slew rate control */ +#define IT6621_CEC_IO_DRV GENMASK(7, 6) +#define IT6621_CEC_IO_DRV_2P5MA (0x00 << 6) /* 2.5mA */ +#define IT6621_CEC_IO_DRV_5MA (0x01 << 6) /* 5mA */ +#define IT6621_CEC_IO_DRV_7P5MA (0x02 << 6) /* 7.5mA */ +#define IT6621_CEC_IO_DRV_10MA (0x03 << 6) /* 10mA */ + +/* CEC Initiator Registers */ +#define IT6621_REG_TX_HEADER 0x10 /* CEC initiator command header */ +#define IT6621_REG_TX_OPCODE 0x11 /* CEC initiator command Opcode */ +#define IT6621_REG_TX_OPERAND1 0x12 /* CEC initiator command Operand1 */ +#define IT6621_REG_TX_OPERAND2 0x13 /* CEC initiator command Operand2 */ +#define IT6621_REG_TX_OPERAND3 0x14 /* CEC initiator command Operand3 */ +#define IT6621_REG_TX_OPERAND4 0x15 /* CEC initiator command Operand4 */ +#define IT6621_REG_TX_OPERAND5 0x16 /* CEC initiator command Operand5 */ +#define IT6621_REG_TX_OPERAND6 0x17 /* CEC initiator command Operand6 */ +#define IT6621_REG_TX_OPERAND7 0x18 /* CEC initiator command Operand7 */ +#define IT6621_REG_TX_OPERAND8 0x19 /* CEC initiator command Operand8 */ +#define IT6621_REG_TX_OPERAND9 0x1a /* CEC initiator command Operand9 */ +#define IT6621_REG_TX_OPERAND10 0x1b /* CEC initiator command Operand10 */ +#define IT6621_REG_TX_OPERAND11 0x1c /* CEC initiator command Operand11 */ +#define IT6621_REG_TX_OPERAND12 0x1d /* CEC initiator command Operand12 */ +#define IT6621_REG_TX_OPERAND13 0x1e /* CEC initiator command Operand13 */ +#define IT6621_REG_TX_OPERAND14 0x1f /* CEC initiator command Operand14 */ +#define IT6621_REG_TX_OPERAND15 0x20 /* CEC initiator command Operand15 */ +#define IT6621_REG_TX_OPERAND16 0x21 /* CEC initiator command Operand16 */ + +#define IT6621_REG_CEC_INIT22 0x22 +#define IT6621_LOG_ADDR GENMASK(3, 0) /* CEC target logical address */ + +#define IT6621_REG_CEC_INIT23 0x23 +#define IT6621_OUT_NUM GENMASK(4, 0) /* CEC output byte size in a frame */ + +/* CEC Follower Registers */ +#define IT6621_REG_RX_HEADER 0x30 /* CEC Follower command header */ +#define IT6621_REG_RX_OPCODE 0x31 /* CEC Follower command Opcode */ +#define IT6621_REG_RX_OPERAND1 0x32 /* CEC Follower command Operand1 */ +#define IT6621_REG_RX_OPERAND2 0x33 /* CEC Follower command Operand2 */ +#define IT6621_REG_RX_OPERAND3 0x34 /* CEC Follower command Operand3 */ +#define IT6621_REG_RX_OPERAND4 0x35 /* CEC Follower command Operand4 */ +#define IT6621_REG_RX_OPERAND5 0x36 /* CEC Follower command Operand5 */ +#define IT6621_REG_RX_OPERAND6 0x37 /* CEC Follower command Operand6 */ +#define IT6621_REG_RX_OPERAND7 0x38 /* CEC Follower command Operand7 */ +#define IT6621_REG_RX_OPERAND8 0x39 /* CEC Follower command Operand8 */ +#define IT6621_REG_RX_OPERAND9 0x3a /* CEC Follower command Operand9 */ +#define IT6621_REG_RX_OPERAND10 0x3b /* CEC Follower command Operand10 */ +#define IT6621_REG_RX_OPERAND11 0x3c /* CEC Follower command Operand11 */ +#define IT6621_REG_RX_OPERAND12 0x3d /* CEC Follower command Operand12 */ +#define IT6621_REG_RX_OPERAND13 0x3e /* CEC Follower command Operand13 */ +#define IT6621_REG_RX_OPERAND14 0x3f /* CEC Follower command Operand14 */ +#define IT6621_REG_RX_OPERAND15 0x40 /* CEC Follower command Operand15 */ +#define IT6621_REG_RX_OPERAND16 0x41 /* CEC Follower command Operand16 */ + +#define IT6621_REG_CEC_FOL22 0x42 +#define IT6621_IN_CNT GENMASK(4, 0) /* CEC follower received bytes */ + +/* CEC Misc. Registers */ +#define IT6621_REG_CEC_MSIC0 0x43 +#define IT6621_OUT_CNT GENMASK(4, 0) /* CEC initiator output bytes */ + +#define IT6621_REG_CEC_MSIC1 0x44 +#define IT6621_BUS_STATUS BIT(1) +#define IT6621_BUS_STATUS_BUSY (0x00 << 1) /* Busy */ +#define IT6621_BUS_STATUS_FREE (0x01 << 1) /* Busy */ +#define IT6621_OUT_STATUS GENMASK(3, 2) /* Output status */ +#define IT6621_OUT_STATUS_RCV_ACK (0x00 << 2) /* Received ACK */ +#define IT6621_OUT_STATUS_RCV_NACK (0x01 << 2) /* Received NACK */ +#define IT6621_OUT_STATUS_RTY (0x02 << 2) /* Retry, if no ACK, NACK + * or arbitration lose + */ +#define IT6621_OUT_STATUS_FAIL (0x03 << 2) /* Fail */ +#define IT6621_ERR_STATUS GENMASK(5, 4) /* Output status */ +#define IT6621_ERR_STATUS_NO_ERR (0x00 << 4) /* No error occurs */ +#define IT6621_ERR_STATUS_MDBP (0x01 << 4) /* Received data period < minimum + * data bit period + */ +#define IT6621_ERR_STATUS_IHLP (0x02 << 4) /* Illegal high-low period */ +#define IT6621_ERR_STATUS_BOTH (0x03 << 4) /* Both */ +#define IT6621_READY_FIRE BIT(6) /* Bus ready for firing a CEC command */ + +#define IT6621_REG_CEC_MS_COUNT_7_0 0x45 +#define IT6621_REG_CEC_MS_COUNT_15_8 0x46 +#define IT6621_REG_CEC_MS_COUNT_19_16 0x47 + +#define IT6621_REG_CEC_MSIC5 0x48 +#define IT6621_DBG_STATE GENMASK(3, 0) /* Debug CEC error state */ +#define IT6621_DBG_INT BIT(4) /* CEC interrupt for debug */ +#define IT6621_CEC_INT BIT(5) /* CEC interrupt status */ + +#define IT6621_REG_CEC_MSIC6 0x49 +#define IT6621_DBG_BLOCK GENMASK(4, 0) /* Debug CEC error block number */ + +#define IT6621_REG_CEC_MSIC7 0x4a +#define IT6621_DBG_BIT GENMASK(3, 0) /* Debug CEC error bit number */ + +#define IT6621_REG_DBG_TIMING 0x4b /* Debug CEC error data bit time */ + +#define IT6621_REG_CEC_MSIC8 0x4c +#define IT6621_TX_INT BIT(0) /* CEC initiator output byte interrupt */ +#define IT6621_RX_INT BIT(1) /* CEC follower received byte interrupt */ +#define IT6621_RX_FAIL_INT BIT(2) /* CEC received fail interrupt */ +#define IT6621_TX_DONE_INT BIT(3) /* CEC output finish interrupt */ +#define IT6621_RX_DONE_INT BIT(4) /* CEC received finish interrupt */ +#define IT6621_TX_FAIL_INT BIT(5) /* CEC initiator output fail interrupt */ +#define IT6621_CMD_OVERFLOW_INT BIT(6) /* CEC command FIFO over flow interrupt */ +#define IT6621_DATA_OVERFLOW_INT BIT(7) /* CEC data FIFO over flow interrupt */ + +#define IT6621_REG_RX_CMD_RX_HEADER 0x4d /* Command FIFO Rx_Header */ +#define IT6621_REG_RX_CMD_RX_OPCODE 0x4e /* Command FIFO Rx_Opcode */ + +#define IT6621_REG_RX_CMD_BYTE2 0x4f +#define IT6621_RX_CMD_IN_CNT GENMASK(4, 0) /* Command FIFO In_Cnt */ +#define IT6621_RX_CMD_ERR_STATUS GENMASK(6, 5) /* Command FIFO Error_Status */ +#define IT6621_RX_CMD_CEC_RX_FAIL BIT(7) /* Command FIFO CEC Rx_Fail */ + +#define IT6621_REG_RX_DATA 0x50 /* Data FIFO Rx_Operand */ + +#define IT6621_REG_CEC_MSIC12 0x51 +#define IT6621_RX_CMD_VALID BIT(0) /* Read command FIFO valid */ +#define IT6621_RX_CMD_FULL BIT(1) /* Command FIFO full */ +#define IT6621_RX_CMD_WRITE_OVERFLOW BIT(2) /* Write command FIFO over flow */ +#define IT6621_RX_CMD_READ_OVERFLOW BIT(3) /* Read command FIFO over flow */ +#define IT6621_RX_DATA_VALID BIT(4) /* Read data FIFO valid */ +#define IT6621_RX_DATA_FULL BIT(5) /* Data FIFO full */ +#define IT6621_RX_DATA_WRITE_OVERFLOW BIT(6) /* Write data FIFO over flow */ +#define IT6621_RX_DATA_READ_OVERFLOW BIT(7) /* Read data FIFO over flow */ + +#define IT6621_REG_CEC_MSIC13 0x52 +#define IT6621_RX_CMD_STG GENMASK(3, 0) /* Rx command FIFO stage */ +#define IT6621_RX_CMD_FIFO_RST BIT(5) /* CEC command FIFO reset 1:Reset */ +#define IT6621_RX_DATA_FIFO_RST BIT(6) /* CEC data FIFO reset 1:Reset */ +#define IT6621_RX_CEC_FIFO_EN_SEL BIT(7) /* CEC FIFO enable */ +#define IT6621_RX_CEC_FIFO_DIS (0x00 << 7) /* Disable */ +#define IT6621_RX_CEC_FIFO_EN (0x01 << 7) /* Enable */ + +#define IT6621_REG_CEC_MSIC14 0x53 +#define IT6621_RX_DATA_STG GENMASK(3, 0) /* Rx data FIFO stage */ + +#define IT6621_REG_CEC_MSIC15 0x54 +#define IT6621_TX_FAIL_STATUS GENMASK(2, 0) +#define IT6621_TX_FAIL_STATUS_RCV_ACK BIT(0) /* receive ACK */ +#define IT6621_TX_FAIL_STATUS_RCV_NACK BIT(1) /* receive NACK */ +#define IT6621_TX_FAIL_STATUS_RTY BIT(2) /* retry */ + +#endif /* _IT6621_REG_CEC_H */ diff --git a/sound/soc/codecs/it6621/it6621-uapi.c b/sound/soc/codecs/it6621/it6621-uapi.c new file mode 100644 index 000000000000..27ef368f50e8 --- /dev/null +++ b/sound/soc/codecs/it6621/it6621-uapi.c @@ -0,0 +1,364 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Jason Zhang + */ + +#include +#include +#include + +#include "it6621.h" +#include "it6621-earc.h" +#include "it6621-uapi.h" + +#define IT6621_MAX_MSGS 18 +#define IT6621_MAX_MSG_LEN 256 + +struct it6621_msg { + u8 event; + u8 data[IT6621_MAX_MSG_LEN]; +} __packed; + +/* Command */ +#define IT6621_EARC_SET_ENABLED _IOW('a', 0x01, unsigned int) +#define IT6621_EARC_GET_STATE _IOR('a', 0x02, unsigned int) +#define IT6621_EARC_GET_AUDIO_CAP _IOR('a', 0x03, u8[IT6621_MAX_MSG_LEN]) +#define IT6621_EARC_GET_EVENT _IOR('a', 0x04, struct it6621_msg) +#define IT6621_EARC_SET_ENTER_ARC _IOW('a', 0x05, unsigned int) + +struct it6621_msg_entry { + struct list_head list; + struct it6621_msg msg; +}; + +struct it6621_fh { + struct list_head list; + struct list_head msgs; + unsigned int msgs_num; + struct mutex msgs_lock; + wait_queue_head_t wait; + struct it6621_priv *priv; + struct mutex valid_lock; + bool valid; +}; + +static int minor; + +static bool it6621_fh_get_valid(struct it6621_fh *fh) +{ + bool valid; + + mutex_lock(&fh->valid_lock); + valid = fh->valid; + mutex_unlock(&fh->valid_lock); + + return valid; +} + +static void it6621_fh_set_valid(struct it6621_fh *fh, bool valid) +{ + mutex_lock(&fh->valid_lock); + fh->valid = valid; + mutex_unlock(&fh->valid_lock); +} + +static int it6621_fh_set_earc_enabled(struct it6621_fh *fh, + unsigned int __user *argp) +{ + struct it6621_priv *priv = fh->priv; + unsigned int enabled; + int ret; + + ret = copy_from_user(&enabled, argp, sizeof(enabled)); + if (ret) + return -EFAULT; + + return it6621_set_earc_enabled(priv, !!enabled); +} + +static int it6621_fh_get_earc_state(struct it6621_fh *fh, + unsigned int __user *argp) +{ + struct it6621_priv *priv = fh->priv; + int ret; + + ret = copy_to_user(argp, &priv->state, sizeof(priv->state)); + if (ret) + return -EFAULT; + + return 0; +} + +static int it6621_fh_get_earc_audio_cap(struct it6621_fh *fh, u8 __user *argp) +{ + struct it6621_priv *priv = fh->priv; + int ret; + + mutex_lock(&priv->rxcap_lock); + ret = copy_to_user(argp, priv->rxcap, sizeof(priv->rxcap)); + mutex_unlock(&priv->rxcap_lock); + + if (ret) + return -EFAULT; + + return 0; +} + +static int it6621_fh_get_msg(struct it6621_fh *fh, + struct it6621_msg __user *argp, + bool block) +{ + struct it6621_msg_entry *entry; + int ret = 0; + + do { + mutex_lock(&fh->msgs_lock); + + if (fh->msgs_num) { + entry = list_first_entry(&fh->msgs, + struct it6621_msg_entry, + list); + list_del(&entry->list); + ret = copy_to_user(argp, &entry->msg, sizeof(entry->msg)); + kfree(entry); + fh->msgs_num--; + mutex_unlock(&fh->msgs_lock); + + if (ret) + return -EFAULT; + + return 0; + } + + mutex_unlock(&fh->msgs_lock); + + if (!block) + return -EAGAIN; + + ret = wait_event_interruptible(fh->wait, fh->msgs_num); + + if (!it6621_fh_get_valid(fh)) + return -ENXIO; + /* Exit on error, otherwise loop to get the new message */ + } while (!ret); + + return ret; +} + +static int it6621_fh_push_msg(struct it6621_fh *fh, u8 event, void *data, + size_t len) +{ + struct it6621_msg_entry *entry; + + mutex_lock(&fh->msgs_lock); + + if (fh->msgs_num <= IT6621_MAX_MSGS) { + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) { + mutex_unlock(&fh->msgs_lock); + return -ENOMEM; + } + + entry->msg.event = event; + memcpy(entry->msg.data, data, len); + list_add_tail(&entry->list, &fh->msgs); + fh->msgs_num++; + } else { + dev_warn(fh->priv->dev, "queue is full for fh: %p", fh); + } + + mutex_unlock(&fh->msgs_lock); + + wake_up_interruptible(&fh->wait); + + return 0; +} + +static int it6621_fh_set_enter_arc(struct it6621_fh *fh, + unsigned int __user *argp) +{ + struct it6621_priv *priv = fh->priv; + int enabled; + int ret; + + ret = copy_from_user(&enabled, argp, sizeof(enabled)); + if (ret) + return -EFAULT; + + return it6621_set_enter_arc(priv, !!enabled); +} + +static int it6621_uapi_open(struct inode *inode, struct file *file) +{ + struct miscdevice *mdev = file->private_data; + struct it6621_priv *priv = container_of(mdev, struct it6621_priv, mdev); + struct it6621_fh *fh; + + if (!priv->uapi_registered) + return -ENXIO; + + fh = kzalloc(sizeof(*fh), GFP_KERNEL); + if (!fh) + return -ENOMEM; + + fh->priv = priv; + fh->valid = true; + fh->msgs_num = 0; + INIT_LIST_HEAD(&fh->msgs); + mutex_init(&fh->msgs_lock); + mutex_init(&fh->valid_lock); + init_waitqueue_head(&fh->wait); + + mutex_lock(&priv->fhs_lock); + list_add(&fh->list, &priv->fhs); + mutex_unlock(&priv->fhs_lock); + + file->private_data = fh; + + return 0; +} + +static long it6621_uapi_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct it6621_fh *fh = file->private_data; + bool block = !(file->f_flags & O_NONBLOCK); + void __user *argp = (void __user *)arg; + + if (!it6621_fh_get_valid(fh)) + return -ENODEV; + + switch (cmd) { + case IT6621_EARC_SET_ENABLED: + return it6621_fh_set_earc_enabled(fh, argp); + case IT6621_EARC_GET_STATE: + return it6621_fh_get_earc_state(fh, argp); + case IT6621_EARC_GET_AUDIO_CAP: + return it6621_fh_get_earc_audio_cap(fh, argp); + case IT6621_EARC_GET_EVENT: + return it6621_fh_get_msg(fh, argp, block); + case IT6621_EARC_SET_ENTER_ARC: + return it6621_fh_set_enter_arc(fh, argp); + default: + return -ENOTTY; + } +} + +static int it6621_uapi_release(struct inode *inode, struct file *file) +{ + struct it6621_fh *fh = file->private_data; + struct it6621_priv *priv = fh->priv; + struct it6621_msg_entry *entry; + + if (it6621_fh_get_valid(fh)) { + mutex_lock(&priv->fhs_lock); + list_del(&fh->list); + mutex_unlock(&priv->fhs_lock); + } + + mutex_lock(&fh->msgs_lock); + + while (!list_empty(&fh->msgs)) { + entry = list_first_entry(&fh->msgs, struct it6621_msg_entry, + list); + list_del(&entry->list); + kfree(entry); + } + + mutex_unlock(&fh->msgs_lock); + + kfree(fh); + file->private_data = NULL; + + return 0; +} + +static __poll_t it6621_uapi_poll(struct file *file, + struct poll_table_struct *poll) +{ + struct it6621_fh *fh = file->private_data; + __poll_t ret = 0; + + poll_wait(file, &fh->wait, poll); + if (!it6621_fh_get_valid(fh)) + ret = EPOLLERR | EPOLLHUP; + else + ret = EPOLLIN | EPOLLRDNORM; + + return ret; +} + +const struct file_operations it6621_uapi_fops = { + .owner = THIS_MODULE, + .open = it6621_uapi_open, + .unlocked_ioctl = it6621_uapi_ioctl, + .compat_ioctl = it6621_uapi_ioctl, + .release = it6621_uapi_release, + .poll = it6621_uapi_poll, + .llseek = no_llseek, +}; + +int it6621_uapi_init(struct it6621_priv *priv) +{ + char *name; + int ret; + + name = kzalloc(NAME_MAX, GFP_KERNEL); + if (!name) + return -ENOMEM; + + snprintf(name, NAME_MAX, "ite-earc%d", minor++); + priv->mdev.minor = MISC_DYNAMIC_MINOR; + priv->mdev.name = name; + priv->mdev.fops = &it6621_uapi_fops; + + ret = misc_register(&priv->mdev); + if (ret) + return ret; + + priv->uapi_registered = true; + + return 0; +} + +void it6621_uapi_remove(struct it6621_priv *priv) +{ + struct it6621_fh *fh; + + mutex_lock(&priv->fhs_lock); + + priv->uapi_registered = false; + + list_for_each_entry(fh, &priv->fhs, list) + it6621_fh_set_valid(fh, false); + + list_for_each_entry(fh, &priv->fhs, list) + wake_up_interruptible(&fh->wait); + + mutex_unlock(&priv->fhs_lock); + + misc_deregister(&priv->mdev); + kfree(priv->mdev.name); +} + +int it6621_uapi_msg(struct it6621_priv *priv, u8 event, void *data, size_t len) +{ + struct it6621_fh *fh; + int ret = 0; + + if (!priv->uapi_registered) + return 0; + + mutex_lock(&priv->fhs_lock); + + list_for_each_entry(fh, &priv->fhs, list) { + ret = it6621_fh_push_msg(fh, event, data, len); + if (ret) + break; + } + + mutex_unlock(&priv->fhs_lock); + + return ret; +} diff --git a/sound/soc/codecs/it6621/it6621-uapi.h b/sound/soc/codecs/it6621/it6621-uapi.h new file mode 100644 index 000000000000..daf6f67eff3d --- /dev/null +++ b/sound/soc/codecs/it6621/it6621-uapi.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Jason Zhang + */ + +#ifndef _IT6621_UAPI_H +#define _IT6621_UAPI_H + +/* States */ +#define IT6621_EARC_IDLE 0x01 +#define IT6621_EARC_PENDING 0x02 +#define IT6621_ARC_PENDING 0x03 +#define IT6621_EARC_CONNECTED 0x04 + +/* Events */ +#define IT6621_EVENT_STATE_CHANGE 0x01 /* Event of state change, with a + * state following up. + */ + +#define IT6621_EVENT_AUDIO_CAP_CHANGE 0x02 /* Event of capabilities change, + * with a audio capabilities + * following up. + */ + +int it6621_uapi_init(struct it6621_priv *priv); +void it6621_uapi_remove(struct it6621_priv *priv); +int it6621_uapi_msg(struct it6621_priv *priv, u8 event, void *data, size_t len); + +#endif /* _IT6621_UAPI_H */ diff --git a/sound/soc/codecs/it6621/it6621.h b/sound/soc/codecs/it6621/it6621.h new file mode 100644 index 000000000000..bb902ebeabc4 --- /dev/null +++ b/sound/soc/codecs/it6621/it6621.h @@ -0,0 +1,210 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Jason Zhang + */ + +#ifndef _IT6621_H +#define _IT6621_H + +#include +#include +#include +#include +#include +#include +#include + +#define IT6621_VENDOR_ID 0x4954 +#define IT6621_DEVICE_ID 0x6621 +#define IT6621_REVISION_VARIANT_B0 0xb0 +#define IT6621_REVISION_VARIANT_C0 0xc0 +#define IT6621_REVISION_VARIANT_D0 0xd0 + +#define IT6621_ARC_START 0 +#define IT6621_EARC_CAP_CHG 1 +#define IT6621_EARC_EDID_OK 2 +#define IT6621_EARC_BCLK_OK 3 + +#define IT6621_AUDIO_START 0 +#define IT6621_AUDIO_TO_EN_DMAC 7 + +#define IT6621_CMD_WAIT_TIME_MS 1 +#define IT6621_CMD_WAIT_COUNT 10 +#define IT6621_RXCAP_BULK_LEN 16 +#define IT6621_RX_CAP_MAX_LEN 256 +#define IT6621_ADB_MAX_LEN 32 + +/** + * struct it6621_priv - IT6621 device + * @client: the i2c client used by the driver. + * @dev: i2c device. + * @mclk: master clock. + * @hpdio: Input Hot Plus Detection. + * @hpdio_lock: hpdio lock to protect hpdio access. + * @rxcap_lock: rxcap lock to protect rxcap access. + * @state: the state of IT6621 device. + * @vid: vendor ID. + * @devid: device ID. + * @revid: revision ID. + * @audio_enc: LPCM 2-ch do not support encryption. + * @audio_src: I2S, SPDIF, TDM, DSD (DSD: EnAudGen must be TRUE for + * Internal AudGen). + * @audio_ch: channel number. + * @audio_fs: sample frequency. + * @audio_type: LPCM, NLPCM. + * @audio_hbr: HBR. + * @audio_input_hbr: input audio HBR. + * @i2s_wl: 0 for 16-bit, 1 for 18-bit, 2 for 20-bit, 3 for 24-bit. + * @i2s_hbr: I2S HBR. + * @i2s_fmt: I2S format. + * @i2s_nlpcm_enabled: auto by input setting. + * @i2s_hbr_enabled: enable eARC TX I2S hbr. + * @hbr_layb_enabled: QD980 HFR5-1-40. + * @mch_lpcm_enabled: SL-870 5-1-30 [Multi-channel 2-ch layout] has audio output + * @layout_2ch_enabled: use for SL-870 5-1-29 [Multi-channel 2-ch layout] => + * fixed by SL-870 @ FW Ver1.11 => (always FALSE) + * @vcm_sel: tx VCM selection. + * @force_ca: force channel allocation. + * @force_16ch: force to 16 channels. + * @toggle_by_edid: indicate whether HPD is toggled by EDID. + * @rclk: RCLK frequency. + * @aclk: ACLK frequency. + * @bclk: BCLK frequency. + * @rclk_sel: RCLK frequency selection. + * @update_avg_enabled: enable update average clock detection value. + * @cmo_opt: eARC TX common mode output enable option. + * @force_cmo_enabled: force eARC TX common mode enable. + * @resync_opt: eARC TX common mode resync option. + * @ubit_opt: U-bit option. + * @c_ch_opt: eARC TX U-bit C-Ch option. + * @ecc_opt: eARC TX ECC option. + * @enc_seed: eARC TX encryption seed. + * @enc_opt: eARC TX encryption option. + * @fixed_lcf: fixed LC frequency. + * @bclk_inv_enabled: enable eARC BCLK inversion. + * @sck_inv_enabled: enable I2S serial clock inversion. + * @tck_inv_enabled: enable TDM clock inversion. + * @mclk_inv_enabled: enable SPDIF master clock inversion. + * @dclk_inv_enabled: enable DSD clock inversion. + * @nxt_pkt_to_sel: eARC TX next packet timeout selection. + * @turn_over_sel: eARC TX turn-over time selection before + * transmitting packet, set 24 us for QD980 HFR5-1-21. + * @hb_retry_sel: eARC TX HeartBeat retry time selection. + * @hb_retry_enabled: enable eARC TX auto HeartBeat retry. + * @cmd_to_enabled: indicate whether command timeout is enabled. + * @force_arc: force TX ARC mode. + * @enter_arc_now: enter ARC mode when initiate IT6621 device, + * enable for standalone ARC mode. + * @arc_enabled: enable ARC mode. + * @earc_enabled: enable eARC mode, disable for standalone ARC mode. + * @pkt1_enabled: enable eARC TX packet 1 using U-bit. + * @pkt2_enabled: enable eARC TX packet 2 using U-bit. + * @pkt3_enabled: enable eARC TX packet 3 using U-bit. + * @events: eARC events. + * @audio_flag: upstream's audio state, if upstream is audio on, set to 1 at + * upstream, extern to upstream's function. + * @hpdio_work: work to toggle hpdio. + * @config_audio: indicate whether audio is need to be configured. + * @force_mute: force mute. + * @uapi_registered: indicate whether uapi is registered. + * @rxcap: capabilities from the ARC device. + * @adb: audio data block. + */ +struct it6621_priv { + struct i2c_client *client; + struct device *dev; + struct regmap *regmap; + struct miscdevice mdev; + struct clk *mclk; + struct gpio_desc *hpdio; + struct list_head fhs; + struct mutex fhs_lock; + struct mutex hpdio_lock; + struct mutex rxcap_lock; + unsigned int state; + unsigned int vid; + unsigned int devid; + unsigned int revid; + + /* Tx Audio Option */ + unsigned int audio_enc; + unsigned int audio_src; + unsigned int audio_ch; + unsigned int audio_fs; + unsigned int audio_type; + unsigned int audio_hbr; + unsigned int audio_input_hbr; + unsigned int i2s_wl; + unsigned int i2s_hbr; + unsigned int i2s_fmt; + unsigned int i2s_nlpcm_enabled; + unsigned int i2s_hbr_enabled; + unsigned int hbr_layb_enabled; + unsigned int mch_lpcm_enabled; + unsigned int layout_2ch_enabled; + unsigned int vcm_sel; + unsigned int force_ca; + unsigned int force_16ch; + + /* FIXME: Need to toggle by edid? */ + unsigned int toggle_by_edid; + unsigned int rclk; + unsigned int aclk; + unsigned int bclk; + + /* Clock configurations */ + unsigned int rclk_sel; + unsigned int update_avg_enabled; + + unsigned int cmo_opt; + unsigned int force_cmo_enabled; + unsigned int resync_opt; + unsigned int ubit_opt; + unsigned int c_ch_opt; + unsigned int ecc_opt; + unsigned int enc_seed; + unsigned int enc_opt; + unsigned int fixed_lcf; + + /* Clock inversion option */ + unsigned int bclk_inv_enabled; + unsigned int sck_inv_enabled; + unsigned int tck_inv_enabled; + unsigned int mclk_inv_enabled; + unsigned int dclk_inv_enabled; + + /* DMCD option */ + unsigned int nxt_pkt_to_sel; + unsigned int turn_over_sel; + + /* TX CMDC option */ + unsigned int hb_retry_sel; + unsigned int hb_retry_enabled; + unsigned int cmd_to_enabled; + + /* Discovery option */ + unsigned int force_arc; + unsigned int force_earc; + unsigned int enter_arc_now; + unsigned int arc_enabled; + unsigned int earc_enabled; + + /* Loop Test option */ + unsigned int pkt1_enabled; + unsigned int pkt2_enabled; + unsigned int pkt3_enabled; + + unsigned long events; + unsigned long audio_flag; + + struct work_struct hpdio_work; + struct class class; + bool config_audio; + bool force_mute; + bool uapi_registered; + u8 rxcap[IT6621_RX_CAP_MAX_LEN]; + u8 adb[IT6621_ADB_MAX_LEN]; +}; + +#endif /* _IT6621_H */ From 1feee0d9c0b20750eef52b06b9211a4a3a353895 Mon Sep 17 00:00:00 2001 From: "shunhua.lan" Date: Wed, 31 Jan 2024 21:25:45 +0800 Subject: [PATCH 3/3] ASoC: codecs: add aw882xx amp Change-Id: Ia1249aa8971f6e7dee58858343ea56454862601c Signed-off-by: Shunhua Lan --- sound/soc/codecs/Kconfig | 1 + sound/soc/codecs/Makefile | 1 + sound/soc/codecs/aw882xx/Kconfig | 5 + sound/soc/codecs/aw882xx/Makefile | 5 + sound/soc/codecs/aw882xx/aw882xx.c | 2755 +++++++++++++++++ sound/soc/codecs/aw882xx/aw882xx.h | 223 ++ sound/soc/codecs/aw882xx/aw882xx_bin_parse.c | 1421 +++++++++ sound/soc/codecs/aw882xx/aw882xx_bin_parse.h | 102 + sound/soc/codecs/aw882xx/aw882xx_calib.c | 2453 +++++++++++++++ sound/soc/codecs/aw882xx/aw882xx_calib.h | 193 ++ sound/soc/codecs/aw882xx/aw882xx_data_type.h | 165 + sound/soc/codecs/aw882xx/aw882xx_device.c | 1593 ++++++++++ sound/soc/codecs/aw882xx/aw882xx_device.h | 463 +++ sound/soc/codecs/aw882xx/aw882xx_dsp.c | 1309 ++++++++ sound/soc/codecs/aw882xx/aw882xx_dsp.h | 109 + sound/soc/codecs/aw882xx/aw882xx_init.c | 2277 ++++++++++++++ sound/soc/codecs/aw882xx/aw882xx_log.h | 35 + sound/soc/codecs/aw882xx/aw882xx_monitor.c | 1431 +++++++++ sound/soc/codecs/aw882xx/aw882xx_monitor.h | 234 ++ .../soc/codecs/aw882xx/aw882xx_pid_1852_reg.h | 1927 ++++++++++++ .../soc/codecs/aw882xx/aw882xx_pid_2013_reg.h | 2158 +++++++++++++ .../soc/codecs/aw882xx/aw882xx_pid_2032_reg.h | 2008 ++++++++++++ .../soc/codecs/aw882xx/aw882xx_pid_2055_reg.h | 2034 ++++++++++++ .../codecs/aw882xx/aw882xx_pid_2055a_reg.h | 2062 ++++++++++++ .../soc/codecs/aw882xx/aw882xx_pid_2071_reg.h | 2066 ++++++++++++ .../soc/codecs/aw882xx/aw882xx_pid_2113_reg.h | 2351 ++++++++++++++ .../soc/codecs/aw882xx/aw882xx_pid_2308_reg.h | 2397 ++++++++++++++ sound/soc/codecs/aw882xx/aw882xx_spin.c | 247 ++ sound/soc/codecs/aw882xx/aw882xx_spin.h | 31 + 29 files changed, 32056 insertions(+) create mode 100644 sound/soc/codecs/aw882xx/Kconfig create mode 100644 sound/soc/codecs/aw882xx/Makefile create mode 100644 sound/soc/codecs/aw882xx/aw882xx.c create mode 100644 sound/soc/codecs/aw882xx/aw882xx.h create mode 100644 sound/soc/codecs/aw882xx/aw882xx_bin_parse.c create mode 100644 sound/soc/codecs/aw882xx/aw882xx_bin_parse.h create mode 100644 sound/soc/codecs/aw882xx/aw882xx_calib.c create mode 100644 sound/soc/codecs/aw882xx/aw882xx_calib.h create mode 100644 sound/soc/codecs/aw882xx/aw882xx_data_type.h create mode 100644 sound/soc/codecs/aw882xx/aw882xx_device.c create mode 100644 sound/soc/codecs/aw882xx/aw882xx_device.h create mode 100644 sound/soc/codecs/aw882xx/aw882xx_dsp.c create mode 100644 sound/soc/codecs/aw882xx/aw882xx_dsp.h create mode 100644 sound/soc/codecs/aw882xx/aw882xx_init.c create mode 100644 sound/soc/codecs/aw882xx/aw882xx_log.h create mode 100644 sound/soc/codecs/aw882xx/aw882xx_monitor.c create mode 100644 sound/soc/codecs/aw882xx/aw882xx_monitor.h create mode 100644 sound/soc/codecs/aw882xx/aw882xx_pid_1852_reg.h create mode 100644 sound/soc/codecs/aw882xx/aw882xx_pid_2013_reg.h create mode 100644 sound/soc/codecs/aw882xx/aw882xx_pid_2032_reg.h create mode 100644 sound/soc/codecs/aw882xx/aw882xx_pid_2055_reg.h create mode 100644 sound/soc/codecs/aw882xx/aw882xx_pid_2055a_reg.h create mode 100644 sound/soc/codecs/aw882xx/aw882xx_pid_2071_reg.h create mode 100644 sound/soc/codecs/aw882xx/aw882xx_pid_2113_reg.h create mode 100644 sound/soc/codecs/aw882xx/aw882xx_pid_2308_reg.h create mode 100644 sound/soc/codecs/aw882xx/aw882xx_spin.c create mode 100644 sound/soc/codecs/aw882xx/aw882xx_spin.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c75b1e9803dd..d82aaa8afb9b 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -2272,6 +2272,7 @@ config SND_SOC_LPASS_TX_MACRO tristate "Qualcomm TX Macro in LPASS(Low Power Audio SubSystem)" source "sound/soc/codecs/aw87xxx/Kconfig" +source "sound/soc/codecs/aw882xx/Kconfig" source "sound/soc/codecs/aw883xx/Kconfig" source "sound/soc/codecs/it6621/Kconfig" endmenu diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index b198d18d6209..a7ed3cdc885e 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -746,6 +746,7 @@ obj-$(CONFIG_SND_SOC_ZL38060) += snd-soc-zl38060.o # Amp obj-$(CONFIG_SND_SOC_AW87XXX) += aw87xxx/ +obj-$(CONFIG_SND_SOC_AW882XX) += aw882xx/ obj-$(CONFIG_SND_SOC_AW883XX) += aw883xx/ obj-$(CONFIG_SND_SOC_IT6621) += it6621/ obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o diff --git a/sound/soc/codecs/aw882xx/Kconfig b/sound/soc/codecs/aw882xx/Kconfig new file mode 100644 index 000000000000..dc01b6d347a7 --- /dev/null +++ b/sound/soc/codecs/aw882xx/Kconfig @@ -0,0 +1,5 @@ +config SND_SOC_AW882XX + tristate "SoC Audio for awinic AW883XX series Smart PA" + depends on I2C + help + This option enables support for AW883XX series Smart PA. diff --git a/sound/soc/codecs/aw882xx/Makefile b/sound/soc/codecs/aw882xx/Makefile new file mode 100644 index 000000000000..e44d7815a0f2 --- /dev/null +++ b/sound/soc/codecs/aw882xx/Makefile @@ -0,0 +1,5 @@ +#for AWINIC AW883XX Smart PA +snd-soc-aw882xx-objs := aw882xx.o aw882xx_device.o aw882xx_dsp.o aw882xx_monitor.o aw882xx_bin_parse.o aw882xx_init.o aw882xx_calib.o aw882xx_spin.o +obj-$(CONFIG_SND_SOC_AW882XX) += snd-soc-aw882xx.o + + diff --git a/sound/soc/codecs/aw882xx/aw882xx.c b/sound/soc/codecs/aw882xx/aw882xx.c new file mode 100644 index 000000000000..335dccf01f22 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx.c @@ -0,0 +1,2755 @@ +// SPDX-License-Identifier: GPL-2.0 +/* aw882xx.c aw882xx codec module + * + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/*#define DEBUG*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aw882xx.h" +#include "aw882xx_log.h" +#include "aw882xx_dsp.h" +#include "aw882xx_bin_parse.h" +#include "aw882xx_spin.h" + +#define AW882XX_DRIVER_VERSION "v1.15.0" +#define AW882XX_I2C_NAME "aw882xx_smartpa" + +#define AW_READ_CHIPID_RETRIES 5 /* 5 times */ +#define AW_READ_CHIPID_RETRY_DELAY 5 /* 5 ms */ + +static unsigned int g_aw882xx_dev_cnt; +static unsigned int g_print_dbg; +static unsigned int g_algo_rx_en = true; +static unsigned int g_algo_tx_en = true; +static unsigned int g_algo_copp_en = true; + +static DEFINE_MUTEX(g_aw882xx_lock); +struct aw_container *g_awinic_cfg; + +static const char *const aw882xx_switch[] = {"Disable", "Enable"}; +static const char *const aw882xx_spin[] = {"spin_0", "spin_90", + "spin_180", "spin_270"}; + +/****************************************************** + * + * aw882xx distinguish between codecs and components by version + * + ******************************************************/ +#ifdef AW_KERNEL_VER_OVER_4_19_1 +static struct aw_componet_codec_ops aw_componet_codec_ops = { + .kcontrol_codec = snd_soc_kcontrol_component, + .codec_get_drvdata = snd_soc_component_get_drvdata, + .add_codec_controls = snd_soc_add_component_controls, + .unregister_codec = snd_soc_unregister_component, + .register_codec = snd_soc_register_component, +}; +#else +static struct aw_componet_codec_ops aw_componet_codec_ops = { + .kcontrol_codec = snd_soc_kcontrol_codec, + .codec_get_drvdata = snd_soc_codec_get_drvdata, + .add_codec_controls = snd_soc_add_codec_controls, + .unregister_codec = snd_soc_unregister_codec, + .register_codec = snd_soc_register_codec, +}; +#endif + +static aw_snd_soc_codec_t *aw_get_codec(struct snd_soc_dai *dai) +{ +#ifdef AW_KERNEL_VER_OVER_4_19_1 + return dai->component; +#else + return dai->codec; +#endif +} + + +/****************************************************** + * + * aw882xx i2c write/read + * + ******************************************************/ +int aw882xx_get_version(char *buf, int size) +{ + if (size > strlen(AW882XX_DRIVER_VERSION)) { + memcpy(buf, AW882XX_DRIVER_VERSION, strlen(AW882XX_DRIVER_VERSION)); + return strlen(AW882XX_DRIVER_VERSION); + } else { + return -ENOMEM; + } +} + +int aw882xx_get_dev_num(void) +{ + return g_aw882xx_dev_cnt; +} + +static int aw882xx_i2c_writes(struct aw882xx *aw882xx, + unsigned char reg_addr, unsigned char *buf, unsigned int len) +{ + int ret = -1; + unsigned char *data = NULL; + + data = kmalloc(len+1, GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + + + data[0] = reg_addr; + memcpy(&data[1], buf, len); + + ret = i2c_master_send(aw882xx->i2c, data, len+1); + if (ret < 0) + aw_dev_err(aw882xx->dev, "i2c master send error"); + + kfree(data); + + return ret; +} + +static int aw882xx_i2c_reads(struct aw882xx *aw882xx, + unsigned char reg_addr, unsigned char *data_buf, unsigned int data_len) +{ + int ret; + struct i2c_msg msg[] = { + [0] = { + .addr = aw882xx->i2c->addr, + .flags = 0, + .len = sizeof(uint8_t), + .buf = ®_addr, + }, + [1] = { + .addr = aw882xx->i2c->addr, + .flags = I2C_M_RD, + .len = data_len, + .buf = data_buf, + }, + }; + + ret = i2c_transfer(aw882xx->i2c->adapter, msg, ARRAY_SIZE(msg)); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "transfer failed."); + return ret; + } else if (ret != AW882XX_I2C_READ_MSG_NUM) { + aw_dev_err(aw882xx->dev, "transfer failed(size error)."); + return -ENXIO; + } + + return 0; +} + +int aw882xx_i2c_write(struct aw882xx *aw882xx, + unsigned char reg_addr, unsigned int reg_data) +{ + int ret = -1; + unsigned char cnt = 0; + unsigned char buf[2]; + + buf[0] = (reg_data&0xff00)>>8; + buf[1] = (reg_data&0x00ff)>>0; + + while (cnt < AW_I2C_RETRIES) { + ret = aw882xx_i2c_writes(aw882xx, reg_addr, buf, 2); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "i2c_write cnt=%d error=%d", + cnt, ret); + } else { + if (g_print_dbg) + aw_dev_info(aw882xx->dev, "reg_addr: 0x%02x, reg_data :0x%04x", + (uint8_t)reg_addr, (uint16_t)reg_data); + break; + } + cnt++; + } + + return ret; +} + +int aw882xx_i2c_read(struct aw882xx *aw882xx, + unsigned char reg_addr, unsigned int *reg_data) +{ + int ret = -1; + unsigned char cnt = 0; + unsigned char buf[2]; + + while (cnt < AW_I2C_RETRIES) { + ret = aw882xx_i2c_reads(aw882xx, reg_addr, buf, 2); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "i2c_read cnt=%d error=%d", + cnt, ret); + } else { + *reg_data = (buf[0]<<8) | (buf[1]<<0); + if (g_print_dbg) + aw_dev_info(aw882xx->dev, "reg_addr: 0x%02x, reg_data :0x%04x", + (uint8_t)reg_addr, (uint16_t)(*reg_data)); + break; + } + cnt++; + } + + return ret; +} + +int aw882xx_i2c_write_bits(struct aw882xx *aw882xx, + unsigned char reg_addr, unsigned int mask, unsigned int reg_data) +{ + int ret = -1; + unsigned int reg_val = 0; + + ret = aw882xx_i2c_read(aw882xx, reg_addr, ®_val); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "i2c read error, ret=%d", ret); + return ret; + } + reg_val &= mask; + reg_val |= (reg_data & (~mask)); + ret = aw882xx_i2c_write(aw882xx, reg_addr, reg_val); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "i2c read error, ret=%d", ret); + return ret; + } + + return 0; +} + +static void *aw882xx_devm_kstrdup(struct device *dev, char *buf) +{ + char *str = NULL; + + str = devm_kzalloc(dev, strlen(buf) + 1, GFP_KERNEL); + if (!str) + return str; + + memcpy(str, buf, strlen(buf)); + return str; +} + +/***************************************************** + * + * snd_soc_dai_driver ops + * + *****************************************************/ +static int aw882xx_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + aw_snd_soc_codec_t *codec = aw_get_codec(dai); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + aw_dev_info(aw882xx->dev, "playback enter"); + /*load cali re*/ + aw882xx_dev_init_cali_re(aw882xx->aw_pa); + } else { + aw_dev_info(aw882xx->dev, "capture enter"); + } + return 0; +} + +static int aw882xx_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + /*struct aw882xx *aw882xx = aw_snd_soc_codec_get_drvdata(dai->codec);*/ + aw_snd_soc_codec_t *codec = aw_get_codec(dai); + + aw_dev_info(codec->dev, "fmt=0x%x", fmt); + + return 0; +} + +static int aw882xx_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + aw_snd_soc_codec_t *codec = aw_get_codec(dai); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + aw_dev_info(aw882xx->dev, "freq=%d", freq); + + aw882xx->sysclk = freq; + return 0; +} + +static int aw882xx_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + aw_snd_soc_codec_t *codec = aw_get_codec(dai); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + aw_dev_info(aw882xx->dev, "stream capture requested rate: %d, sample size: %d", + params_rate(params), params_width(params)); + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + aw_dev_info(aw882xx->dev, "stream playback requested rate: %d, sample size: %d", + params_rate(params), params_width(params)); + } + + return 0; +} + +static void aw882xx_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + aw_snd_soc_codec_t *codec = aw_get_codec(dai); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + aw882xx->rate = 0; + aw_dev_info(aw882xx->dev, "stream playback"); + } else { + aw_dev_info(aw882xx->dev, "stream capture"); + } +} + +static void aw882xx_start_pa(struct aw882xx *aw882xx) +{ + int ret; + int i; + + aw_dev_info(aw882xx->dev, "enter"); + + if (aw882xx->fw_status == AW_DEV_FW_OK) { + if (aw882xx->allow_pw == false) { + aw_dev_info(aw882xx->dev, "dev can not allow power "); + return; + } + + for (i = 0; i < AW_START_RETRIES; i++) { + /*if PA already power ,stop PA then start*/ + if (aw882xx->aw_pa->status) { + aw_dev_info(aw882xx->dev, "already start"); + return; + } + + ret = aw882xx_dev_reg_update(aw882xx->aw_pa, aw882xx->phase_sync); + if (ret) { + aw_dev_err(aw882xx->dev, "fw update failed, cnt:%d", i); + continue; + } + + ret = aw882xx_device_start(aw882xx->aw_pa); + if (ret) { + aw_dev_err(aw882xx->dev, "start failed, cnt:%d", i); + continue; + } else { + if (aw882xx->dc_flag) + queue_delayed_work(aw882xx->work_queue, + &aw882xx->dc_work, + msecs_to_jiffies(AW882XX_DC_DELAY_TIME)); + aw_dev_info(aw882xx->dev, "start success"); + break; + } + } + } else { + aw_dev_info(aw882xx->dev, "dev acf load failed"); + } + +} + +static int aw882xx_mute(struct snd_soc_dai *dai, int mute, int stream) +{ + int ret = 0; + aw_snd_soc_codec_t *codec = aw_get_codec(dai); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + aw_dev_info(aw882xx->dev, "mute state=%d", mute); + + if (stream != SNDRV_PCM_STREAM_PLAYBACK) { + aw_dev_info(aw882xx->dev, "capture"); + return 0; + } + + if (mute) { + aw882xx->pstream = false; + cancel_delayed_work_sync(&aw882xx->dc_work); + cancel_delayed_work_sync(&aw882xx->start_work); + mutex_lock(&aw882xx->lock); + g_algo_auth_st = AW_ALGO_AUTH_WAIT; + aw882xx_device_stop(aw882xx->aw_pa); + mutex_unlock(&aw882xx->lock); + } else { + if (aw882xx->fw_status == AW_DEV_FW_FAILED) { + aw_dev_info(aw882xx->dev, "fw_load failed ,can not start PA"); + return 0; + } + aw882xx->pstream = true; + mutex_lock(&aw882xx->lock); + /*aw882xx_start_pa(aw882xx);*/ + queue_delayed_work(aw882xx->work_queue, + &aw882xx->start_work, 0); + if (aw882xx->aw_pa->channel == 0) { + ret = aw882xx_spin_set_record_val(aw882xx->aw_pa); + if (ret) + aw_dev_err(aw882xx->dev, "set spin error, ret=%d", ret); + } + mutex_unlock(&aw882xx->lock); + } + + return ret; +} + +static const struct snd_soc_dai_ops aw882xx_dai_ops = { + .startup = aw882xx_startup, + .set_fmt = aw882xx_set_fmt, + .set_sysclk = aw882xx_set_dai_sysclk, + .hw_params = aw882xx_hw_params, + .mute_stream = aw882xx_mute, + .shutdown = aw882xx_shutdown, +}; + +/***************************************************** + * + * snd_soc_codec_driver | snd_soc_component_driver| + * + *****************************************************/ + +static int aw882xx_profile_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int count, ret = 0; + int res = 0; + char *name = NULL; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + + count = aw882xx_dev_get_profile_count(aw882xx->aw_pa); + if (count <= 0) { + uinfo->value.enumerated.items = 0; + aw_dev_err(aw882xx->dev, "get count[%d] failed ", count); + return 0; + } + + uinfo->value.enumerated.items = count; + + if (uinfo->value.enumerated.item >= count) + uinfo->value.enumerated.item = count - 1; + + name = uinfo->value.enumerated.name; + count = uinfo->value.enumerated.item; + ret = aw88xx_dev_get_profile_name(aw882xx->aw_pa, name, count); + if (ret) { + res = strscpy(uinfo->value.enumerated.name, "null", strlen("null") + 1); + if (res < 0) + aw_dev_err(aw882xx->dev, "copy enumerated name failed"); + } + + return 0; +} + +static int aw882xx_profile_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = aw882xx_dev_get_profile_index(aw882xx->aw_pa); + aw_dev_dbg(codec->dev, "profile index [%d]", aw882xx_dev_get_profile_index(aw882xx->aw_pa)); + return 0; + +} + +static int aw882xx_profile_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + int cur_index; + + if (aw882xx->dbg_en_prof == false) { + aw_dev_info(codec->dev, "profile close "); + return 0; + } + + /* check value valid */ + ret = aw882xx_dev_check_profile_index(aw882xx->aw_pa, ucontrol->value.integer.value[0]); + if (ret) { + aw_dev_info(codec->dev, "unsupported index %d", + (int)ucontrol->value.integer.value[0]); + return -EINVAL; + } + + /*check cur_index == set value*/ + cur_index = aw882xx_dev_get_profile_index(aw882xx->aw_pa); + if (cur_index == ucontrol->value.integer.value[0]) { + aw_dev_info(codec->dev, "index no change"); + return 0; + } + + mutex_lock(&aw882xx->lock); + aw882xx_dev_set_profile_index(aw882xx->aw_pa, ucontrol->value.integer.value[0]); + /*pstream = 0 no pcm just set status*/ + if (aw882xx->pstream && aw882xx->allow_pw) { + aw882xx_device_stop(aw882xx->aw_pa); + aw882xx_start_pa(aw882xx); + } + mutex_unlock(&aw882xx->lock); + aw_dev_info(codec->dev, "prof id %d", (int)ucontrol->value.integer.value[0]); + + return 1; +} + +static int aw882xx_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int count = 0; + int ret = 0; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + count = 2; + + uinfo->value.enumerated.items = count; + + if (uinfo->value.enumerated.item >= count) + uinfo->value.enumerated.item = count - 1; + + ret = strscpy(uinfo->value.enumerated.name, + aw882xx_switch[uinfo->value.enumerated.item], + strlen(aw882xx_switch[uinfo->value.enumerated.item]) + 1); + if (ret < 0) + aw_pr_err("copy switch name failed"); + + return 0; +} + +static int aw882xx_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = aw882xx->allow_pw; + + return 0; + +} + +static int aw882xx_switch_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + if (aw882xx->pstream) { + if (ucontrol->value.integer.value[0] == 0) { + cancel_delayed_work_sync(&aw882xx->dc_work); + cancel_delayed_work_sync(&aw882xx->start_work); + mutex_lock(&aw882xx->lock); + aw882xx_device_stop(aw882xx->aw_pa); + aw882xx->allow_pw = false; + mutex_unlock(&aw882xx->lock); + aw_dev_info(aw882xx->dev, "stop pa"); + } else { + cancel_delayed_work_sync(&aw882xx->start_work); + mutex_lock(&aw882xx->lock); + aw882xx->allow_pw = true; + if (aw882xx->fw_status == AW_DEV_FW_OK) + aw882xx_start_pa(aw882xx); + else + aw_dev_info(aw882xx->dev, "fw_load failed ,can not start PA"); + mutex_unlock(&aw882xx->lock); + } + } else { + mutex_lock(&aw882xx->lock); + if (ucontrol->value.integer.value[0]) + aw882xx->allow_pw = true; + else + aw882xx->allow_pw = false; + mutex_unlock(&aw882xx->lock); + } + + return 0; +} + +static int aw882xx_monitor_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int count = 0; + int ret = 0; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + count = 2; + + uinfo->value.enumerated.items = count; + + if (uinfo->value.enumerated.item >= count) + uinfo->value.enumerated.item = count - 1; + + ret = strscpy(uinfo->value.enumerated.name, + aw882xx_switch[uinfo->value.enumerated.item], + strlen(aw882xx_switch[uinfo->value.enumerated.item]) + 1); + if (ret < 0) + aw_pr_err("copy switch name failed"); + + return 0; +} + +static int aw882xx_monitor_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + struct aw_device *aw_dev = aw882xx->aw_pa; + + ucontrol->value.integer.value[0] = + aw_dev->monitor_desc.monitor_cfg.monitor_switch; + + aw_dev_info(aw882xx->dev, "monitor switch is %ld", + ucontrol->value.integer.value[0]); + return 0; + +} + +static int aw882xx_monitor_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + struct aw_device *aw_dev = aw882xx->aw_pa; + uint32_t ctrl_value = 0; + + ctrl_value = ucontrol->value.integer.value[0]; + + aw_dev_info(aw_dev->dev, "set monitor switch is %d", ctrl_value); + + if (aw_dev->monitor_desc.monitor_cfg.monitor_switch == ctrl_value) + return 0; + + aw_dev->monitor_desc.monitor_cfg.monitor_switch = ctrl_value; + if (ctrl_value) + aw882xx_monitor_start(&aw_dev->monitor_desc); + + return 1; +} + +static int aw882xx_hal_monitor_work_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = INT_MIN; + uinfo->value.integer.max = 0; + + return 0; +} + +static int aw882xx_hal_monitor_work_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + struct aw_device *aw_dev = aw882xx->aw_pa; + uint32_t vmax = 0; + + mutex_lock(&aw882xx->lock); + aw882xx_dev_monitor_hal_work(aw_dev, &vmax); + + ucontrol->value.integer.value[0] = vmax; + mutex_unlock(&aw882xx->lock); + + aw_dev_dbg(aw882xx->dev, "vmax is 0x%x", vmax); + return 0; + +} + +static int aw882xx_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + struct aw_volume_desc *vol_desc = &aw882xx->aw_pa->volume_desc; + + /* set kcontrol info */ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = vol_desc->mute_volume; + + return 0; +} + +static int aw882xx_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + struct aw_volume_desc *vol_desc = &aw882xx->aw_pa->volume_desc; + + ucontrol->value.integer.value[0] = vol_desc->ctl_volume; + + aw_dev_info(aw882xx->dev, "ucontrol->value.integer.value[0]=%d", + vol_desc->ctl_volume); + + return 0; +} + +static int aw882xx_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int value = 0; + int compared_vol = 0; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + struct aw_volume_desc *vol_desc = &aw882xx->aw_pa->volume_desc; + + value = ucontrol->value.integer.value[0]; + if ((value > vol_desc->mute_volume) || (value < 0)) { + aw_dev_err(aw882xx->dev, "value over range\n"); + return -EINVAL; + } + + aw_dev_info(aw882xx->dev, "ucontrol->value.integer.value[0]=%d", value); + + if (vol_desc->ctl_volume == value) + return 0; + + vol_desc->ctl_volume = value; + compared_vol = AW_GET_MAX_VALUE(vol_desc->ctl_volume, + vol_desc->monitor_volume); + + aw882xx_dev_set_volume(aw882xx->aw_pa, compared_vol); + + return 1; +} + +static int aw882xx_algo_auth_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = sizeof(struct algo_auth_data); + return 0; +} + +/*op_flag: SNDRV_CTL_TLV_OP_READ = 0, SNDRV_CTL_TLV_OP_WRITE = 1*/ +static int aw882xx_algo_auth_tlv_rw(struct snd_kcontrol *kcontrol, int op_flag, + unsigned int size, unsigned int __user *tlv) +{ + int ret = 0; + aw_snd_soc_codec_t *codec = aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = aw_componet_codec_ops.codec_get_drvdata(codec); + + struct aw_device *aw_pa = aw882xx->aw_pa; + struct algo_auth_data algo_data; + + aw_dev_dbg(aw882xx->dev, "op_flag = [%d]", op_flag); + + if (!tlv) { + aw_dev_err(aw882xx->dev, "tlv is NULL"); + return -EINVAL; + } + + if (size != sizeof(struct algo_auth_data)) { + aw_dev_err(aw882xx->dev, "size != algo_auth_data"); + return -EINVAL; + } + + switch (op_flag) { + case SNDRV_CTL_TLV_OP_READ: + aw_dev_dbg(aw882xx->dev, "get algo auth data"); + memset(&algo_data, 0x0, sizeof(struct algo_auth_data)); + + algo_data.auth_mode = aw_pa->auth_desc.auth_mode; + algo_data.chip_id = aw_pa->auth_desc.chip_id; + algo_data.random = aw_pa->auth_desc.random; + algo_data.reg_crc = aw_pa->auth_desc.reg_crc; + algo_data.check_result = aw_pa->auth_desc.check_result; + + if (copy_to_user((void __user *)tlv, (char *)&algo_data, size)) + ret = -EFAULT; + break; + case SNDRV_CTL_TLV_OP_WRITE: + aw_dev_dbg(aw882xx->dev, "set algo auth data"); + if (copy_from_user(&algo_data, (void __user *)tlv, size)) + ret = -EFAULT; + + aw882xx_dev_algo_auth_mode(aw_pa, &algo_data); + break; + default: + aw_dev_dbg(aw882xx->dev, "unsupport op flag[0x%x]", op_flag); + return -EINVAL; + } + + aw_dev_dbg(aw882xx->dev, "mode=%d,reg_crc=0x%x,random=0x%x,id=0x%x,res=%d", + algo_data.auth_mode, algo_data.reg_crc, algo_data.random, + algo_data.chip_id, algo_data.check_result); + + return ret; +} + +static int aw882xx_dynamic_create_controls(struct aw882xx *aw882xx) +{ + struct snd_kcontrol_new *aw882xx_dev_control = NULL; + char *kctl_name = NULL; + + aw882xx_dev_control = devm_kzalloc(aw882xx->codec->dev, + sizeof(struct snd_kcontrol_new) * AW_KCTL_NUM, GFP_KERNEL); + if (aw882xx_dev_control == NULL) + return -ENOMEM; + + + kctl_name = devm_kzalloc(aw882xx->codec->dev, AW_NAME_BUF_MAX, GFP_KERNEL); + if (!kctl_name) + return -ENOMEM; + + snprintf(kctl_name, AW_NAME_BUF_MAX, "aw_dev_%d_prof", aw882xx->aw_pa->channel); + + aw882xx_dev_control[KCTL_TYPE_PROFILE].name = kctl_name; + aw882xx_dev_control[KCTL_TYPE_PROFILE].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + aw882xx_dev_control[KCTL_TYPE_PROFILE].info = aw882xx_profile_info; + aw882xx_dev_control[KCTL_TYPE_PROFILE].get = aw882xx_profile_get; + aw882xx_dev_control[KCTL_TYPE_PROFILE].put = aw882xx_profile_set; + + kctl_name = devm_kzalloc(aw882xx->codec->dev, AW_NAME_BUF_MAX, GFP_KERNEL); + if (!kctl_name) + return -ENOMEM; + + snprintf(kctl_name, AW_NAME_BUF_MAX, "aw_dev_%d_switch", aw882xx->aw_pa->channel); + + aw882xx_dev_control[KCTL_TYPE_SWITCH].name = kctl_name; + aw882xx_dev_control[KCTL_TYPE_SWITCH].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + aw882xx_dev_control[KCTL_TYPE_SWITCH].info = aw882xx_switch_info; + aw882xx_dev_control[KCTL_TYPE_SWITCH].get = aw882xx_switch_get; + aw882xx_dev_control[KCTL_TYPE_SWITCH].put = aw882xx_switch_set; + + kctl_name = devm_kzalloc(aw882xx->codec->dev, AW_NAME_BUF_MAX, GFP_KERNEL); + if (!kctl_name) + return -ENOMEM; + + snprintf(kctl_name, AW_NAME_BUF_MAX, "aw_dev_%d_monitor", aw882xx->aw_pa->channel); + + aw882xx_dev_control[KCTL_TYPE_MONITOR].name = kctl_name; + aw882xx_dev_control[KCTL_TYPE_MONITOR].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + aw882xx_dev_control[KCTL_TYPE_MONITOR].info = aw882xx_monitor_info; + aw882xx_dev_control[KCTL_TYPE_MONITOR].get = aw882xx_monitor_get; + aw882xx_dev_control[KCTL_TYPE_MONITOR].put = aw882xx_monitor_set; + + + kctl_name = devm_kzalloc(aw882xx->codec->dev, AW_NAME_BUF_MAX, GFP_KERNEL); + if (!kctl_name) + return -ENOMEM; + + snprintf(kctl_name, AW_NAME_BUF_MAX, "aw_dev_%d_volume", aw882xx->aw_pa->channel); + + aw882xx_dev_control[KCTL_TYPE_VOLUME].name = kctl_name; + aw882xx_dev_control[KCTL_TYPE_VOLUME].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + aw882xx_dev_control[KCTL_TYPE_VOLUME].info = aw882xx_volume_info; + aw882xx_dev_control[KCTL_TYPE_VOLUME].get = aw882xx_volume_get; + aw882xx_dev_control[KCTL_TYPE_VOLUME].put = aw882xx_volume_put; + + + kctl_name = devm_kzalloc(aw882xx->codec->dev, AW_NAME_BUF_MAX, GFP_KERNEL); + if (!kctl_name) + return -ENOMEM; + + snprintf(kctl_name, AW_NAME_BUF_MAX, "aw_dev_%d_hal_mon_work", aw882xx->aw_pa->channel); + + aw882xx_dev_control[KCTL_TYPE_MON_HAL].name = kctl_name; + aw882xx_dev_control[KCTL_TYPE_MON_HAL].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + aw882xx_dev_control[KCTL_TYPE_MON_HAL].access = SNDRV_CTL_ELEM_ACCESS_READ; + aw882xx_dev_control[KCTL_TYPE_MON_HAL].info = aw882xx_hal_monitor_work_info; + aw882xx_dev_control[KCTL_TYPE_MON_HAL].get = aw882xx_hal_monitor_work_get; + + aw_componet_codec_ops.add_codec_controls(aw882xx->codec, + aw882xx_dev_control, AW_KCTL_NUM); + + return 0; +} + +static void aw882xx_request_firmware(struct work_struct *work) +{ + int ret = -1; + struct aw882xx *aw882xx = + container_of(work, struct aw882xx, fw_work.work); + const struct firmware *cont = NULL; + struct aw_container *aw_cfg = NULL; + + aw882xx->fw_status = AW_DEV_FW_FAILED; + ret = request_firmware(&cont, ACF_BIN_NAME, aw882xx->dev); + if ((ret) || (!cont)) { + aw_dev_info(aw882xx->dev, "load [%s] failed!", ACF_BIN_NAME); + if (aw882xx->fw_retry_cnt == AW_READ_CHIPID_RETRIES) { + aw882xx->fw_retry_cnt = 0; + } else { + aw882xx->fw_retry_cnt++; + /* sleep 1s */ + msleep(1000); + aw_dev_info(aw882xx->dev, "load [%s] try [%d]!", + ACF_BIN_NAME, aw882xx->fw_retry_cnt); + aw882xx_request_firmware(work); + } + return; + } + + aw_dev_info(aw882xx->dev, "load [%s] , file size: [%zu]", + ACF_BIN_NAME, cont ? cont->size : 0); + + mutex_lock(&g_aw882xx_lock); + if (g_awinic_cfg == NULL) { + aw_cfg = vzalloc(cont->size + sizeof(int)); + if (aw_cfg == NULL) { + release_firmware(cont); + aw_dev_err(aw882xx->dev, "malloc failed"); + mutex_unlock(&g_aw882xx_lock); + return; + } + aw_cfg->len = cont->size; + memcpy(aw_cfg->data, cont->data, cont->size); + release_firmware(cont); + ret = aw882xx_dev_parse_check_acf(aw_cfg); + if (ret) { + aw_dev_err(aw882xx->dev, "Load [%s] failed ....!", ACF_BIN_NAME); + vfree(aw_cfg); + aw_cfg = NULL; + mutex_unlock(&g_aw882xx_lock); + return; + } + g_awinic_cfg = aw_cfg; + } else { + aw_cfg = g_awinic_cfg; + release_firmware(cont); + aw_dev_info(aw882xx->dev, "[%s] already loaded...", ACF_BIN_NAME); + } + mutex_unlock(&g_aw882xx_lock); + + mutex_lock(&aw882xx->lock); + /*aw device init*/ + ret = aw882xx_device_init(aw882xx->aw_pa, aw_cfg); + if (ret < 0) { + aw_dev_info(aw882xx->dev, "dev init failed"); + mutex_unlock(&aw882xx->lock); + return; + } + + /*create kcontrol by profile*/ + aw882xx_dynamic_create_controls(aw882xx); + + aw882xx->fw_status = AW_DEV_FW_OK; + aw882xx->fw_retry_cnt = 0; + + mutex_unlock(&aw882xx->lock); +} + +static void aw882xx_startup_work(struct work_struct *work) +{ + struct aw882xx *aw882xx = container_of(work, struct aw882xx, start_work.work); + + aw_dev_info(aw882xx->dev, "enter"); + + mutex_lock(&aw882xx->lock); + aw882xx_start_pa(aw882xx); + mutex_unlock(&aw882xx->lock); +} + +static void aw882xx_dc_prot_work(struct work_struct *work) +{ + struct aw882xx *aw882xx = container_of(work, struct aw882xx, dc_work.work); + int dc_status = -1; + int dev_status = aw882xx_dev_status(aw882xx->aw_pa); + + if (aw882xx->dc_flag) { + if (dev_status) { + dc_status = aw882xx_dev_dc_status(aw882xx->aw_pa); + if (dc_status > 0) { + cancel_delayed_work_sync(&aw882xx->start_work); + mutex_lock(&aw882xx->lock); + aw882xx_device_stop(aw882xx->aw_pa); + mutex_unlock(&aw882xx->lock); + } else { + queue_delayed_work(aw882xx->work_queue, + &aw882xx->dc_work, + msecs_to_jiffies(AW882XX_DC_DELAY_TIME)); + } + } + } +} + +#ifdef AW882XX_IRQ_START_FLAG +static void aw882xx_irq_restart(struct aw882xx *aw882xx) +{ + int ret; + + aw_dev_dbg(aw882xx->dev, "enter"); + + mutex_lock(&aw882xx->lock); + + /*stop pa*/ + aw882xx_device_stop(aw882xx->aw_pa); + + /*hw reset*/ + aw882xx_hw_reset(aw882xx); + + /*aw reinit*/ + if (aw882xx->fw_status == AW_DEV_FW_OK) { + ret = aw882xx_device_irq_reinit(aw882xx->aw_pa); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "irq reinit failed"); + goto failed_exit; + } + + if (aw882xx->allow_pw && aw882xx->pstream) { + ret = aw882xx_device_start(aw882xx->aw_pa); + if (ret) { + aw_dev_err(aw882xx->dev, "start failed"); + goto failed_exit; + } + } else { + aw_dev_info(aw882xx->dev, "allow_pw [%d] ,pstream[%d], not start", + aw882xx->allow_pw, aw882xx->pstream); + } + } else { + aw_dev_err(aw882xx->dev, "fw not load ,cannot init device"); + } +failed_exit: + mutex_unlock(&aw882xx->lock); +} + +static void aw882xx_interrupt_work(struct work_struct *work) +{ + struct aw882xx *aw882xx = container_of(work, struct aw882xx, interrupt_work.work); + int16_t reg_value; + int ret; + + aw_dev_info(aw882xx->dev, "enter"); + + /*read reg value*/ + ret = aw882xx_dev_get_int_status(aw882xx->aw_pa, ®_value); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "get init_reg value failed"); + } else { + aw_dev_info(aw882xx->dev, "int value 0x%x", reg_value); + if (aw882xx->aw_pa->ops.aw_get_irq_type) { + ret = aw882xx->aw_pa->ops.aw_get_irq_type(aw882xx->aw_pa, reg_value); + if (ret != INT_TYPE_NONE) { + aw882xx_irq_restart(aw882xx); + return; + } + } + } + + /*clear init reg*/ + aw882xx_dev_clear_int_status(aw882xx->aw_pa); + + /*unmask interrupt*/ + aw882xx_dev_set_intmask(aw882xx->aw_pa, true); +} +#else +static void aw882xx_interrupt_work(struct work_struct *work) +{ + struct aw882xx *aw882xx = container_of(work, struct aw882xx, interrupt_work.work); + struct aw_device *aw_dev = aw882xx->aw_pa; + unsigned int reg_value = 0; + + aw882xx_i2c_read(aw882xx, aw_dev->sysst_desc.reg, ®_value); + aw_dev_info(aw882xx->dev, "SYSST is 0x%04x", (uint16_t)reg_value); + + aw882xx_i2c_read(aw882xx, aw_dev->int_desc.st_reg, ®_value); + aw_dev_info(aw882xx->dev, "SYSINT is 0x%04x", (uint16_t)reg_value); + + /*unmask interrupt*/ + aw882xx_dev_set_intmask(aw882xx->aw_pa, true); +} +#endif + +static int aw882xx_set_rx_en(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = -EINVAL; + uint32_t ctrl_value = 0; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + aw_dev_dbg(aw882xx->dev, "ucontrol->value.integer.value[0]=%ld", + ucontrol->value.integer.value[0]); + + ctrl_value = ucontrol->value.integer.value[0]; + + if (aw882xx->pstream) { + ret = aw882xx_dev_set_afe_module_en(AW_RX_MODULE, ctrl_value); + if (ret) + aw_dev_err(aw882xx->dev, "dsp_msg error, ret=%d", ret); + } else { + aw_dev_info(aw882xx->dev, "stream no start only record"); + } + + g_algo_rx_en = ctrl_value; + aw_dev_info(aw882xx->dev, "set value %d", ctrl_value); + return 0; +} + +static int aw882xx_get_rx_en(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = -EINVAL; + uint32_t ctrl_value = 0; + + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + if (aw882xx->pstream) { + ret = aw882xx_dev_get_afe_module_en(AW_RX_MODULE, &ctrl_value); + if (ret) + aw_dev_err(aw882xx->dev, "dsp_msg error, ret=%d", ret); + + ucontrol->value.integer.value[0] = ctrl_value; + } else { + ucontrol->value.integer.value[0] = g_algo_rx_en; + aw_dev_info(aw882xx->dev, "no stream, use record value"); + } + + aw_dev_dbg(aw882xx->dev, "aw882xx_rx_enable %ld", + ucontrol->value.integer.value[0]); + return 0; +} + +static int aw882xx_set_tx_en(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = -EINVAL; + uint32_t ctrl_value = 0; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + aw_dev_dbg(aw882xx->dev, "ucontrol->value.integer.value[0]=%ld", + ucontrol->value.integer.value[0]); + + ctrl_value = ucontrol->value.integer.value[0]; + + if (aw882xx->pstream) { + ret = aw882xx_dev_set_afe_module_en(AW_TX_MODULE, ctrl_value); + if (ret) + aw_dev_err(aw882xx->dev, "dsp_msg error, ret=%d", ret); + } else { + aw_dev_info(aw882xx->dev, "stream no start only record"); + } + + g_algo_tx_en = ctrl_value; + aw_dev_info(aw882xx->dev, "set value %d", ctrl_value); + return 0; +} + +static int aw882xx_get_tx_en(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = -EINVAL; + uint32_t ctrl_value = 0; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + if (aw882xx->pstream) { + ret = aw882xx_dev_get_afe_module_en(AW_TX_MODULE, &ctrl_value); + if (ret) { + aw_dev_err(aw882xx->dev, "dsp_msg error, ret=%d", ret); + ctrl_value = 0; + } + ucontrol->value.integer.value[0] = ctrl_value; + } else { + ucontrol->value.integer.value[0] = g_algo_tx_en; + aw_dev_info(aw882xx->dev, "no stream, use record value"); + } + + aw_dev_dbg(aw882xx->dev, "aw882xx_tx_enable %ld", + ucontrol->value.integer.value[0]); + return 0; +} + +static int aw882xx_set_copp_en(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = -EINVAL; + uint32_t ctrl_value = 0; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + aw_dev_dbg(aw882xx->dev, "ucontrol->value.integer.value[0]=%ld", + ucontrol->value.integer.value[0]); + ctrl_value = ucontrol->value.integer.value[0]; + + if (aw882xx->pstream) { + ret = aw882xx_dev_set_copp_module_en(ctrl_value); + if (ret) + aw_dev_err(aw882xx->dev, "dsp_msg error, ret=%d", ret); + } else { + aw_dev_info(aw882xx->dev, "stream no start only record"); + } + + g_algo_copp_en = ctrl_value; + aw_dev_info(aw882xx->dev, "set value %d", ctrl_value); + + return 0; +} + +static int aw882xx_get_copp_en(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = g_algo_copp_en; + + aw_dev_dbg(aw882xx->dev, "done nothing"); + return 0; +} + +void aw882xx_kcontorl_set(struct aw882xx *aw882xx) +{ + int ret; + + ret = aw882xx_dev_set_afe_module_en(AW_RX_MODULE, g_algo_rx_en); + if (ret) + aw_dev_err(aw882xx->dev, "afe set, ret=%d", ret); + + ret = aw882xx_dev_set_copp_module_en(g_algo_copp_en); + if (ret) + aw_dev_err(aw882xx->dev, "copp set error, ret=%d", ret); +} + +static int aw882xx_set_spin(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = -EINVAL; + uint32_t ctrl_value = 0; + struct aw_device *aw_dev = NULL; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + aw_dev_dbg(aw882xx->dev, "ucontrol->value.integer.value[0]=%ld", + ucontrol->value.integer.value[0]); + + aw_dev = aw882xx->aw_pa; + ctrl_value = ucontrol->value.integer.value[0]; + if (ctrl_value >= ARRAY_SIZE(aw882xx_spin)) { + aw_dev_err(aw_dev->dev, "spin value %d is unsupport", ctrl_value); + return -EINVAL; + } + + ret = aw882xx_spin_value_set(aw_dev, ctrl_value, aw882xx->pstream); + if (ret) + aw_dev_err(aw882xx->dev, "set spin error, ret = %d", ret); + return ret; +} + +static int aw882xx_get_spin(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = -EINVAL; + struct aw_device *aw_dev = NULL; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + uint32_t ctrl_value = 0; + + aw_dev = aw882xx->aw_pa; + ret = aw882xx_spin_value_get(aw_dev, &ctrl_value, aw882xx->pstream); + if (ret) { + aw_dev_err(aw882xx->dev, "get spin failed!, ret = %d", ret); + ctrl_value = 0; + } + ucontrol->value.integer.value[0] = ctrl_value; + + aw_dev_dbg(aw882xx->dev, "spin value is %s", aw882xx_spin[ctrl_value]); + return 0; +} + +static int aw882xx_get_fade_in_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + unsigned int time; + + aw882xx_dev_get_fade_time(&time, true); + ucontrol->value.integer.value[0] = time; + + aw_pr_dbg("step time %ld", ucontrol->value.integer.value[0]); + + return 0; +} + +static int aw882xx_set_fade_in_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + if (ucontrol->value.integer.value[0] > mc->max) { + aw_pr_dbg("set val %ld overflow %d", + ucontrol->value.integer.value[0], mc->max); + return 0; + } + aw882xx_dev_set_fade_time(ucontrol->value.integer.value[0], true); + + aw_pr_dbg("step time %ld", ucontrol->value.integer.value[0]); + return 0; +} + +static int aw882xx_get_fade_out_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + unsigned int time; + + aw882xx_dev_get_fade_time(&time, false); + ucontrol->value.integer.value[0] = time; + + aw_pr_dbg("step time %ld", ucontrol->value.integer.value[0]); + + return 0; +} + +static int aw882xx_set_fade_out_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + if (ucontrol->value.integer.value[0] > mc->max) { + aw_pr_dbg("set val %ld overflow %d", + ucontrol->value.integer.value[0], mc->max); + return 0; + } + + aw882xx_dev_set_fade_time(ucontrol->value.integer.value[0], false); + + aw_pr_dbg("step time %ld", ucontrol->value.integer.value[0]); + + return 0; +} + + +static int aw882xx_hal_get_monitor_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + unsigned int time; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(codec); + + aw882xx_dev_monitor_hal_get_time(aw882xx->aw_pa, &time); + ucontrol->value.integer.value[0] = time; + + aw_pr_dbg("get monitor time %ld", ucontrol->value.integer.value[0]); + + return 0; +} + +static int aw882xx_hal_set_monitor_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + return 0; +} + +static const struct soc_enum aw882xx_snd_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(aw882xx_switch), aw882xx_switch), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(aw882xx_spin), aw882xx_spin), +}; + +static struct snd_kcontrol_new aw882xx_controls[] = { + SOC_ENUM_EXT("aw882xx_rx_switch", aw882xx_snd_enum[0], + aw882xx_get_rx_en, aw882xx_set_rx_en), + SOC_ENUM_EXT("aw882xx_tx_switch", aw882xx_snd_enum[0], + aw882xx_get_tx_en, aw882xx_set_tx_en), + SOC_ENUM_EXT("aw882xx_copp_switch", aw882xx_snd_enum[0], + aw882xx_get_copp_en, aw882xx_set_copp_en), + SOC_SINGLE_EXT("aw882xx_fadein_us", 0, 0, 1000000, 0, + aw882xx_get_fade_in_time, aw882xx_set_fade_in_time), + SOC_SINGLE_EXT("aw882xx_fadeout_us", 0, 0, 1000000, 0, + aw882xx_get_fade_out_time, aw882xx_set_fade_out_time), + SOC_SINGLE_EXT("aw882xx_hal_monitor_time", 0, 0, 100000, 0, + aw882xx_hal_get_monitor_time, aw882xx_hal_set_monitor_time), + +}; + +static struct snd_kcontrol_new aw882xx_spin_control[] = { + SOC_ENUM_EXT("aw882xx_spin_switch", aw882xx_snd_enum[1], + aw882xx_get_spin, aw882xx_set_spin), +}; + +static void aw882xx_add_codec_controls(struct aw882xx *aw882xx) +{ + struct snd_kcontrol_new *aw882xx_dev_control = NULL; + char *kctl_name = NULL; + + aw_dev_info(aw882xx->dev, "enter"); + + aw882xx_dev_control = devm_kzalloc(aw882xx->codec->dev, + sizeof(struct snd_kcontrol_new), GFP_KERNEL); + + if (aw882xx_dev_control == NULL) + return; + + kctl_name = devm_kzalloc(aw882xx->codec->dev, AW_NAME_BUF_MAX, GFP_KERNEL); + if (!kctl_name) + return; + + snprintf(kctl_name, AW_NAME_BUF_MAX, "aw_algo_auth"); + + aw882xx_dev_control[0].name = kctl_name; + aw882xx_dev_control[0].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + aw882xx_dev_control[0].access = SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK|SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE; + aw882xx_dev_control[0].info = aw882xx_algo_auth_info; + aw882xx_dev_control[0].tlv.c = aw882xx_algo_auth_tlv_rw; + + aw_componet_codec_ops.add_codec_controls(aw882xx->codec, aw882xx_dev_control, 1); + + aw_componet_codec_ops.add_codec_controls(aw882xx->codec, + &aw882xx_controls[0], ARRAY_SIZE(aw882xx_controls)); + + if (aw882xx->aw_pa->spin_desc.aw_spin_kcontrol_st == AW_SPIN_KCONTROL_ENABLE) + aw_componet_codec_ops.add_codec_controls(aw882xx->codec, + aw882xx_spin_control, ARRAY_SIZE(aw882xx_spin_control)); +} + +static int aw882xx_append_i2c_suffix(char *format, + const char **name, struct aw882xx *aw882xx) +{ + char buf[64]; + int i2cbus = aw882xx->i2c->adapter->nr; + int i2caddr = aw882xx->i2c->addr; + + snprintf(buf, sizeof(buf), format, *name, i2cbus, i2caddr); + (*name) = aw882xx_devm_kstrdup(aw882xx->dev, buf); + if (!(*name)) + return -ENOMEM; + + aw_dev_info(aw882xx->dev, "change name is %s", (*name)); + return 0; +} + +static int aw882xx_append_channel_suffix(char *format, + const char **name, struct aw882xx *aw882xx) +{ + char buf[64]; + int channel = aw882xx->aw_pa->channel; + + snprintf(buf, sizeof(buf), format, *name, channel); + (*name) = aw882xx_devm_kstrdup(aw882xx->dev, buf); + if (!(*name)) + return -ENOMEM; + + aw_dev_info(aw882xx->dev, "change name is %s", (*name)); + return 0; +} + +#ifdef AW_MTK_PLATFORM_WITH_DSP +static const struct snd_soc_dapm_widget aw882xx_dapm_widgets[] = { + /* playback */ + SND_SOC_DAPM_AIF_IN("AIF_RX", "Speaker_Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_OUTPUT("audio_out"), + /* capture */ + SND_SOC_DAPM_AIF_OUT("AIF_TX", "Speaker_Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_INPUT("iv_in"), +}; + +static const struct snd_soc_dapm_route aw882xx_audio_map[] = { + {"audio_out", NULL, "AIF_RX"}, + {"AIF_TX", NULL, "iv_in"}, +}; + +#if KERNEL_VERSION(4, 2, 0) > LINUX_VERSION_CODE +static struct snd_soc_dapm_context *snd_soc_codec_get_dapm(struct snd_soc_codec *codec) +{ + return &codec->dapm; +} +#endif +#endif + +static void aw882xx_add_widgets(struct aw882xx *aw882xx) +{ +#ifdef AW_MTK_PLATFORM_WITH_DSP + int ret; + int i = 0; + struct snd_soc_dapm_widget *aw_widgets = NULL; + struct snd_soc_dapm_route *aw_route = NULL; +#ifdef AW_KERNEL_VER_OVER_4_19_1 + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(aw882xx->codec); +#else + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(aw882xx->codec); +#endif + + + /*add widgets*/ + aw_widgets = devm_kzalloc(aw882xx->dev, + sizeof(struct snd_soc_dapm_widget) * ARRAY_SIZE(aw882xx_dapm_widgets), + GFP_KERNEL); + if (!aw_widgets) { + aw_dev_err(aw882xx->dev, "alloc widget memory failed!"); + return; + } + memcpy(aw_widgets, aw882xx_dapm_widgets, + sizeof(struct snd_soc_dapm_widget) * ARRAY_SIZE(aw882xx_dapm_widgets)); + + for (i = 0; i < ARRAY_SIZE(aw882xx_dapm_widgets); i++) { + if (aw882xx->rename_flag == AW_RENAME_ENABLE) { + if (aw_widgets[i].name) { + ret = aw882xx_append_channel_suffix("%s_%d", + &aw_widgets[i].name, aw882xx); + if (ret) { + aw_dev_err(aw882xx->dev, "append widget name channel suffix failed!"); + return; + } + } + + if (aw_widgets[i].sname) { + ret = aw882xx_append_channel_suffix("%s_%d", + &aw_widgets[i].sname, aw882xx); + if (ret) { + aw_dev_err(aw882xx->dev, "append widget sname channel suffix failed!"); + return; + } + } + } else { + if (aw_widgets[i].name) { + ret = aw882xx_append_i2c_suffix("%s_%d_%x", + &aw_widgets[i].name, aw882xx); + if (ret) { + aw_dev_err(aw882xx->dev, "append widget name i2c suffix failed!"); + return; + } + } + + if (aw_widgets[i].sname) { + ret = aw882xx_append_i2c_suffix("%s_%d_%x", + &aw_widgets[i].sname, aw882xx); + if (ret) { + aw_dev_err(aw882xx->dev, "append widget sname i2c suffix failed!"); + return; + } + } + } + + } + + snd_soc_dapm_new_controls(dapm, aw_widgets, ARRAY_SIZE(aw882xx_dapm_widgets)); + + /*add route*/ + aw_route = devm_kzalloc(aw882xx->dev, + sizeof(struct snd_soc_dapm_route) * ARRAY_SIZE(aw882xx_audio_map), + GFP_KERNEL); + if (!aw_route) { + aw_dev_err(aw882xx->dev, "alloc route memory failed!"); + return; + } + memcpy(aw_route, aw882xx_audio_map, + sizeof(struct snd_soc_dapm_route) * ARRAY_SIZE(aw882xx_audio_map)); + + for (i = 0; i < ARRAY_SIZE(aw882xx_audio_map); i++) { + if (aw882xx->rename_flag == AW_RENAME_ENABLE) { + if (aw_route[i].sink) { + ret = aw882xx_append_channel_suffix("%s_%d", + &aw_route[i].sink, aw882xx); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "append sink channel suffix failed!"); + return; + } + } + + if (aw_route[i].source) { + ret = aw882xx_append_channel_suffix("%s_%d", + &aw_route[i].source, aw882xx); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "append source channel suffix failed!"); + return; + } + } + } else { + if (aw_route[i].sink) { + ret = aw882xx_append_i2c_suffix("%s_%d_%x", + &aw_route[i].sink, aw882xx); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "append sink i2c suffix failed!"); + return; + } + } + + if (aw_route[i].source) { + ret = aw882xx_append_i2c_suffix("%s_%d_%x", + &aw_route[i].source, aw882xx); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "append source i2c suffix failed!"); + return; + } + } + } + + } + snd_soc_dapm_add_routes(dapm, aw_route, ARRAY_SIZE(aw882xx_audio_map)); +#endif +} + +static void aw882xx_load_fw(struct aw882xx *aw882xx) +{ + if (aw882xx->sync_load) { + aw882xx_request_firmware(&aw882xx->fw_work.work); + } else { + queue_delayed_work(aw882xx->work_queue, + &aw882xx->fw_work, + msecs_to_jiffies(AW882XX_LOAD_FW_DELAY_TIME)); + } +} + +static int aw882xx_codec_probe(aw_snd_soc_codec_t *aw_codec) +{ + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(aw_codec); + aw_dev_info(aw882xx->dev, "enter"); + + aw882xx->work_queue = create_singlethread_workqueue("aw882xx"); + if (!aw882xx->work_queue) { + aw_dev_err(aw882xx->dev, "create workqueue failed !"); + return -EINVAL; + } + + INIT_DELAYED_WORK(&aw882xx->start_work, aw882xx_startup_work); + INIT_DELAYED_WORK(&aw882xx->interrupt_work, aw882xx_interrupt_work); + INIT_DELAYED_WORK(&aw882xx->dc_work, aw882xx_dc_prot_work); + INIT_DELAYED_WORK(&aw882xx->fw_work, aw882xx_request_firmware); + + aw882xx->codec = aw_codec; + + if (aw882xx->aw_pa->channel == 0) + aw882xx_add_codec_controls(aw882xx); + + aw882xx_add_widgets(aw882xx); + + /*load fw bin*/ + aw882xx_load_fw(aw882xx); + + /*load cali re*/ + aw882xx_dev_init_cali_re(aw882xx->aw_pa); + + return 0; +} + +#ifdef AW_KERNEL_VER_OVER_4_19_1 +static void aw882xx_codec_remove(aw_snd_soc_codec_t *aw_codec) +{ + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(aw_codec); + aw_dev_info(aw882xx->dev, "enter"); + aw882xx_dev_deinit(aw882xx->aw_pa); + destroy_workqueue(aw882xx->work_queue); + aw882xx->work_queue = NULL; +} +#else +static int aw882xx_codec_remove(aw_snd_soc_codec_t *aw_codec) +{ + struct aw882xx *aw882xx = + aw_componet_codec_ops.codec_get_drvdata(aw_codec); + + aw_dev_info(aw882xx->dev, "enter"); + aw882xx_dev_deinit(aw882xx->aw_pa); + destroy_workqueue(aw882xx->work_queue); + aw882xx->work_queue = NULL; + return 0; +} +#endif + +static int aw882xx_dai_drv_append_suffix(struct aw882xx *aw882xx, + struct snd_soc_dai_driver *dai_drv, + int num_dai) +{ + int ret; + int i; + + if ((dai_drv != NULL) && (num_dai > 0)) + for (i = 0; i < num_dai; i++) { + if (aw882xx->rename_flag == AW_RENAME_ENABLE) { + ret = aw882xx_append_channel_suffix("%s-%d", + &dai_drv->name, aw882xx); + if (ret < 0) + return ret; + ret = aw882xx_append_channel_suffix("%s_%d", + &dai_drv->playback.stream_name, aw882xx); + if (ret < 0) + return ret; + ret = aw882xx_append_channel_suffix("%s_%d", + &dai_drv->capture.stream_name, aw882xx); + if (ret < 0) + return ret; + dev_set_name(aw882xx->dev, "%s_%d", + "aw882xx_smartpa", aw882xx->aw_pa->channel); + aw_dev_info(aw882xx->dev, "change dev_name:%s", + dev_name(aw882xx->dev)); + } else { + ret = aw882xx_append_i2c_suffix("%s-%d-%x", + &dai_drv->name, aw882xx); + if (ret < 0) + return ret; + ret = aw882xx_append_i2c_suffix("%s_%d_%x", + &dai_drv->playback.stream_name, aw882xx); + if (ret < 0) + return ret; + ret = aw882xx_append_i2c_suffix("%s_%d_%x", + &dai_drv->capture.stream_name, aw882xx); + if (ret < 0) + return ret; + } + + aw_dev_info(aw882xx->dev, "dai name [%s]", dai_drv[i].name); + aw_dev_info(aw882xx->dev, "pstream_name name [%s]", dai_drv[i].playback.stream_name); + aw_dev_info(aw882xx->dev, "cstream_name name [%s]", dai_drv[i].capture.stream_name); + } + + return 0; +} + +static struct snd_soc_dai_driver aw882xx_dai[] = { + { + .name = "aw882xx-aif", + .id = 1, + .playback = { + .stream_name = "Speaker_Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_96000, + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), + }, + .capture = { + .stream_name = "Speaker_Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_96000, + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), + }, + .ops = &aw882xx_dai_ops, + /* .symmetric_rates = 1,*/ + }, +}; + + +#ifdef AW_KERNEL_VER_OVER_4_19_1 +static const struct snd_soc_component_driver soc_codec_dev_aw882xx = { + .probe = aw882xx_codec_probe, + .remove = aw882xx_codec_remove, +}; +#else +static const struct snd_soc_codec_driver soc_codec_dev_aw882xx = { + .probe = aw882xx_codec_probe, + .remove = aw882xx_codec_remove, +}; +#endif + +static int aw_componet_codec_register(struct aw882xx *aw882xx) +{ + int ret = 0; + struct snd_soc_dai_driver *dai_drv = NULL; + + dai_drv = devm_kzalloc(aw882xx->dev, sizeof(aw882xx_dai), GFP_KERNEL); + if (dai_drv == NULL) + return -ENOMEM; + + + memcpy(dai_drv, aw882xx_dai, sizeof(aw882xx_dai)); + + aw882xx_dai_drv_append_suffix(aw882xx, dai_drv, ARRAY_SIZE(aw882xx_dai)); + + ret = aw882xx->codec_ops->register_codec(aw882xx->dev, + &soc_codec_dev_aw882xx, + dai_drv, ARRAY_SIZE(aw882xx_dai)); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "failed to register aw882xx: %d", ret); + return -EINVAL; + } + + if (aw882xx->rename_flag == AW_RENAME_ENABLE) { + dev_set_name(aw882xx->dev, "%d-00%x", + aw882xx->i2c->adapter->nr, aw882xx->i2c->addr); + aw_dev_info(aw882xx->dev, "reset dev_name:%s", + dev_name(aw882xx->dev)); + } + + return 0; +} +/***************************************************** + * + * device tree + * + *****************************************************/ +static int aw882xx_parse_gpio_dt(struct aw882xx *aw882xx, + struct device_node *np) +{ + if (!np) { + aw882xx->reset_gpio = -1; + aw882xx->irq_gpio = -1; + return -EINVAL; + } + + aw882xx->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); + if (aw882xx->reset_gpio < 0) + aw_dev_info(aw882xx->dev, "no reset gpio provided, will not HW reset device"); + else + aw_dev_info(aw882xx->dev, "reset gpio provided ok"); + + aw882xx->irq_gpio = of_get_named_gpio(np, "irq-gpio", 0); + if (aw882xx->irq_gpio < 0) + aw_dev_info(aw882xx->dev, "no irq gpio provided."); + else + aw_dev_info(aw882xx->dev, "irq gpio provided ok."); + + + return 0; +} + +static struct aw882xx *aw882xx_malloc_init(struct i2c_client *i2c) +{ + struct aw882xx *aw882xx = devm_kzalloc(&i2c->dev, sizeof(struct aw882xx), GFP_KERNEL); + + if (aw882xx == NULL) + return NULL; + + aw882xx->aw_pa = devm_kzalloc(&i2c->dev, sizeof(struct aw_device), GFP_KERNEL); + if (aw882xx->aw_pa == NULL) + return NULL; + + aw882xx->dev = &i2c->dev; + aw882xx->i2c = i2c; + aw882xx->codec = NULL; + aw882xx->codec_ops = &aw_componet_codec_ops; + aw882xx->fw_status = AW_DEV_FW_FAILED; + aw882xx->fw_retry_cnt = 0; + aw882xx->dbg_en_prof = true; + aw882xx->allow_pw = true; + aw882xx->work_queue = NULL; + + mutex_init(&aw882xx->lock); + + return aw882xx; +} + +static int aw882xx_gpio_request(struct aw882xx *aw882xx) +{ + int ret = 0; + + if (gpio_is_valid(aw882xx->reset_gpio)) { + ret = devm_gpio_request_one(aw882xx->dev, aw882xx->reset_gpio, + GPIOF_OUT_INIT_LOW, "aw882xx_rst"); + if (ret) { + aw_dev_err(aw882xx->dev, "rst request failed"); + return ret; + } + } + + if (gpio_is_valid(aw882xx->irq_gpio)) { + ret = devm_gpio_request_one(aw882xx->dev, aw882xx->irq_gpio, + GPIOF_DIR_IN, "aw882xx_int"); + if (ret) { + aw_dev_err(aw882xx->dev, "int request failed"); + return ret; + } + } + + return 0; +} + +static void aw882xx_parse_rename_flag_dt(struct aw882xx *aw882xx) +{ + int ret; + uint32_t rename_enable = 0; + struct device_node *np = aw882xx->dev->of_node; + + ret = of_property_read_u32(np, "rename-flag", &rename_enable); + if (ret) + aw_dev_info(aw882xx->dev, "read rename flag failed, default rename off!"); + else + aw_dev_info(aw882xx->dev, "rename-flag = %d", rename_enable); + + + aw882xx->rename_flag = rename_enable; + +} + +static void aw882xx_parse_sync_load_dt(struct aw882xx *aw882xx) +{ + int ret = -1; + int32_t sync_load = 0; + struct device_node *np = aw882xx->dev->of_node; + + ret = of_property_read_u32(np, "sync-load", &sync_load); + if (ret < 0) { + aw_dev_info(aw882xx->dev, + "read sync load failed,default async loading fw"); + sync_load = false; + } else { + aw_dev_info(aw882xx->dev, + "sync load is %d", sync_load); + } + + aw882xx->sync_load = sync_load; +} + +static int aw882xx_parse_dt(struct device *dev, struct aw882xx *aw882xx, + struct device_node *np) +{ + int ret; + int32_t dc_enable = 0; + int32_t sync_enable = 0; + + /*gpio dts parser*/ + ret = aw882xx_parse_gpio_dt(aw882xx, np); + if (ret) + return ret; + + ret = of_property_read_u32(np, "dc-flag", &dc_enable); + if (ret) { + dc_enable = false; + aw_dev_info(aw882xx->dev, "close dc protect!"); + } else { + aw_dev_info(aw882xx->dev, "dc-flag = %d", dc_enable); + } + + aw882xx->dc_flag = dc_enable; + + + ret = of_property_read_u32(np, "sync-flag", &sync_enable); + if (ret < 0) { + aw_dev_info(aw882xx->dev, + "read sync flag failed,default phase sync off"); + sync_enable = false; + } else { + aw_dev_info(aw882xx->dev, + "sync flag is %d", sync_enable); + } + + aw882xx->phase_sync = sync_enable; + + aw882xx_parse_rename_flag_dt(aw882xx); + aw882xx_parse_sync_load_dt(aw882xx); + + return 0; +} + +int aw882xx_hw_reset(struct aw882xx *aw882xx) +{ + aw_dev_info(aw882xx->dev, "enter"); + + if (gpio_is_valid(aw882xx->reset_gpio)) { + gpio_set_value_cansleep(aw882xx->reset_gpio, 0); + mdelay(1); + gpio_set_value_cansleep(aw882xx->reset_gpio, 1); + mdelay(2); + } else { + aw_dev_info(aw882xx->dev, "has no reset gpio"); + } + return 0; +} + +static int aw882xx_read_chipid(struct aw882xx *aw882xx) +{ + int ret = -1; + unsigned int cnt = 0; + unsigned int reg_value = 0; + + while (cnt < AW_READ_CHIPID_RETRIES) { + ret = aw882xx_i2c_read(aw882xx, AW882XX_CHIP_ID_REG, ®_value); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "failed to read REG_ID: %d", ret); + return -EIO; + } + switch (reg_value) { + case PID_1852_ID: { + aw_dev_info(aw882xx->dev, "aw882xx 1852 detected"); + aw882xx->aw_pa->chip_id = reg_value; + return 0; + } + case PID_2013_ID: { + aw_dev_info(aw882xx->dev, "aw882xx 2013 detected"); + aw882xx->aw_pa->chip_id = reg_value; + return 0; + } + case PID_2032_ID: { + aw_dev_info(aw882xx->dev, "aw882xx 2032 detected"); + aw882xx->aw_pa->chip_id = reg_value; + return 0; + } + case PID_2055_ID: { + aw_dev_info(aw882xx->dev, "aw882xx 2055 detected"); + aw882xx->aw_pa->chip_id = reg_value; + return 0; + } + case PID_2071_ID: { + aw_dev_info(aw882xx->dev, "aw882xx 2071 detected"); + aw882xx->aw_pa->chip_id = reg_value; + return 0; + } + case PID_2113_ID: { + aw_dev_info(aw882xx->dev, "aw882xx 2113 detected"); + aw882xx->aw_pa->chip_id = reg_value; + return 0; + } + case PID_2308_ID: { + aw_dev_info(aw882xx->dev, "aw882xx 2308 detected"); + aw882xx->aw_pa->chip_id = reg_value; + return 0; + } + default: + aw_dev_info(aw882xx->dev, "unsupported device revision (0x%x)", + reg_value); + break; + } + cnt++; + + msleep(AW_READ_CHIPID_RETRY_DELAY); + } + + return -EINVAL; +} + +static irqreturn_t aw882xx_irq(int irq, void *data) +{ + struct aw882xx *aw882xx = (struct aw882xx *)data; + + if (!aw882xx) { + aw_pr_err("pointer is NULL"); + return -EINVAL; + } + aw_dev_info(aw882xx->dev, "enter"); + + /* mask all irq */ + aw882xx_dev_set_intmask(aw882xx->aw_pa, false); + + /* upload workqueue */ + if (aw882xx->work_queue) + queue_delayed_work(aw882xx->work_queue, &aw882xx->interrupt_work, 0); + + return IRQ_HANDLED; +} + +static int aw882xx_interrupt_init(struct aw882xx *aw882xx) +{ + int ret; + int irq_flags; + + if (gpio_is_valid(aw882xx->irq_gpio)) { + irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; + ret = devm_request_threaded_irq(aw882xx->dev, + gpio_to_irq(aw882xx->irq_gpio), + NULL, aw882xx_irq, irq_flags, + "aw882xx", aw882xx); + if (ret != 0) { + aw_dev_err(aw882xx->dev, "Failed to request IRQ %d: %d", + gpio_to_irq(aw882xx->irq_gpio), ret); + return ret; + } + } else { + aw_dev_info(aw882xx->dev, "gpio invalid"); + /* disable interrupt */ + } + + return 0; +} + +static ssize_t reg_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + unsigned int databuf[2] = {0}; + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) + aw882xx_i2c_write(aw882xx, databuf[0], databuf[1]); + + return count; +} + +static ssize_t reg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + ssize_t len = 0; + unsigned char i = 0; + unsigned int reg_val = 0; + int reg_num = aw882xx->aw_pa->ops.aw_get_reg_num(); + + for (i = 0; i < reg_num; i++) { + if (aw882xx->aw_pa->ops.aw_check_rd_access(i)) { + aw882xx_i2c_read(aw882xx, i, ®_val); + len += snprintf(buf+len, PAGE_SIZE-len, + "reg:0x%02x=0x%04x\n", i, reg_val); + } + } + + return len; +} + +static ssize_t rw_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + + unsigned int databuf[2] = {0}; + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + aw882xx->rw_reg_addr = (unsigned char)databuf[0]; + if (aw882xx->aw_pa->ops.aw_check_rd_access(databuf[0])) + aw882xx_i2c_write(aw882xx, databuf[0], databuf[1]); + } else if (kstrtouint(buf, 16, &databuf[0]) == 0) { + aw882xx->rw_reg_addr = (unsigned char)databuf[0]; + } + + return count; +} + +static ssize_t rw_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + ssize_t len = 0; + unsigned int reg_val = 0; + + if (aw882xx->aw_pa->ops.aw_check_rd_access(aw882xx->rw_reg_addr)) { + aw882xx_i2c_read(aw882xx, aw882xx->rw_reg_addr, ®_val); + len += snprintf(buf + len, PAGE_SIZE - len, + "reg:0x%02x=0x%04x\n", aw882xx->rw_reg_addr, reg_val); + } + return len; +} + +static int aw882xx_awrw_write(struct aw882xx *aw882xx, const char *buf, size_t count) +{ + int i, ret; + char *data_buf = NULL; + int str_len, data_len, temp_data; + char *reg_data = NULL; + struct aw882xx_i2c_packet *packet = &aw882xx->i2c_packet; + + aw_dev_info(aw882xx->dev, "write:reg_addr[0x%02x], reg_num[%d]", + packet->reg_addr, packet->reg_num); + + data_len = AWRW_DATA_BYTES * packet->reg_num; + + str_len = count - AWRW_HDR_LEN - 1; + + if ((data_len * 5 - 1) > str_len) { + aw_dev_err(aw882xx->dev, "data_str_len [%d], requeset len [%d]", + str_len, (data_len * 5 - 1)); + return -EINVAL; + } + + data_buf = kmalloc(data_len + 1, GFP_KERNEL); + if (data_buf == NULL) + return -ENOMEM; + + + data_buf[0] = packet->reg_addr; + reg_data = data_buf + 1; + + aw_dev_dbg(aw882xx->dev, "reg_addr: 0x%02x", data_buf[0]); + + for (i = 0; i < data_len; i++) { + if (sscanf(buf + AWRW_HDR_LEN + 1 + i * 5, "0x%02x", &temp_data) == 1) { + reg_data[i] = temp_data; + aw_dev_dbg(aw882xx->dev, "[%d] : 0x%02x", i, reg_data[i]); + } else { + return -EINVAL; + } + } + + ret = i2c_master_send(aw882xx->i2c, data_buf, data_len + 1); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "write failed"); + kfree(data_buf); + data_buf = NULL; + return -EFAULT; + } + + kfree(data_buf); + data_buf = NULL; + + aw_dev_info(aw882xx->dev, "write success"); + return 0; +} + +static int aw882xx_awrw_data_check(struct aw882xx *aw882xx, int *data) +{ + int reg_num_max = aw882xx->aw_pa->ops.aw_get_reg_num(); + + if ((data[AWRW_HDR_ADDR_BYTES] != AWRW_ADDR_BYTES) || + (data[AWRW_HDR_DATA_BYTES] != AWRW_DATA_BYTES)) { + aw_dev_err(aw882xx->dev, "addr_bytes [%d] or data_bytes [%d] unsupport", + data[AWRW_HDR_ADDR_BYTES], data[AWRW_HDR_DATA_BYTES]); + return -EINVAL; + } + + if (data[AWRW_HDR_REG_ADDR] >= reg_num_max) { + aw_dev_err(aw882xx->dev, "reg_addr[%d] > reg_max[%d]", + data[AWRW_HDR_REG_ADDR], reg_num_max); + return -EINVAL; + } + + return 0; +} + +/* flag addr_bytes data_bytes reg_num reg_addr*/ +static int aw882xx_awrw_parse_buf(struct aw882xx *aw882xx, + const char *buf, size_t count) +{ + int ret; + int data[AWRW_HDR_MAX] = {0}; + struct aw882xx_i2c_packet *packet = &aw882xx->i2c_packet; + + if (sscanf(buf, "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", + &data[AWRW_HDR_WR_FLAG], + &data[AWRW_HDR_ADDR_BYTES], + &data[AWRW_HDR_DATA_BYTES], + &data[AWRW_HDR_REG_NUM], + &data[AWRW_HDR_REG_ADDR]) == 5) { + ret = aw882xx_awrw_data_check(aw882xx, data); + if (ret < 0) + return ret; + + packet->reg_addr = data[AWRW_HDR_REG_ADDR]; + packet->reg_num = data[AWRW_HDR_REG_NUM]; + + switch (data[AWRW_HDR_WR_FLAG]) { + case AWRW_FLAG_WRITE: + return aw882xx_awrw_write(aw882xx, buf, count); + case AWRW_FLAG_READ: + packet->status = AWRW_I2C_ST_READ; + aw_dev_info(aw882xx->dev, "read_cmd:reg_addr[0x%02x], reg_num[%d]", + packet->reg_addr, packet->reg_num); + return 0; + default: + aw_dev_err(aw882xx->dev, "please check str format, unsupport flag %d", + data[AWRW_HDR_WR_FLAG]); + return -EINVAL; + } + } + + aw_dev_err(aw882xx->dev, "can not parse string"); + + return -EINVAL; +} + +static ssize_t awrw_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + + if (count < AWRW_HDR_LEN) { + aw_dev_err(dev, "data count too smaller, please check write format"); + aw_dev_err(dev, "string %s", buf); + return -EINVAL; + } + + ret = aw882xx_awrw_parse_buf(aw882xx, buf, count); + if (ret) + return -EINVAL; + + return count; +} + +static ssize_t awrw_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret, i; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw882xx_i2c_packet *packet = &aw882xx->i2c_packet; + int data_len, len = 0; + char *reg_data = NULL; + + if (packet->status != AWRW_I2C_ST_READ) { + aw_dev_err(aw882xx->dev, "please write read cmd first"); + return -EINVAL; + } + + data_len = AWRW_DATA_BYTES * packet->reg_num; + reg_data = kmalloc(data_len, GFP_KERNEL); + if (reg_data == NULL) + return -ENOMEM; + + ret = aw882xx_i2c_reads(aw882xx, packet->reg_addr, (char *)reg_data, data_len); + if (ret < 0) { + ret = -EFAULT; + goto exit; + } + + aw_dev_info(aw882xx->dev, "reg_addr 0x%02x, reg_num %d", + packet->reg_addr, packet->reg_num); + + for (i = 0; i < data_len; i++) { + len += snprintf(buf + len, PAGE_SIZE - len, + "0x%02x,", reg_data[i]); + aw_dev_dbg(aw882xx->dev, "0x%02x", reg_data[i]); + } + + ret = len; + +exit: + + kfree(reg_data); + reg_data = NULL; + packet->status = AWRW_I2C_ST_NONE; + return ret; +} + + +static ssize_t drv_ver_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + "driver_ver: %s\n", AW882XX_DRIVER_VERSION); + + return len; +} + +static ssize_t dsp_re_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + ssize_t len = 0; + int cali_re; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + + ret = aw882xx_dev_get_cali_re(aw882xx->aw_pa, &cali_re); + if (ret) { + len += snprintf(buf + len, PAGE_SIZE - len, + "read dsp_re failed!\n"); + return len; + } + + len += snprintf(buf + len, PAGE_SIZE - len, + "%d\n", cali_re); + + return len; +} + +static ssize_t fade_step_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + unsigned int databuf[2] = {0}; + + /*step 0 - 12*/ + if (kstrtouint(buf, 10, &databuf[0]) == 0) { + if (databuf[0] > (aw882xx->aw_pa->volume_desc.mute_volume)) { + aw_dev_info(aw882xx->dev, "step overflow %d Db", databuf[0]); + return count; + } + aw882xx_dev_set_fade_vol_step(aw882xx->aw_pa, databuf[0]); + } + aw_dev_info(aw882xx->dev, "set step %d Done", databuf[0]); + + return count; +} + +static ssize_t fade_step_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + + len += snprintf(buf + len, PAGE_SIZE - len, + "step: %d\n", aw882xx_dev_get_fade_vol_step(aw882xx->aw_pa)); + + return len; +} + +static ssize_t dbg_prof_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + + unsigned int databuf[2] = {0}; + + if (kstrtouint(buf, 10, &databuf[0]) == 0) { + if (databuf[0]) + aw882xx->dbg_en_prof = true; + else + aw882xx->dbg_en_prof = false; + } + aw_dev_info(aw882xx->dev, "en_prof %d Done", databuf[0]); + + return count; +} + +static ssize_t dbg_prof_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + " %d\n", aw882xx->dbg_en_prof); + + return len; +} + +static ssize_t phase_sync_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret = -1; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + unsigned int flag = 0; + + ret = kstrtouint(buf, 10, &flag); + if (ret < 0) + return ret; + + flag = ((flag == false) ? false : true); + + aw_dev_info(aw882xx->dev, "set phase sync flag : [%d]", flag); + + aw882xx->phase_sync = flag; + + return count; +} + +static ssize_t phase_sync_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + "sync flag : %d\n", aw882xx->phase_sync); + + return len; +} + +static ssize_t print_dbg_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + + ret = kstrtouint(buf, 0, &g_print_dbg); + if (ret < 0) + return ret; + + g_print_dbg = ((g_print_dbg == false) ? false : true); + + aw_dev_info(aw882xx->dev, "set g_print_dbg : [%d]", g_print_dbg); + + return count; +} + +static ssize_t print_dbg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + "g_print_dbg : %d\n", g_print_dbg); + + return len; +} + +static ssize_t algo_ver_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + ssize_t len = 0; + char algo_ver_buf[ALGO_VERSION_MAX] = { 0 }; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + + ret = aw882xx_get_algo_version(aw882xx->aw_pa, algo_ver_buf); + if (ret < 0) { + len += snprintf(buf + len, PAGE_SIZE - len, + "read algo version failed!\n"); + return len; + } + len += snprintf(buf + len, PAGE_SIZE - len, "%s\n", algo_ver_buf); + + return len; +} + +static DEVICE_ATTR_RW(reg); +static DEVICE_ATTR_RW(rw); +static DEVICE_ATTR_RW(awrw); +static DEVICE_ATTR_RO(drv_ver); +static DEVICE_ATTR_RO(dsp_re); +static DEVICE_ATTR_RW(fade_step); +static DEVICE_ATTR_RW(dbg_prof); +static DEVICE_ATTR_RW(phase_sync); +static DEVICE_ATTR_RW(print_dbg); +static DEVICE_ATTR_RO(algo_ver); + + +static struct attribute *aw882xx_attributes[] = { + &dev_attr_reg.attr, + &dev_attr_rw.attr, + &dev_attr_awrw.attr, + &dev_attr_drv_ver.attr, + &dev_attr_fade_step.attr, + &dev_attr_dbg_prof.attr, + &dev_attr_dsp_re.attr, + &dev_attr_phase_sync.attr, + &dev_attr_print_dbg.attr, + &dev_attr_algo_ver.attr, + NULL +}; + +static struct attribute_group aw882xx_attribute_group = { + .attrs = aw882xx_attributes, +}; + +static int aw882xx_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + int ret; + struct aw882xx *aw882xx = NULL; + struct device_node *np = i2c->dev.of_node; + + aw_pr_info("enter addr=0x%x", i2c->addr); + + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) { + aw_dev_err(&i2c->dev, "check_functionality failed"); + return -EIO; + } + + /*dev free all auto free*/ + aw882xx = aw882xx_malloc_init(i2c); + if (aw882xx == NULL) { + aw_dev_err(&i2c->dev, "malloc aw882xx failed"); + return -ENOMEM; + } + + i2c_set_clientdata(i2c, aw882xx); + + ret = aw882xx_parse_dt(&i2c->dev, aw882xx, np); + if (ret) { + aw_dev_err(&i2c->dev, "failed to parse device tree node"); + return ret; + } + + /*get gpio resource*/ + ret = aw882xx_gpio_request(aw882xx); + if (ret) + return ret; + + /* hardware reset */ + aw882xx_hw_reset(aw882xx); + + /* aw882xx chip id */ + ret = aw882xx_read_chipid(aw882xx); + if (ret < 0) { + aw_dev_err(&i2c->dev, "aw882xx_read_chipid failed ret=%d", ret); + return ret; + } + + /*aw pa init*/ + ret = aw882xx_init(aw882xx); + if (ret) + return ret; + + /*aw882xx irq*/ + aw882xx_interrupt_init(aw882xx); + + /*codec register*/ + ret = aw_componet_codec_register(aw882xx); + if (ret) { + aw_dev_err(&i2c->dev, "codec register failde"); + return ret; + } + + /*create attr*/ + ret = sysfs_create_group(&i2c->dev.kobj, &aw882xx_attribute_group); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "error creating sysfs attr files"); + goto err_sysfs; + } + + /*set aw882xx to dev private*/ + dev_set_drvdata(&i2c->dev, aw882xx); + + /*i2c packet init*/ + aw882xx->i2c_packet.status = AWRW_I2C_ST_NONE; + aw882xx->i2c_packet.reg_num = 0; + aw882xx->i2c_packet.reg_addr = 0xff; + aw882xx->i2c_packet.reg_data = NULL; + + /*add device to total list*/ + mutex_lock(&g_aw882xx_lock); + g_aw882xx_dev_cnt++; + mutex_unlock(&g_aw882xx_lock); + aw_dev_info(&i2c->dev, "dev_cnt %d", g_aw882xx_dev_cnt); + return ret; +err_sysfs: + aw_componet_codec_ops.unregister_codec(&i2c->dev); + + return ret; +} + +#ifdef AW_KERNEL_VER_OVER_6_1_0 +static void aw882xx_i2c_remove(struct i2c_client *i2c) +#else +static int aw882xx_i2c_remove(struct i2c_client *i2c) +#endif +{ + struct aw882xx *aw882xx = i2c_get_clientdata(i2c); + + aw_dev_info(aw882xx->dev, "enter"); + + /*rm irq*/ + if (gpio_to_irq(aw882xx->irq_gpio)) + devm_free_irq(&i2c->dev, + gpio_to_irq(aw882xx->irq_gpio), + aw882xx); + + /*rm attr node*/ + sysfs_remove_group(&i2c->dev.kobj, &aw882xx_attribute_group); + + /*free device resource */ + aw882xx_device_remove(aw882xx->aw_pa); + + /*unregister codec*/ + aw882xx->codec_ops->unregister_codec(&i2c->dev); + + /*remove device to total list*/ + mutex_lock(&g_aw882xx_lock); + g_aw882xx_dev_cnt--; + if (g_aw882xx_dev_cnt == 0) { + if (g_awinic_cfg) { + vfree(g_awinic_cfg); + g_awinic_cfg = NULL; + } + } + mutex_unlock(&g_aw882xx_lock); + +#ifdef AW_KERNEL_VER_OVER_6_1_0 +#else + return 0; +#endif +} + +static void aw882xx_i2c_shutdown(struct i2c_client *i2c) +{ + struct aw882xx *aw882xx = i2c_get_clientdata(i2c); + + aw_dev_info(aw882xx->dev, "enter"); + mutex_lock(&aw882xx->lock); + aw882xx_device_stop(aw882xx->aw_pa); + mutex_unlock(&aw882xx->lock); +} + +static const struct i2c_device_id aw882xx_i2c_id[] = { + { AW882XX_I2C_NAME, 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, aw882xx_i2c_id); + +static const struct of_device_id aw882xx_dt_match[] = { + { .compatible = "awinic,aw882xx_smartpa" }, + { }, +}; + +static struct i2c_driver aw882xx_i2c_driver = { + .driver = { + .name = AW882XX_I2C_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(aw882xx_dt_match), + }, + .probe = aw882xx_i2c_probe, + .remove = aw882xx_i2c_remove, + .shutdown = aw882xx_i2c_shutdown, + .id_table = aw882xx_i2c_id, +}; + + +static int __init aw882xx_i2c_init(void) +{ + int ret = -1; + + aw_pr_info("aw882xx driver version %s", AW882XX_DRIVER_VERSION); + + ret = i2c_add_driver(&aw882xx_i2c_driver); + if (ret) + aw_pr_err("fail to add aw882xx device into i2c"); + + return ret; +} +module_init(aw882xx_i2c_init); + + +static void __exit aw882xx_i2c_exit(void) +{ + i2c_del_driver(&aw882xx_i2c_driver); +} +module_exit(aw882xx_i2c_exit); + + +MODULE_DESCRIPTION("ASoC AW882XX Smart PA Driver"); +MODULE_LICENSE("GPL v2"); + + + diff --git a/sound/soc/codecs/aw882xx/aw882xx.h b/sound/soc/codecs/aw882xx/aw882xx.h new file mode 100644 index 000000000000..8316eb113748 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx.h @@ -0,0 +1,223 @@ +/* SPDX-License-Identifier: GPL-2.0 + * aw882xx.h + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef _AW882XX_H_ +#define _AW882XX_H_ +#include +#include +#include "aw882xx_device.h" + +/* + * i2c transaction on Linux limited to 64k + * (See Linux kernel documentation: Documentation/i2c/writing-clients) + */ +#define AW882XX_CHIP_ID_REG (0x00) +#define MAX_I2C_BUFFER_SIZE 65536 +#define AW882XX_I2C_READ_MSG_NUM 2 +#define AW882XX_DC_DELAY_TIME (1000) +#define AW882XX_LOAD_FW_DELAY_TIME (0) +#define AW_START_RETRIES (5) + +#define AW_PID_2055_VERSION_DIFF_REG (0x23) + +#define AW_I2C_RETRIES 5 /* 5 times */ +#define AW_I2C_RETRY_DELAY 5 /* 5 ms */ + +#define ACF_BIN_NAME "aw882xx_acf.bin" + +#define AW882XX_RATES SNDRV_PCM_RATE_8000_48000 +#define AW882XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) +/*#define AW882XX_IRQ_START_FLAG*/ +enum { + AW882XX_STREAM_CLOSE = 0, + AW882XX_STREAM_OPEN, +}; + +enum aw882xx_chipid { + PID_1852_ID = 0x1852, + PID_2013_ID = 0x2013, + PID_2032_ID = 0x2032, + PID_2055_ID = 0x2055, + PID_2055A_ID = 0x2055A, + PID_2071_ID = 0x2071, + PID_2113_ID = 0x2113, + PID_2308_ID = 0x2308, +}; + +#define AW882XX_SOFT_RESET_REG (0x00) +#define AW882XX_SOFT_RESET_VALUE (0x55aa) + +enum aw882xx_int_type { + INT_TYPE_NONE = 0, + INT_TYPE_UVLO = 0x1, + INT_TYPE_BSTOC = 0x2, + INT_TYPE_OCDI = 0x4, + INT_TYPE_OTHI = 0x8, +}; + +#if KERNEL_VERSION(4, 19, 1) <= LINUX_VERSION_CODE +#define AW_KERNEL_VER_OVER_4_19_1 +#endif + + +#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE +#define AW_KERNEL_VER_OVER_5_4_0 +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); +#endif + +#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE +#define AW_KERNEL_VER_OVER_5_10_0 +#endif +#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE +#define AW_KERNEL_VER_OVER_6_1_0 +#endif + + +#ifdef AW_KERNEL_VER_OVER_4_19_1 +typedef struct snd_soc_component aw_snd_soc_codec_t; +typedef const struct snd_soc_component_driver aw_snd_soc_codec_driver_t; +#else +typedef struct snd_soc_codec aw_snd_soc_codec_t; +typedef const struct snd_soc_codec_driver aw_snd_soc_codec_driver_t; +#endif + +struct aw_componet_codec_ops { + aw_snd_soc_codec_t *(*kcontrol_codec)(struct snd_kcontrol *kcontrol); + void *(*codec_get_drvdata)(aw_snd_soc_codec_t *codec); + int (*add_codec_controls)(aw_snd_soc_codec_t *codec, + const struct snd_kcontrol_new *controls, unsigned int num_controls); + void (*unregister_codec)(struct device *dev); + int (*register_codec)(struct device *dev, + const aw_snd_soc_codec_driver_t *codec_drv, + struct snd_soc_dai_driver *dai_drv, + int num_dai); +}; + +enum { + AWRW_I2C_ST_NONE = 0, + AWRW_I2C_ST_READ, + AWRW_I2C_ST_WRITE, +}; + +#define AWRW_ADDR_BYTES (1) +#define AWRW_DATA_BYTES (2) +#define AWRW_HDR_LEN (24) + + +enum { + KCTL_TYPE_PROFILE = 0, + KCTL_TYPE_SWITCH, + KCTL_TYPE_MONITOR, + KCTL_TYPE_VOLUME, + KCTL_TYPE_MON_HAL, + AW_KCTL_NUM, + +}; + +enum { + AWRW_FLAG_WRITE = 0, + AWRW_FLAG_READ, +}; + +enum { + AW_BSTCFG_DISABLE = 0, + AW_BSTCFG_ENABLE, +}; + +enum { + AW_FRCSET_DISABLE = 0, + AW_FRCSET_ENABLE, +}; + +enum { + AW_BOP_DISABLE = 0, + AW_BOP_ENABLE, +}; + +enum { + AW_RENAME_DISABLE = 0, + AW_RENAME_ENABLE, +}; + +enum { + AWRW_HDR_WR_FLAG = 0, + AWRW_HDR_ADDR_BYTES, + AWRW_HDR_DATA_BYTES, + AWRW_HDR_REG_NUM, + AWRW_HDR_REG_ADDR, + AWRW_HDR_MAX, +}; + +struct aw882xx_i2c_packet { + char status; + unsigned int reg_num; + unsigned int reg_addr; + char *reg_data; +}; + +/******************************************** + * struct aw882xx + *******************************************/ +struct aw882xx { + int sysclk; + int rate; + int pstream; + int cstream; + + unsigned char phase_sync; /* phase sync */ + unsigned char dc_flag; + unsigned char dbg_en_prof; /* debug enable/disable profile function */ + unsigned char allow_pw; /* allow power */ + uint32_t rename_flag; + unsigned char sync_load; /* sync load fw */ + + int reset_gpio; + int irq_gpio; + unsigned char fw_status; + unsigned char fw_retry_cnt; + unsigned char rw_reg_addr; /* rw attr node store read addr */ + + aw_snd_soc_codec_t *codec; + struct aw_componet_codec_ops *codec_ops; + + struct i2c_client *i2c; + struct device *dev; + struct aw882xx_i2c_packet i2c_packet; + struct aw_device *aw_pa; + + struct workqueue_struct *work_queue; + struct delayed_work start_work; + struct delayed_work interrupt_work; + struct delayed_work dc_work; + struct delayed_work fw_work; + + struct mutex lock; +}; + +void aw882xx_kcontorl_set(struct aw882xx *aw882xx); +int aw882xx_get_version(char *buf, int size); +int aw882xx_get_dev_num(void); +int aw882xx_i2c_write(struct aw882xx *aw882xx, + unsigned char reg_addr, unsigned int reg_data); +int aw882xx_i2c_read(struct aw882xx *aw882xx, + unsigned char reg_addr, unsigned int *reg_data); +int aw882xx_i2c_write_bits(struct aw882xx *aw882xx, + unsigned char reg_addr, unsigned int mask, unsigned int reg_data); +int aw882xx_init(struct aw882xx *aw882xx); +int aw882xx_hw_reset(struct aw882xx *aw882xx); + + +#endif + diff --git a/sound/soc/codecs/aw882xx/aw882xx_bin_parse.c b/sound/soc/codecs/aw882xx/aw882xx_bin_parse.c new file mode 100644 index 000000000000..e423a340abb5 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_bin_parse.c @@ -0,0 +1,1421 @@ +// SPDX-License-Identifier: GPL-2.0 +/* aw882xx_bin_parse.c + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "aw882xx_bin_parse.h" +#include "aw882xx_device.h" +#include "aw882xx_data_type.h" +#include "aw882xx_log.h" + + +#define AWINIC_CODE_VERSION "V0.0.7-V1.0.4" /* "code version"-"excel version" */ + +#define DEBUG_LOG_LEVEL +#ifdef DEBUG_LOG_LEVEL +#define DBG(fmt, arg...) \ + pr_debug("AWINIC_BIN %s,line= %d,"fmt, __func__, __LINE__, ##arg) +#define DBG_ERR(fmt, arg...) \ + pr_err("AWINIC_BIN_ERR %s,line= %d,"fmt, __func__, __LINE__, ##arg) +#else +#define DBG(fmt, arg...) do {} while (0) +#define DBG_ERR(fmt, arg...) do {} while (0) +#endif + + +static char *profile_name[AW_PROFILE_MAX] = { + "Music", "Voice", "Voip", "Ringtone", "Ringtone_hs", + "Lowpower", "Bypass", "Mmi", "Fm", "Notification", "Receiver" +}; + +static int aw_parse_bin_header_1_0_0(struct aw_bin *bin); + +/******************************************************** + * + * check sum data + * + ********************************************************/ +static int aw_check_sum(struct aw_bin *bin, int bin_num) +{ + unsigned int i = 0; + unsigned int sum_data = 0; + unsigned int check_sum = 0; + unsigned char *p_check_sum = NULL; + + DBG("enter\n"); + + p_check_sum = &(bin->info.data[(bin->header_info[bin_num].valid_data_addr - + bin->header_info[bin_num].header_len)]); + DBG("aw_bin_parse p_check_sum = %p\n", p_check_sum); + check_sum = GET_32_DATA(*(p_check_sum + 3), + *(p_check_sum + 2), + *(p_check_sum + 1), *(p_check_sum)); + + for (i = 4; i < bin->header_info[bin_num].bin_data_len + + bin->header_info[bin_num].header_len; i++) { + sum_data += *(p_check_sum + i); + } + DBG("aw_bin_parse bin_num=%d, check_sum = 0x%x, sum_data = 0x%x\n", + bin_num, check_sum, sum_data); + if (sum_data != check_sum) { + p_check_sum = NULL; + DBG_ERR("aw_bin_parse check sum or check bin data len error\n"); + DBG_ERR("aw_bin_parse bin_num=%d, check_sum = 0x%x, sum_data = 0x%x\n", bin_num, check_sum, sum_data); + return -EINVAL; + } + p_check_sum = NULL; + + return 0; +} + +static int aw_check_data_version(struct aw_bin *bin, int bin_num) +{ + int i = 0; + + DBG("enter\n"); + + for (i = DATA_VERSION_V1; i < DATA_VERSION_MAX; i++) { + if (bin->header_info[bin_num].bin_data_ver == i) + return 0; + + } + DBG_ERR("aw_bin_parse Unrecognized this bin data version\n"); + return -EINVAL; +} + +static int aw_check_register_num_v1(struct aw_bin *bin, int bin_num) +{ + unsigned int check_register_num = 0; + unsigned int parse_register_num = 0; + char *p_check_sum = NULL; + + DBG("enter\n"); + + p_check_sum = &(bin->info.data[(bin->header_info[bin_num].valid_data_addr)]); + DBG("aw_bin_parse p_check_sum = %p\n", p_check_sum); + parse_register_num = GET_32_DATA(*(p_check_sum + 3), + *(p_check_sum + 2), + *(p_check_sum + 1), *(p_check_sum)); + check_register_num = (bin->header_info[bin_num].bin_data_len - 4) / + (bin->header_info[bin_num].reg_byte_len + + bin->header_info[bin_num].data_byte_len); + DBG("aw_bin_parse bin_num=%d, parse_register_num = 0x%x, check_register_num = 0x%x\n", + bin_num, parse_register_num, check_register_num); + if (parse_register_num != check_register_num) { + p_check_sum = NULL; + DBG_ERR("aw_bin_parse register num is error\n"); + DBG_ERR("aw_bin_parse bin_num=%d, parse_register_num = 0x%x, check_register_num = 0x%x\n", bin_num, parse_register_num, check_register_num); + return -EINVAL; + } + bin->header_info[bin_num].reg_num = parse_register_num; + bin->header_info[bin_num].valid_data_len = + bin->header_info[bin_num].bin_data_len - 4; + p_check_sum = NULL; + bin->header_info[bin_num].valid_data_addr = + bin->header_info[bin_num].valid_data_addr + 4; + return 0; +} + +static int aw_check_dsp_reg_num_v1(struct aw_bin *bin, int bin_num) +{ + unsigned int check_dsp_reg_num = 0; + unsigned int parse_dsp_reg_num = 0; + char *p_check_sum = NULL; + + DBG("enter\n"); + + p_check_sum = &(bin->info.data[(bin->header_info[bin_num].valid_data_addr)]); + DBG("aw_bin_parse p_check_sum = %p\n", p_check_sum); + parse_dsp_reg_num = GET_32_DATA(*(p_check_sum + 7), + *(p_check_sum + 6), + *(p_check_sum + 5), *(p_check_sum + 4)); + bin->header_info[bin_num].reg_data_byte_len = + GET_32_DATA(*(p_check_sum + 11), *(p_check_sum + 10), + *(p_check_sum + 9), *(p_check_sum + 8)); + check_dsp_reg_num = + (bin->header_info[bin_num].bin_data_len - + 12) / bin->header_info[bin_num].reg_data_byte_len; + DBG("aw_bin_parse bin_num=%d, parse_dsp_reg_num = 0x%x, check_dsp_reg_num = 0x%x\n", + bin_num, parse_dsp_reg_num, check_dsp_reg_num); + if (parse_dsp_reg_num != check_dsp_reg_num) { + p_check_sum = NULL; + DBG_ERR("aw_bin_parse dsp reg num is error\n"); + DBG_ERR("aw_bin_parse bin_num=%d, parse_dsp_reg_num = 0x%x, check_dsp_reg_num = 0x%x\n", bin_num, parse_dsp_reg_num, check_dsp_reg_num); + return -EINVAL; + } + bin->header_info[bin_num].download_addr = + GET_32_DATA(*(p_check_sum + 3), *(p_check_sum + 2), + *(p_check_sum + 1), *(p_check_sum)); + bin->header_info[bin_num].reg_num = parse_dsp_reg_num; + bin->header_info[bin_num].valid_data_len = + bin->header_info[bin_num].bin_data_len - 12; + p_check_sum = NULL; + bin->header_info[bin_num].valid_data_addr = + bin->header_info[bin_num].valid_data_addr + 12; + return 0; +} + +static int aw_check_soc_app_num_v1(struct aw_bin *bin, int bin_num) +{ + unsigned int check_soc_app_num = 0; + unsigned int parse_soc_app_num = 0; + char *p_check_sum = NULL; + + DBG("enter\n"); + + p_check_sum = + &(bin->info.data[(bin->header_info[bin_num].valid_data_addr)]); + DBG("aw_bin_parse p_check_sum = %p\n", p_check_sum); + bin->header_info[bin_num].app_version = GET_32_DATA(*(p_check_sum + 3), + *(p_check_sum + 2), + *(p_check_sum + 1), + *(p_check_sum)); + parse_soc_app_num = GET_32_DATA(*(p_check_sum + 11), + *(p_check_sum + 10), + *(p_check_sum + 9), *(p_check_sum + 8)); + check_soc_app_num = bin->header_info[bin_num].bin_data_len - 12; + DBG + ("aw_bin_parse bin_num=%d, parse_soc_app_num = 0x%x, check_soc_app_num = 0x%x\n", + bin_num, parse_soc_app_num, check_soc_app_num); + if (parse_soc_app_num != check_soc_app_num) { + p_check_sum = NULL; + DBG_ERR("aw_bin_parse soc app num is error\n"); + DBG_ERR("aw_bin_parse bin_num=%d, parse_soc_app_num = 0x%x, check_soc_app_num = 0x%x\n", bin_num, parse_soc_app_num, check_soc_app_num); + return -EINVAL; + } + bin->header_info[bin_num].reg_num = parse_soc_app_num; + bin->header_info[bin_num].download_addr = + GET_32_DATA(*(p_check_sum + 7), *(p_check_sum + 6), + *(p_check_sum + 5), *(p_check_sum + 4)); + bin->header_info[bin_num].valid_data_len = + bin->header_info[bin_num].bin_data_len - 12; + p_check_sum = NULL; + bin->header_info[bin_num].valid_data_addr = + bin->header_info[bin_num].valid_data_addr + 12; + return 0; +} + +/************************ + *** + ***bin header 1_0_0 + *** + ************************/ +static void aw_get_single_bin_header_1_0_0(struct aw_bin *bin) +{ + int i = 0; + + DBG("enter\n"); + bin->header_info[bin->all_bin_parse_num].header_len = 60; + bin->header_info[bin->all_bin_parse_num].check_sum = + GET_32_DATA(*(bin->p_addr + 3), *(bin->p_addr + 2), + *(bin->p_addr + 1), *(bin->p_addr)); + bin->header_info[bin->all_bin_parse_num].header_ver = + GET_32_DATA(*(bin->p_addr + 7), *(bin->p_addr + 6), + *(bin->p_addr + 5), *(bin->p_addr + 4)); + bin->header_info[bin->all_bin_parse_num].bin_data_type = + GET_32_DATA(*(bin->p_addr + 11), *(bin->p_addr + 10), + *(bin->p_addr + 9), *(bin->p_addr + 8)); + bin->header_info[bin->all_bin_parse_num].bin_data_ver = + GET_32_DATA(*(bin->p_addr + 15), *(bin->p_addr + 14), + *(bin->p_addr + 13), *(bin->p_addr + 12)); + bin->header_info[bin->all_bin_parse_num].bin_data_len = + GET_32_DATA(*(bin->p_addr + 19), *(bin->p_addr + 18), + *(bin->p_addr + 17), *(bin->p_addr + 16)); + bin->header_info[bin->all_bin_parse_num].ui_ver = + GET_32_DATA(*(bin->p_addr + 23), *(bin->p_addr + 22), + *(bin->p_addr + 21), *(bin->p_addr + 20)); + bin->header_info[bin->all_bin_parse_num].reg_byte_len = + GET_32_DATA(*(bin->p_addr + 35), *(bin->p_addr + 34), + *(bin->p_addr + 33), *(bin->p_addr + 32)); + bin->header_info[bin->all_bin_parse_num].data_byte_len = + GET_32_DATA(*(bin->p_addr + 39), *(bin->p_addr + 38), + *(bin->p_addr + 37), *(bin->p_addr + 36)); + bin->header_info[bin->all_bin_parse_num].device_addr = + GET_32_DATA(*(bin->p_addr + 43), *(bin->p_addr + 42), + *(bin->p_addr + 41), *(bin->p_addr + 40)); + for (i = 0; i < 8; i++) { + bin->header_info[bin->all_bin_parse_num].chip_type[i] = + *(bin->p_addr + 24 + i); + } + bin->header_info[bin->all_bin_parse_num].reg_num = 0x00000000; + bin->header_info[bin->all_bin_parse_num].reg_data_byte_len = 0x00000000; + bin->header_info[bin->all_bin_parse_num].download_addr = 0x00000000; + bin->header_info[bin->all_bin_parse_num].app_version = 0x00000000; + bin->header_info[bin->all_bin_parse_num].valid_data_len = 0x00000000; + bin->all_bin_parse_num += 1; +} + +static int aw_parse_each_of_multi_bins_1_0_0(unsigned int bin_num, int bin_serial_num, + struct aw_bin *bin) +{ + int ret = 0; + unsigned int bin_start_addr = 0; + unsigned int valid_data_len = 0; + + DBG("aw_bin_parse enter multi bin branch -- %s\n", __func__); + if (!bin_serial_num) { + bin_start_addr = GET_32_DATA(*(bin->p_addr + 67), + *(bin->p_addr + 66), + *(bin->p_addr + 65), + *(bin->p_addr + 64)); + bin->p_addr += (60 + bin_start_addr); + bin->header_info[bin->all_bin_parse_num].valid_data_addr = + bin->header_info[bin->all_bin_parse_num - + 1].valid_data_addr + 4 + 8 * bin_num + 60; + } else { + valid_data_len = + bin->header_info[bin->all_bin_parse_num - 1].bin_data_len; + bin->p_addr += (60 + valid_data_len); + bin->header_info[bin->all_bin_parse_num].valid_data_addr = + bin->header_info[bin->all_bin_parse_num - 1].valid_data_addr + + bin->header_info[bin->all_bin_parse_num - 1].bin_data_len + 60; + } + + ret = aw_parse_bin_header_1_0_0(bin); + return ret; +} + +/* Get the number of bins in multi bins, and set a for loop, loop processing each bin data */ +static int aw_get_multi_bin_header_1_0_0(struct aw_bin *bin) +{ + int i = 0; + int ret = 0; + unsigned int bin_num = 0; + + DBG("aw_bin_parse enter multi bin branch -- %s\n", __func__); + bin_num = GET_32_DATA(*(bin->p_addr + 63), + *(bin->p_addr + 62), + *(bin->p_addr + 61), *(bin->p_addr + 60)); + if (bin->multi_bin_parse_num == 1) + bin->header_info[bin->all_bin_parse_num].valid_data_addr = 60; + + aw_get_single_bin_header_1_0_0(bin); + + for (i = 0; i < bin_num; i++) { + DBG("aw_bin_parse enter multi bin for is %d\n", i); + ret = aw_parse_each_of_multi_bins_1_0_0(bin_num, i, bin); + if (ret < 0) + return ret; + + } + return 0; +} + +/******************************************************** + * + * If the bin framework header version is 1.0.0, + determine the data type of bin, and then perform different processing + according to the data type + If it is a single bin data type, write the data directly into the structure array + If it is a multi-bin data type, first obtain the number of bins, + and then recursively call the bin frame header processing function + according to the bin number to process the frame header information of each bin separately + * + ********************************************************/ +static int aw_parse_bin_header_1_0_0(struct aw_bin *bin) +{ + int ret = 0; + unsigned int bin_data_type; + + DBG("enter\n"); + bin_data_type = GET_32_DATA(*(bin->p_addr + 11), + *(bin->p_addr + 10), + *(bin->p_addr + 9), *(bin->p_addr + 8)); + DBG("aw_bin_parse bin_data_type 0x%x\n", bin_data_type); + switch (bin_data_type) { + case DATA_TYPE_REGISTER: + case DATA_TYPE_DSP_REG: + case DATA_TYPE_SOC_APP: + /* Divided into two processing methods, + * one is single bin processing, + * and the other is single bin processing in multi bin + */ + DBG("aw_bin_parse enter single bin branch\n"); + bin->single_bin_parse_num += 1; + DBG("%s bin->single_bin_parse_num is %d\n", __func__, + bin->single_bin_parse_num); + if (!bin->multi_bin_parse_num) + bin->header_info[bin->all_bin_parse_num].valid_data_addr = 60; + + aw_get_single_bin_header_1_0_0(bin); + break; + case DATA_TYPE_MULTI_BINS: + /* Get the number of times to enter multi bins */ + DBG("aw_bin_parse enter multi bin branch\n"); + bin->multi_bin_parse_num += 1; + DBG("%s bin->multi_bin_parse_num is %d\n", __func__, + bin->multi_bin_parse_num); + ret = aw_get_multi_bin_header_1_0_0(bin); + if (ret < 0) + return ret; + + break; + default: + DBG_ERR("aw_bin_parse Unrecognized this bin data type\n"); + return -EINVAL; + } + return 0; +} + +/* get the bin's header version */ +static int aw_check_bin_header_version(struct aw_bin *bin) +{ + int ret = 0; + unsigned int header_version = 0; + + header_version = GET_32_DATA(*(bin->p_addr + 7), + *(bin->p_addr + 6), + *(bin->p_addr + 5), *(bin->p_addr + 4)); + + DBG("aw_bin_parse header_version 0x%x\n", header_version); + + /* Write data to the corresponding structure array + * according to different formats of the bin frame header version + */ + switch (header_version) { + case HEADER_VERSION_1_0_0: + ret = aw_parse_bin_header_1_0_0(bin); + return ret; + default: + DBG_ERR("aw_bin_parse Unrecognized this bin header version\n"); + return -EINVAL; + } +} + +static int aw_parsing_bin_file(struct aw_bin *bin) +{ + int i = 0; + int ret = 0; + + DBG("aw_bin_parse code version:%s\n", AWINIC_CODE_VERSION); + if (!bin) { + DBG_ERR("aw_bin_parse bin is NULL\n"); + return -EINVAL; + } + bin->p_addr = bin->info.data; + bin->all_bin_parse_num = 0; + bin->multi_bin_parse_num = 0; + bin->single_bin_parse_num = 0; + + /* filling bins header info */ + ret = aw_check_bin_header_version(bin); + if (ret < 0) { + DBG_ERR("aw_bin_parse check bin header version error\n"); + return ret; + } + bin->p_addr = NULL; + + /* check bin header info */ + for (i = 0; i < bin->all_bin_parse_num; i++) { + /* check sum */ + ret = aw_check_sum(bin, i); + if (ret < 0) { + DBG_ERR("aw_bin_parse check sum data error\n"); + return ret; + } + /* check bin data version */ + ret = aw_check_data_version(bin, i); + if (ret < 0) { + DBG_ERR("aw_bin_parse check data version error\n"); + return ret; + } + /* check valid data */ + if (bin->header_info[i].bin_data_ver == DATA_VERSION_V1) { + /* check register num */ + if (bin->header_info[i].bin_data_type == + DATA_TYPE_REGISTER) { + ret = aw_check_register_num_v1(bin, i); + if (ret < 0) { + DBG_ERR("aw_bin_parse check register num error\n"); + return ret; + } + /* check dsp reg num */ + } else if (bin->header_info[i].bin_data_type == + DATA_TYPE_DSP_REG) { + ret = aw_check_dsp_reg_num_v1(bin, i); + if (ret < 0) { + DBG_ERR("aw_bin_parse check dsp reg num error\n"); + return ret; + } + /* check soc app num */ + } else if (bin->header_info[i].bin_data_type == + DATA_TYPE_SOC_APP) { + ret = aw_check_soc_app_num_v1(bin, i); + if (ret < 0) { + DBG_ERR + ("aw_bin_parse check soc app num error\n"); + return ret; + } + } else { + bin->header_info[i].valid_data_len = + bin->header_info[i].bin_data_len; + } + } + } + DBG("aw_bin_parse parsing success\n"); + + return 0; +} + +/*********************************awinic audio acf*************************************/ +static uint8_t aw_dev_parse_crc8_check(unsigned char *data, uint32_t data_size) +{ + uint8_t crc_value = 0x00; + uint8_t pdatabuf = 0; + int i; + + while (data_size--) { + pdatabuf = *data++; + for (i = 0; i < 8; i++) { + /*if the lowest bit is 1*/ + if ((crc_value ^ (pdatabuf)) & 0x01) { + /*Xor multinomial*/ + crc_value ^= 0x18; + crc_value >>= 1; + crc_value |= 0x80; + } else { + crc_value >>= 1; + } + pdatabuf >>= 1; + } + } + return crc_value; +} + +static int aw_dev_parse_check_acf_by_hdr(struct aw_container *aw_cfg) +{ + struct aw_cfg_hdr *cfg_hdr = NULL; + struct aw_cfg_dde *cfg_dde = NULL; + unsigned int end_data_offset = 0; + unsigned int act_data = 0; + unsigned int hdr_ddt_len = 0; + uint8_t act_crc8 = 0; + int i; + + cfg_hdr = (struct aw_cfg_hdr *)aw_cfg->data; + + /*check file type id is awinic acf file*/ + if (cfg_hdr->a_id != ACF_FILE_ID) { + aw_pr_err("not acf type file"); + return -EINVAL; + } + + hdr_ddt_len = cfg_hdr->a_hdr_offset + cfg_hdr->a_ddt_size; + if (hdr_ddt_len > aw_cfg->len) { + aw_pr_err("hdrlen with ddt_len [%d] overflow file size[%d]", + cfg_hdr->a_hdr_offset, aw_cfg->len); + return -EINVAL; + } + + /*check data size*/ + cfg_dde = (struct aw_cfg_dde *)((char *)aw_cfg->data + cfg_hdr->a_hdr_offset); + act_data += hdr_ddt_len; + for (i = 0; i < cfg_hdr->a_ddt_num; i++) + act_data += cfg_dde[i].data_size; + + if (act_data != aw_cfg->len) { + aw_pr_err("act_data[%d] not equal to file size[%d]!", + act_data, aw_cfg->len); + return -EINVAL; + } + + for (i = 0; i < cfg_hdr->a_ddt_num; i++) { + /* data check */ + end_data_offset = cfg_dde[i].data_offset + cfg_dde[i].data_size; + if (end_data_offset > aw_cfg->len) { + aw_pr_err("a_ddt_num[%d] end_data_offset[%d] overflow file size[%d]", + i, end_data_offset, aw_cfg->len); + return -EINVAL; + } + + /* crc check */ + act_crc8 = aw_dev_parse_crc8_check(aw_cfg->data + cfg_dde[i].data_offset, cfg_dde[i].data_size); + if (act_crc8 != cfg_dde[i].data_crc) { + aw_pr_err("a_ddt_num[%d] crc8 check failed, act_crc8:0x%x != data_crc 0x%x", + i, (uint32_t)act_crc8, cfg_dde[i].data_crc); + return -EINVAL; + } + } + + aw_pr_info("project name [%s]", cfg_hdr->a_project); + aw_pr_info("custom name [%s]", cfg_hdr->a_custom); + aw_pr_info("version name [%d.%d.%d.%d]", cfg_hdr->a_version[3], cfg_hdr->a_version[2], + cfg_hdr->a_version[1], cfg_hdr->a_version[0]); + aw_pr_info("author id %d", cfg_hdr->a_author_id); + + return 0; +} + +static int aw_dev_parse_check_acf_by_hdr_v_1_0_0_0(struct aw_container *aw_cfg) +{ + struct aw_cfg_hdr *cfg_hdr = NULL; + struct aw_cfg_dde_v_1_0_0_0 *cfg_dde = NULL; + unsigned int end_data_offset = 0; + unsigned int act_data = 0; + unsigned int hdr_ddt_len = 0; + uint8_t act_crc8 = 0; + int i; + + cfg_hdr = (struct aw_cfg_hdr *)aw_cfg->data; + + /*check file type id is awinic acf file*/ + if (cfg_hdr->a_id != ACF_FILE_ID) { + aw_pr_err("not acf type file"); + return -EINVAL; + } + + hdr_ddt_len = cfg_hdr->a_hdr_offset + cfg_hdr->a_ddt_size; + if (hdr_ddt_len > aw_cfg->len) { + aw_pr_err("hdrlen with ddt_len [%d] overflow file size[%d]", + cfg_hdr->a_hdr_offset, aw_cfg->len); + return -EINVAL; + } + + /*check data size*/ + cfg_dde = (struct aw_cfg_dde_v_1_0_0_0 *)((char *)aw_cfg->data + cfg_hdr->a_hdr_offset); + act_data += hdr_ddt_len; + for (i = 0; i < cfg_hdr->a_ddt_num; i++) + act_data += cfg_dde[i].data_size; + + if (act_data != aw_cfg->len) { + aw_pr_err("act_data[%d] not equal to file size[%d]!", + act_data, aw_cfg->len); + return -EINVAL; + } + + for (i = 0; i < cfg_hdr->a_ddt_num; i++) { + /* data check */ + end_data_offset = cfg_dde[i].data_offset + cfg_dde[i].data_size; + if (end_data_offset > aw_cfg->len) { + aw_pr_err("a_ddt_num[%d] end_data_offset[%d] overflow file size[%d]", + i, end_data_offset, aw_cfg->len); + return -EINVAL; + } + + /* crc check */ + act_crc8 = aw_dev_parse_crc8_check(aw_cfg->data + cfg_dde[i].data_offset, cfg_dde[i].data_size); + if (act_crc8 != cfg_dde[i].data_crc) { + aw_pr_err("a_ddt_num[%d] crc8 check failed, act_crc8:0x%x != data_crc 0x%x", + i, (uint32_t)act_crc8, cfg_dde[i].data_crc); + return -EINVAL; + } + } + + aw_pr_info("project name [%s]", cfg_hdr->a_project); + aw_pr_info("custom name [%s]", cfg_hdr->a_custom); + aw_pr_info("version name [%d.%d.%d.%d]", cfg_hdr->a_version[3], cfg_hdr->a_version[2], + cfg_hdr->a_version[1], cfg_hdr->a_version[0]); + aw_pr_info("author id %d", cfg_hdr->a_author_id); + + return 0; +} + + +int aw882xx_dev_parse_check_acf(struct aw_container *aw_cfg) +{ + struct aw_cfg_hdr *cfg_hdr = NULL; + + if (aw_cfg == NULL) { + aw_pr_err("aw_prof is NULL"); + return -ENOMEM; + } + + if (aw_cfg->len < sizeof(struct aw_cfg_hdr)) { + aw_pr_err("cfg hdr size[%d] overflow file size[%d]", + aw_cfg->len, (int)sizeof(struct aw_cfg_hdr)); + return -EINVAL; + } + + cfg_hdr = (struct aw_cfg_hdr *)aw_cfg->data; + switch (cfg_hdr->a_hdr_version) { + case AW_CFG_HDR_VER_0_0_0_1: + return aw_dev_parse_check_acf_by_hdr(aw_cfg); + case AW_CFG_HDR_VER_1_0_0_0: + return aw_dev_parse_check_acf_by_hdr_v_1_0_0_0(aw_cfg); + default: + aw_pr_err("unsupported hdr_version [0x%x]", cfg_hdr->a_hdr_version); + return -EINVAL; + } + + return 0; +} + +static int aw_dev_parse_raw_reg(struct aw_device *aw_dev, + uint8_t *data, uint32_t data_len, struct aw_prof_desc *prof_desc) +{ + aw_dev_info(aw_dev->dev, "data_size:%d enter", data_len); + + if (data_len % 4) { + aw_dev_err(aw_dev->dev, "bin data len get error!"); + return -EINVAL; + } + + prof_desc->sec_desc[AW_PROFILE_DATA_TYPE_REG].data = data; + prof_desc->sec_desc[AW_PROFILE_DATA_TYPE_REG].len = data_len; + + prof_desc->prof_st = AW_PROFILE_OK; + + return 0; +} + +static int aw_dev_parse_raw_dsp(struct aw_device *aw_dev, + uint8_t *data, uint32_t data_len, struct aw_prof_desc *prof_desc) +{ + aw_dev_info(aw_dev->dev, "data_size:%d enter", data_len); + + prof_desc->sec_desc[AW_PROFILE_DATA_TYPE_DSP].data = data; + prof_desc->sec_desc[AW_PROFILE_DATA_TYPE_DSP].len = data_len; + + return 0; +} + +static int aw_dev_parse_reg_bin_with_hdr(struct aw_device *aw_dev, + uint8_t *data, uint32_t data_len, struct aw_prof_desc *prof_desc) +{ + struct aw_bin *aw_bin = NULL; + int ret; + + aw_dev_info(aw_dev->dev, "data_size:%d enter", data_len); + + aw_bin = kzalloc(data_len + sizeof(struct aw_bin), GFP_KERNEL); + if (aw_bin == NULL) + return -ENOMEM; + + + aw_bin->info.len = data_len; + memcpy(aw_bin->info.data, data, data_len); + + ret = aw_parsing_bin_file(aw_bin); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "parse bin failed"); + goto parse_bin_failed; + } + + if ((aw_bin->all_bin_parse_num != 1) || + (aw_bin->header_info[0].bin_data_type != DATA_TYPE_REGISTER)) { + aw_dev_err(aw_dev->dev, "bin num or type error"); + goto parse_bin_failed; + } + + if (aw_bin->header_info[0].valid_data_len % 4) { + aw_dev_err(aw_dev->dev, "bin data len get error!"); + return -EINVAL; + } + + prof_desc->sec_desc[AW_PROFILE_DATA_TYPE_REG].data = + data + aw_bin->header_info[0].valid_data_addr; + prof_desc->sec_desc[AW_PROFILE_DATA_TYPE_REG].len = + aw_bin->header_info[0].valid_data_len; + prof_desc->prof_st = AW_PROFILE_OK; + + kfree(aw_bin); + aw_bin = NULL; + + return 0; + +parse_bin_failed: + kfree(aw_bin); + aw_bin = NULL; + return ret; +} + +static int aw_dev_parse_data_by_sec_type(struct aw_device *aw_dev, struct aw_cfg_hdr *cfg_hdr, + struct aw_cfg_dde *prof_hdr, struct aw_prof_desc *scene_prof_desc) +{ + switch (prof_hdr->data_type) { + case ACF_SEC_TYPE_REG: + return aw_dev_parse_raw_reg(aw_dev, + (uint8_t *)cfg_hdr + prof_hdr->data_offset, + prof_hdr->data_size, + scene_prof_desc); + case ACF_SEC_TYPE_HDR_REG: + return aw_dev_parse_reg_bin_with_hdr(aw_dev, + (uint8_t *)cfg_hdr + prof_hdr->data_offset, + prof_hdr->data_size, + scene_prof_desc); + case ACF_SEC_TYPE_MONITOR: + return aw882xx_monitor_parse_fw(&aw_dev->monitor_desc, + (uint8_t *)cfg_hdr + prof_hdr->data_offset, + prof_hdr->data_size); + } + + return 0; +} + +static int aw_dev_parse_dev_type(struct aw_device *aw_dev, + struct aw_cfg_hdr *prof_hdr, struct aw_all_prof_info *all_prof_info) +{ + int i = 0; + int ret; + int sec_num = 0; + struct aw_cfg_dde *cfg_dde = + (struct aw_cfg_dde *)((char *)prof_hdr + prof_hdr->a_hdr_offset); + + aw_dev_info(aw_dev->dev, "enter"); + + for (i = 0; i < prof_hdr->a_ddt_num; i++) { + if ((aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) && + (aw_dev->i2c->addr == cfg_dde[i].dev_addr) && + (cfg_dde[i].type == AW_DEV_TYPE_ID)) { + if (cfg_dde[i].data_type != ACF_SEC_TYPE_MONITOR) { + ret = aw_dev_parse_data_by_sec_type(aw_dev, prof_hdr, &cfg_dde[i], + &all_prof_info->prof_desc[cfg_dde[i].dev_profile]); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "parse dev driver bin data failed"); + return ret; + } + sec_num++; + } else { + ret = aw_dev_parse_data_by_sec_type(aw_dev, prof_hdr, &cfg_dde[i], NULL); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "parse monitor bin data failed"); + return ret; + } + sec_num++; + } + } + } + + if (sec_num == 0) { + aw_dev_info(aw_dev->dev, "get dev type num is %d, please use default", sec_num); + return AW_DEV_TYPE_NONE; + } + + return AW_DEV_TYPE_OK; +} + +static int aw_dev_parse_dev_default_type(struct aw_device *aw_dev, + struct aw_cfg_hdr *prof_hdr, struct aw_all_prof_info *all_prof_info) +{ + int i = 0; + int ret; + int sec_num = 0; + struct aw_cfg_dde *cfg_dde = + (struct aw_cfg_dde *)((char *)prof_hdr + prof_hdr->a_hdr_offset); + + aw_dev_info(aw_dev->dev, "enter"); + + for (i = 0; i < prof_hdr->a_ddt_num; i++) { + if ((aw_dev->channel == cfg_dde[i].dev_index) && + (cfg_dde[i].type == AW_DEV_DEFAULT_TYPE_ID)) { + if (cfg_dde[i].data_type != ACF_SEC_TYPE_MONITOR) { + ret = aw_dev_parse_data_by_sec_type(aw_dev, prof_hdr, &cfg_dde[i], + &all_prof_info->prof_desc[cfg_dde[i].dev_profile]); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "parse dev driver bin data failed"); + return ret; + } + } else { + ret = aw_dev_parse_data_by_sec_type(aw_dev, prof_hdr, &cfg_dde[i], NULL); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "parse monitor bin data failed"); + return ret; + } + } + sec_num++; + } + } + + if (sec_num == 0) { + aw_dev_err(aw_dev->dev, "get dev default type failed, get num[%d]", sec_num); + return -EINVAL; + } + + return 0; +} + +static int aw_dev_parse_skt_type(struct aw_device *aw_dev, + struct aw_cfg_hdr *prof_hdr, struct aw_all_prof_info *all_prof_info) +{ + int i = 0; + int ret; + int sec_num = 0; + struct aw_cfg_dde *cfg_dde = + (struct aw_cfg_dde *)((char *)prof_hdr + prof_hdr->a_hdr_offset); + + aw_dev_info(aw_dev->dev, "enter"); + + for (i = 0; i < prof_hdr->a_ddt_num; i++) { + if ((aw_dev->channel == cfg_dde[i].dev_index) && + (cfg_dde[i].type == AW_SKT_TYPE_ID)) { + if (cfg_dde[i].data_type == ACF_SEC_TYPE_DSP) { + ret = aw_dev_parse_raw_dsp(aw_dev, + (uint8_t *)prof_hdr + cfg_dde[i].data_offset, + cfg_dde[i].data_size, + &all_prof_info->prof_desc[cfg_dde[i].dev_profile]); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "parse dsp bin data failed"); + return ret; + } + sec_num++; + } + } + } + + aw_dev_info(aw_dev->dev, "get dsp data prof cnt is %d ", sec_num); + return 0; +} + +static int aw_dev_parse_get_vaild_prof(struct aw_device *aw_dev, + struct aw_all_prof_info all_prof_info) +{ + int i; + int num = 0; + struct aw_prof_desc *prof_desc = all_prof_info.prof_desc; + struct aw_prof_info *prof_info = &aw_dev->prof_info; + + for (i = 0; i < AW_PROFILE_MAX; i++) { + if (prof_desc[i].prof_st == AW_PROFILE_OK) + aw_dev->prof_info.count++; + } + + aw_dev_info(aw_dev->dev, "get vaild profile:%d", aw_dev->prof_info.count); + + if (!aw_dev->prof_info.count) { + aw_dev_err(aw_dev->dev, "no profile data"); + return -EPERM; + } + + prof_info->prof_desc = kzalloc(prof_info->count * sizeof(struct aw_prof_desc), GFP_KERNEL); + if (prof_info->prof_desc == NULL) + return -ENOMEM; + + + for (i = 0; i < AW_PROFILE_MAX; i++) { + if (prof_desc[i].prof_st == AW_PROFILE_OK) { + if (num >= prof_info->count) { + aw_dev_err(aw_dev->dev, "get scene num[%d] overflow count[%d]", + num, prof_info->count); + return -ENOMEM; + } + prof_info->prof_desc[num] = prof_desc[i]; + prof_info->prof_desc[num].id = i; + num++; + } + } + + return 0; +} + +static int aw_dev_parse_acf_by_hdr(struct aw_device *aw_dev, + struct aw_cfg_hdr *prof_hdr) +{ + int ret; + struct aw_all_prof_info all_prof_info; + + memset(&all_prof_info, 0, sizeof(struct aw_all_prof_info)); + + ret = aw_dev_parse_dev_type(aw_dev, prof_hdr, &all_prof_info); + if (ret < 0) { + return ret; + } else if (ret == AW_DEV_TYPE_NONE) { + aw_dev_info(aw_dev->dev, "get dev type num is0, parse default dev type"); + ret = aw_dev_parse_dev_default_type(aw_dev, prof_hdr, &all_prof_info); + if (ret < 0) + return ret; + } + + ret = aw_dev_parse_skt_type(aw_dev, prof_hdr, &all_prof_info); + if (ret < 0) + return ret; + + ret = aw_dev_parse_get_vaild_prof(aw_dev, all_prof_info); + if (ret < 0) + return ret; + + aw_dev->prof_info.prof_name_list = profile_name; + + + return 0; +} + + +/******************************************bin format V1.0.0.0********************************************/ +static int aw_dev_parse_get_scene_count_v1_0_0_0(struct aw_device *aw_dev, + struct aw_container *aw_cfg, uint32_t *count, int *is_default) +{ + struct aw_cfg_hdr *cfg_hdr = (struct aw_cfg_hdr *)aw_cfg->data; + struct aw_cfg_dde_v_1_0_0_0 *cfg_dde = + (struct aw_cfg_dde_v_1_0_0_0 *)(aw_cfg->data + cfg_hdr->a_hdr_offset); + int i = 0; + + for (i = 0; i < cfg_hdr->a_ddt_num; ++i) { + if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) || + (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) && + (cfg_dde[i].type == AW_DEV_TYPE_ID) && + ((aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) && + (aw_dev->i2c->addr == cfg_dde[i].dev_addr)) && + (aw_dev->chip_id == cfg_dde[i].chip_id)) { + (*count)++; + (*is_default) = 0; + } + } + + if ((*count) == 0) { + for (i = 0; i < cfg_hdr->a_ddt_num; ++i) { + if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) || + (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) && + (cfg_dde[i].type == AW_DEV_DEFAULT_TYPE_ID) && + (aw_dev->channel == cfg_dde[i].dev_index) && + (aw_dev->chip_id == cfg_dde[i].chip_id)) { + (*count)++; + (*is_default) = 1; + } + } + } + + if ((*count) == 0) { + aw_dev_err(aw_dev->dev, "can't find scene"); + return -EINVAL; + } + + aw_dev_info(aw_dev->dev, "scene count is %d", (*count)); + return 0; +} + + +static int aw_dev_parse_create_prof_name_list_v_1_0_0_0(struct aw_device *aw_dev) +{ + struct aw_prof_info *prof_info = &aw_dev->prof_info; + struct aw_prof_desc *prof_desc = prof_info->prof_desc; + int i; + + if (prof_desc == NULL) { + aw_dev_err(aw_dev->dev, "prof_desc is NULL"); + return -EINVAL; + } + + prof_info->prof_name_list = devm_kzalloc(aw_dev->dev, + prof_info->count * PROFILE_STR_MAX, + GFP_KERNEL); + if (prof_info->prof_name_list == NULL) { + aw_dev_err(aw_dev->dev, "prof_name_list devm_kzalloc failed"); + return -ENOMEM; + } + + for (i = 0; i < prof_info->count; i++) { + prof_desc[i].id = i; + prof_info->prof_name_list[i] = prof_desc[i].prf_str; + aw_dev_info(aw_dev->dev, "prof name is %s", prof_info->prof_name_list[i]); + } + + return 0; +} + +static int aw_dev_parse_drv_type_v_1_0_0_0(struct aw_device *aw_dev, + struct aw_cfg_hdr *prof_hdr, struct aw_cfg_dde_v_1_0_0_0 *cfg_dde, int *cur_scene_id) +{ + int ret = -1; + struct aw_prof_info *prof_info = &aw_dev->prof_info; + + switch (cfg_dde->data_type) { + case ACF_SEC_TYPE_REG: + ret = aw_dev_parse_raw_reg(aw_dev, + (uint8_t *)prof_hdr + cfg_dde->data_offset, + cfg_dde->data_size, &prof_info->prof_desc[*cur_scene_id]); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "parse reg bin failed"); + return ret; + } + prof_info->prof_desc[*cur_scene_id].prf_str = cfg_dde->dev_profile_str; + prof_info->prof_desc[*cur_scene_id].id = cfg_dde->dev_profile; + (*cur_scene_id)++; + break; + case ACF_SEC_TYPE_HDR_REG: + ret = aw_dev_parse_reg_bin_with_hdr(aw_dev, + (uint8_t *)prof_hdr + cfg_dde->data_offset, + cfg_dde->data_size, &prof_info->prof_desc[*cur_scene_id]); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "parse reg bin with hdr failed"); + return ret; + } + prof_info->prof_desc[*cur_scene_id].prf_str = cfg_dde->dev_profile_str; + prof_info->prof_desc[*cur_scene_id].id = cfg_dde->dev_profile; + (*cur_scene_id)++; + break; + case ACF_SEC_TYPE_MONITOR: + ret = aw882xx_monitor_parse_fw(&aw_dev->monitor_desc, + (uint8_t *)prof_hdr + cfg_dde->data_offset, + cfg_dde->data_size); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "parse monitor bin failed"); + return ret; + } + break; + default: + aw_dev_err(aw_dev->dev, "unsupport bin type!"); + return -EINVAL; + } + + return ret; +} + +static int aw_dev_parse_dev_type_v_1_0_0_0(struct aw_device *aw_dev, + struct aw_cfg_hdr *prof_hdr) +{ + int i = 0; + int ret = -1; + int cur_scene_id = 0; + struct aw_cfg_dde_v_1_0_0_0 *cfg_dde = + (struct aw_cfg_dde_v_1_0_0_0 *)((char *)prof_hdr + prof_hdr->a_hdr_offset); + + aw_dev_info(aw_dev->dev, "enter"); + + for (i = 0; i < prof_hdr->a_ddt_num; i++) { + if ((cfg_dde[i].type == AW_DEV_TYPE_ID) && + (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) && + (aw_dev->i2c->addr == cfg_dde[i].dev_addr) && + (aw_dev->chip_id == cfg_dde[i].chip_id)) { + ret = aw_dev_parse_drv_type_v_1_0_0_0(aw_dev, + prof_hdr, &cfg_dde[i], &cur_scene_id); + if (ret < 0) + return ret; + } + } + + if (cur_scene_id == 0) { + aw_dev_info(aw_dev->dev, "get dev type num is %d", cur_scene_id); + return -EINVAL; + } + + return 0; +} + +static int aw_dev_parse_dev_default_type_v_1_0_0_0(struct aw_device *aw_dev, + struct aw_cfg_hdr *prof_hdr) +{ + int i = 0; + int ret; + int cur_scene_id = 0; + struct aw_cfg_dde_v_1_0_0_0 *cfg_dde = + (struct aw_cfg_dde_v_1_0_0_0 *)((char *)prof_hdr + prof_hdr->a_hdr_offset); + + aw_dev_info(aw_dev->dev, "enter"); + + for (i = 0; i < prof_hdr->a_ddt_num; i++) { + if ((cfg_dde[i].type == AW_DEV_DEFAULT_TYPE_ID) && + (aw_dev->channel == cfg_dde[i].dev_index) && + (aw_dev->chip_id == cfg_dde[i].chip_id)) { + ret = aw_dev_parse_drv_type_v_1_0_0_0(aw_dev, + prof_hdr, &cfg_dde[i], &cur_scene_id); + if (ret < 0) + return ret; + } + } + + if (cur_scene_id == 0) { + aw_dev_err(aw_dev->dev, "get dev default type failed, get num[%d]", cur_scene_id); + return -EINVAL; + } + + return 0; +} + +static int aw_dev_parse_get_scene_id_v_1_0_0_0(struct aw_device *aw_dev, char *scene_str, int *scene_id) +{ + struct aw_prof_info *prof_info = &aw_dev->prof_info; + int i; + + if (scene_str == NULL) { + aw_dev_err(aw_dev->dev, "scene_str is NULL"); + return -EINVAL; + } + + for (i = 0; i < prof_info->count; i++) { + if (prof_info->prof_desc[i].prf_str == NULL) { + aw_dev_err(aw_dev->dev, "porfile name is NULL"); + return -EINVAL; + } + + if (!strcmp(prof_info->prof_desc[i].prf_str, scene_str)) { + *scene_id = i; + return 0; + } + } + + aw_dev_err(aw_dev->dev, "not found scene:%s", scene_str); + + return -EINVAL; +} + +static int aw_dev_parse_skt_type_v_1_0_0_0(struct aw_device *aw_dev, + struct aw_cfg_hdr *prof_hdr) +{ + int i = 0; + int ret; + int scene_id = 0; + struct aw_prof_info *prof_info = &aw_dev->prof_info; + struct aw_cfg_dde_v_1_0_0_0 *cfg_dde = + (struct aw_cfg_dde_v_1_0_0_0 *)((char *)prof_hdr + prof_hdr->a_hdr_offset); + + aw_dev_info(aw_dev->dev, "enter"); + + for (i = 0; i < prof_hdr->a_ddt_num; i++) { + if ((cfg_dde[i].type == AW_SKT_TYPE_ID) && + (cfg_dde[i].data_type == ACF_SEC_TYPE_DSP) && + (aw_dev->channel == cfg_dde[i].dev_index) && + (aw_dev->chip_id == cfg_dde[i].chip_id)) { + ret = aw_dev_parse_get_scene_id_v_1_0_0_0(aw_dev, cfg_dde[i].dev_profile_str, &scene_id); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "get scene id failed"); + return ret; + } + + ret = aw_dev_parse_raw_dsp(aw_dev, + (uint8_t *)prof_hdr + cfg_dde[i].data_offset, + cfg_dde[i].data_size, &prof_info->prof_desc[scene_id]); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "parse dsp bin data failed"); + return ret; + } + } + } + + return 0; +} + + +static int aw_dev_parse_by_hdr_v_1_0_0_0(struct aw_device *aw_dev, + struct aw_cfg_hdr *cfg_hdr, int is_default) +{ + int ret; + + if (is_default) { + ret = aw_dev_parse_dev_default_type_v_1_0_0_0(aw_dev, cfg_hdr); + if (ret < 0) + return ret; + } else { + ret = aw_dev_parse_dev_type_v_1_0_0_0(aw_dev, cfg_hdr); + if (ret < 0) + return ret; + } + + ret = aw_dev_parse_skt_type_v_1_0_0_0(aw_dev, cfg_hdr); + if (ret < 0) + return ret; + + return 0; +} + +static int aw_dev_parse_acf_by_hdr_v_1_0_0_0(struct aw_device *aw_dev, struct aw_container *aw_cfg) +{ + struct aw_prof_info *prof_info = &aw_dev->prof_info; + struct aw_cfg_hdr *cfg_hdr = (struct aw_cfg_hdr *)aw_cfg->data; + int ret; + int is_default = 0; + + ret = aw_dev_parse_get_scene_count_v1_0_0_0(aw_dev, aw_cfg, &prof_info->count, &is_default); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "get scene count failed"); + return ret; + } + + prof_info->prof_desc = devm_kzalloc(aw_dev->dev, + prof_info->count * sizeof(struct aw_prof_desc), + GFP_KERNEL); + if (prof_info->prof_desc == NULL) { + aw_dev_err(aw_dev->dev, "prof_desc devm_kzalloc failed"); + return -ENOMEM; + } + + ret = aw_dev_parse_by_hdr_v_1_0_0_0(aw_dev, cfg_hdr, is_default); + if (ret < 0) { + aw_dev_err(aw_dev->dev, " failed"); + return ret; + } + + ret = aw_dev_parse_create_prof_name_list_v_1_0_0_0(aw_dev); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "create prof name list failed"); + return ret; + } + + return 0; +} + +int aw882xx_dev_parse_acf(struct aw_device *aw_dev, struct aw_container *aw_cfg) +{ + struct aw_cfg_hdr *cfg_hdr = NULL; + int ret; + + aw_dev_info(aw_dev->dev, "enter"); + + cfg_hdr = (struct aw_cfg_hdr *)aw_cfg->data; + switch (cfg_hdr->a_hdr_version) { + case AW_CFG_HDR_VER_0_0_0_1: + ret = aw_dev_parse_acf_by_hdr(aw_dev, cfg_hdr); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "hdr_cersion[0x%x] parse failed", + cfg_hdr->a_hdr_version); + return ret; + } + break; + case AW_CFG_HDR_VER_1_0_0_0: + ret = aw_dev_parse_acf_by_hdr_v_1_0_0_0(aw_dev, aw_cfg); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "hdr_cersion[0x%x] parse failed", + cfg_hdr->a_hdr_version); + return ret; + } + break; + default: + aw_pr_err("unsupported hdr_version [0x%x]", cfg_hdr->a_hdr_version); + return -EINVAL; + } + + aw_dev_info(aw_dev->dev, "parse cfg success"); + return 0; +} + +char *aw882xx_dev_get_prof_name(struct aw_device *aw_dev, int index) +{ + struct aw_prof_desc *prof_desc = NULL; + struct aw_prof_info *prof_info = &aw_dev->prof_info; + + if (index < 0) { + aw_dev_err(aw_dev->dev, "index[%d] error", index); + return NULL; + } + + if (index >= prof_info->count) { + aw_dev_err(aw_dev->dev, "index[%d] overflow count[%d]", + index, aw_dev->prof_info.count); + return NULL; + } + + prof_desc = &prof_info->prof_desc[index]; + + return prof_info->prof_name_list[prof_desc->id]; +} + +int aw88xx_dev_get_profile_name(struct aw_device *aw_dev, char *name, int index) +{ + int dev_profile_id = 0; + int ret = 0; + struct aw_prof_info *prof_info = &aw_dev->prof_info; + + if (index < 0) { + aw_dev_err(aw_dev->dev, "index[%d] error", index); + return -EINVAL; + } + + if (index > prof_info->count) { + aw_dev_err(aw_dev->dev, "index[%d] overflow dev prof num[%d]", + index, prof_info->count); + return -EINVAL; + } + + dev_profile_id = prof_info->prof_desc[index].id; + + ret = strscpy(name, prof_info->prof_name_list[dev_profile_id], + strlen(prof_info->prof_name_list[dev_profile_id]) + 1); + if (ret < 0) + return ret; + + return 0; +} + +struct aw_sec_data_desc *aw882xx_dev_get_prof_data(struct aw_device *aw_dev, int index, int data_type) +{ + struct aw_sec_data_desc *sec_data = NULL; + struct aw_prof_desc *prof_desc = NULL; + struct aw_prof_info *prof_info = &aw_dev->prof_info; + + if (index >= prof_info->count) { + aw_dev_err(aw_dev->dev, "index[%d] overflow count[%d]", + index, prof_info->count); + return NULL; + } + + prof_desc = &aw_dev->prof_info.prof_desc[index]; + + if (data_type >= AW_PROFILE_DATA_TYPE_MAX) { + aw_dev_err(aw_dev->dev, "unsupport data type id [%d]", data_type); + return NULL; + } + + sec_data = &prof_desc->sec_desc[data_type]; + + aw_dev_dbg(aw_dev->dev, "get prof[%s] data len[%d]", + prof_info->prof_name_list[prof_desc->id], sec_data->len); + + return sec_data; +} + +int aw882xx_dev_set_profile_index(struct aw_device *aw_dev, int index) +{ + struct aw_prof_info *prof_info = &aw_dev->prof_info; + struct mutex *ext_dsp_prof_wr_lock = NULL; + char *ext_dsp_prof_write = NULL; + + if (index >= prof_info->count || index < 0) + return -EINVAL; + + aw_dev->set_prof = index; + aw_dev_info(aw_dev->dev, "set prof[%s]", + prof_info->prof_name_list[prof_info->prof_desc[index].id]); + + + ext_dsp_prof_wr_lock = aw882xx_dev_get_ext_dsp_prof_wr_lock(); + ext_dsp_prof_write = aw882xx_dev_get_ext_dsp_prof_write(); + + mutex_lock(ext_dsp_prof_wr_lock); + *ext_dsp_prof_write = AW_EXT_DSP_WRITE_NONE; + mutex_unlock(ext_dsp_prof_wr_lock); + + return 0; +} + +int aw882xx_dev_get_profile_count(struct aw_device *aw_dev) +{ + if (aw_dev == NULL) { + aw_pr_err("aw_dev is NULL"); + return -ENOMEM; + } + + return aw_dev->prof_info.count; +} + +int aw882xx_dev_check_profile_index(struct aw_device *aw_dev, int index) +{ + if ((index >= aw_dev->prof_info.count) || (index < 0)) + return -EINVAL; + else + return 0; +} + +int aw882xx_dev_get_profile_index(struct aw_device *aw_dev) +{ + return aw_dev->set_prof; +} + diff --git a/sound/soc/codecs/aw882xx/aw882xx_bin_parse.h b/sound/soc/codecs/aw882xx/aw882xx_bin_parse.h new file mode 100644 index 000000000000..b47dbf66ccb7 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_bin_parse.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0 + * aw882xx_bin_parse.h + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_BIN_PARSE_H__ +#define __AW882XX_BIN_PARSE_H__ + +#include "aw882xx_device.h" + +#define NULL ((void *)0) +#define GET_32_DATA(w, x, y, z) ((unsigned int)((((uint32_t)w) << 24) | (((uint32_t)x) << 16) | (((uint32_t)y) << 8) | ((uint32_t)z))) +#define BIN_NUM_MAX 100 +#define HEADER_LEN 60 +/********************************************************* + * + * header information + * + ********************************************************/ +enum bin_header_version_enum { + HEADER_VERSION_1_0_0 = 0x01000000, +}; + +enum data_type_enum { + DATA_TYPE_REGISTER = 0x00000000, + DATA_TYPE_DSP_REG = 0x00000010, + DATA_TYPE_DSP_CFG = 0x00000011, + DATA_TYPE_SOC_REG = 0x00000020, + DATA_TYPE_SOC_APP = 0x00000021, + DATA_TYPE_MULTI_BINS = 0x00002000, +}; + +enum data_version_enum { + DATA_VERSION_V1 = 0X00000001, /*default little edian */ + DATA_VERSION_MAX, +}; + +struct bin_header_info { + unsigned int header_len; /* Frame header length */ + unsigned int check_sum; /* Frame header information-Checksum */ + unsigned int header_ver; /* Frame header information-Frame header version */ + unsigned int bin_data_type; /* Frame header information-Data type */ + unsigned int bin_data_ver; /* Frame header information-Data version */ + unsigned int bin_data_len; /* Frame header information-Data length */ + unsigned int ui_ver; /* Frame header information-ui version */ + unsigned char chip_type[8]; /* Frame header information-chip type */ + unsigned int reg_byte_len; /* Frame header information-reg byte len */ + unsigned int data_byte_len; /* Frame header information-data byte len */ + unsigned int device_addr; /* Frame header information-device addr */ + unsigned int valid_data_len; /* Length of valid data obtained after parsing */ + unsigned int valid_data_addr; /* The offset address of the valid data obtained after parsing relative to info */ + + unsigned int reg_num; /* The number of registers obtained after parsing */ + unsigned int reg_data_byte_len; /* The byte length of the register obtained after parsing */ + unsigned int download_addr; /* The starting address or download address obtained after parsing */ + unsigned int app_version; /* The software version number obtained after parsing */ +}; + +/************************************************************ + * + * function define + * + ************************************************************/ +struct bin_container { + unsigned int len; /* The size of the bin file obtained from the firmware */ + unsigned char data[]; /* Store the bin file obtained from the firmware */ +}; + +struct aw_bin { + unsigned char *p_addr; /* Offset pointer (backward offset pointer to obtain frame header information and important information) */ + unsigned int all_bin_parse_num; /* The number of all bin files */ + unsigned int multi_bin_parse_num; /* The number of single bin files */ + unsigned int single_bin_parse_num; /* The number of multiple bin files */ + struct bin_header_info header_info[BIN_NUM_MAX]; /* Frame header information and other important data obtained after parsing */ + struct bin_container info; /* Obtained bin file data that needs to be parsed */ +}; + + +/*******************awinic audio parse acf***********************/ + +int aw882xx_dev_parse_check_acf(struct aw_container *aw_cfg); +int aw882xx_dev_parse_acf(struct aw_device *aw_dev, struct aw_container *aw_cfg); + + +int aw882xx_dev_get_profile_count(struct aw_device *aw_dev); +int aw88xx_dev_get_profile_name(struct aw_device *aw_dev, char *name, int index); +int aw882xx_dev_check_profile_index(struct aw_device *aw_dev, int index); +int aw882xx_dev_get_profile_index(struct aw_device *aw_dev); +int aw882xx_dev_set_profile_index(struct aw_device *aw_dev, int index); +char *aw882xx_dev_get_prof_name(struct aw_device *aw_dev, int index); +struct aw_sec_data_desc *aw882xx_dev_get_prof_data(struct aw_device *aw_dev, int index, int data_type); + + +#endif diff --git a/sound/soc/codecs/aw882xx/aw882xx_calib.c b/sound/soc/codecs/aw882xx/aw882xx_calib.c new file mode 100644 index 000000000000..fad7ba7c4175 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_calib.c @@ -0,0 +1,2453 @@ +// SPDX-License-Identifier: GPL-2.0 +/* aw882xx_calib.c cali_module + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +/*#define DEBUG*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aw882xx.h" +#include "aw882xx_dsp.h" +#include "aw882xx_log.h" +#include "aw882xx_calib.h" + +static bool is_single_cali; /*if mutli_dev cali false, single dev true*/ + +static const char *cali_str[CALI_STR_MAX] = {"none", "start_cali", "cali_re", + "cali_f0", "store_re", "show_re", "show_r0", "show_cali_f0", "show_f0", + "show_te", "show_st", "dev_sel", "get_ver", "get_dev_num", + "cali_q_f0", "show_q_f0", "get_re_range" +}; + +static char *ch_name[AW_DEV_CH_MAX] = {"pri_l", "pri_r", "sec_l", "sec_r", + "tert_l", "tert_r", "quat_l", "quat_r"}; +static unsigned int g_cali_re_time = AW_CALI_RE_DEFAULT_TIMER; +static unsigned int g_msic_wr_flag = CALI_STR_NONE; +static unsigned int g_dev_select = AW_DEV_CH_PRI_L; +static unsigned int g_cali_status; +static struct miscdevice *g_misc_dev; +static DEFINE_MUTEX(g_cali_lock); + +#ifndef AW_AUDIOREACH_PLATFORM +#define AW_CALI_STORE_EXAMPLE +#endif + +#ifdef AW_CALI_STORE_EXAMPLE + /*write cali to persist file example*/ +#define AWINIC_CALI_FILE "/mnt/vendor/persist/factory/audio/aw_cali.bin" +#define AW_INT_DEC_DIGIT 10 + +static void aw_fs_read(struct file *file, char *buf, size_t count, loff_t *pos) +{ +#ifdef AW_KERNEL_VER_OVER_5_4_0 + kernel_read(file, buf, count, pos); +#else + vfs_read(file, buf, count, pos); +#endif +} + +static void aw_fs_write(struct file *file, char *buf, size_t count, loff_t *pos) +{ +#ifdef AW_KERNEL_VER_OVER_5_4_0 + kernel_write(file, buf, count, pos); +#else + vfs_write(file, buf, count, pos); +#endif +} + +static int aw_cali_write_cali_re_to_file(int32_t cali_re, int channel) +{ + struct file *fp = NULL; + char buf[50] = {0}; + loff_t pos = 0; +#if !defined AW_KERNEL_VER_OVER_6_1_0 + mm_segment_t fs; +#endif + + fp = filp_open(AWINIC_CALI_FILE, O_RDWR | O_CREAT, 0644); + if (IS_ERR(fp)) { + aw_pr_err("channel:%d open %s failed, error=%ld", + channel, AWINIC_CALI_FILE, PTR_ERR(fp)); + return -EINVAL; + } + + pos = AW_INT_DEC_DIGIT * channel; + + snprintf(buf, sizeof(buf), "%10d", cali_re); + +#ifdef AW_KERNEL_VER_OVER_6_1_0 +#elif defined AW_KERNEL_VER_OVER_5_10_0 + fs = force_uaccess_begin(); +#else + fs = get_fs(); + set_fs(KERNEL_DS); +#endif + + aw_fs_write(fp, buf, strlen(buf), &pos); + +#ifdef AW_KERNEL_VER_OVER_6_1_0 +#elif defined AW_KERNEL_VER_OVER_5_10_0 + force_uaccess_end(fs); +#else + set_fs(fs); +#endif + + aw_pr_info("channel:%d buf:%s cali_re:%d", + channel, buf, cali_re); + + filp_close(fp, NULL); + return 0; +} + +static int aw_cali_get_read_cali_re(int32_t *cali_re, int channel) +{ + struct file *fp = NULL; + /*struct inode *node;*/ + int f_size; + char *buf = NULL; + int32_t int_cali_re = 0; + loff_t pos = 0; +#if !defined AW_KERNEL_VER_OVER_6_1_0 + mm_segment_t fs; +#endif + + char *re_buf = NULL; + + fp = filp_open(AWINIC_CALI_FILE, O_RDONLY, 0); + if (IS_ERR(fp)) { + aw_pr_err("channel:%d open %s failed, error=%ld", + channel, AWINIC_CALI_FILE, PTR_ERR(fp)); + return -EINVAL; + } + + pos = AW_INT_DEC_DIGIT * channel; + + /*node = fp->f_dentry->d_inode;*/ + /*f_size = node->i_size;*/ + f_size = AW_INT_DEC_DIGIT; + + buf = kzalloc(f_size + 1, GFP_ATOMIC); + if (!buf) { + filp_close(fp, NULL); + return -ENOMEM; + } + +#ifdef AW_KERNEL_VER_OVER_6_1_0 +#elif defined AW_KERNEL_VER_OVER_5_10_0 + fs = force_uaccess_begin(); +#else + fs = get_fs(); + set_fs(KERNEL_DS); +#endif + + aw_fs_read(fp, buf, f_size, &pos); + +#ifdef AW_KERNEL_VER_OVER_6_1_0 +#elif defined AW_KERNEL_VER_OVER_5_10_0 + force_uaccess_end(fs); +#else + set_fs(fs); +#endif + + re_buf = skip_spaces(buf); + + if (kstrtoint(re_buf, 10, &int_cali_re) == 0) + *cali_re = int_cali_re; + else + *cali_re = AW_ERRO_CALI_VALUE; + + re_buf = NULL; + aw_pr_info("channel:%d buf:%s int_cali_re: %d", + channel, buf, int_cali_re); + + kfree(buf); + buf = NULL; + filp_close(fp, NULL); + + return 0; +} +#endif + +/*custom need add to set/get cali_re form/to nv*/ +static int aw_cali_write_re_to_nvram(int32_t cali_re, int32_t channel) +{ +#ifdef AW_CALI_STORE_EXAMPLE + if (channel >= AW_DEV_CH_MAX) { + aw_pr_err("unsupported channel [%d]", channel); + return -EINVAL; + } + return aw_cali_write_cali_re_to_file(cali_re, channel); +#else + return 0; +#endif +} + +int aw882xx_cali_read_re_from_nvram(int32_t *cali_re, int32_t channel) +{ + /*custom add, if success return value is 0 , else -1*/ +#ifdef AW_CALI_STORE_EXAMPLE + if (channel >= AW_DEV_CH_MAX) { + aw_pr_err("unsupported channel [%d]", channel); + return -EINVAL; + } + return aw_cali_get_read_cali_re(cali_re, channel); +#else + return 0; +#endif +} + +bool aw882xx_cali_check_result(struct aw_cali_desc *cali_desc) +{ + if (cali_desc->cali_check_st && + (cali_desc->cali_result == CALI_RESULT_ERROR)) { + return false; + } else { + return true; + } +} + +static void aw_cali_svc_run_mute(struct aw_device *aw_dev, int8_t cali_result) +{ + aw_dev_dbg(aw_dev->dev, "enter"); + + if (aw_dev->cali_desc.cali_check_st) { + if (cali_result == CALI_RESULT_ERROR) + aw882xx_dev_mute(aw_dev, true); + else if (cali_result == CALI_RESULT_NORMAL) + aw882xx_dev_mute(aw_dev, false); + else + aw_dev_info(aw_dev->dev, "unsupported result"); + } else { + aw_dev_info(aw_dev->dev, "cali check disable"); + } + + aw_dev_info(aw_dev->dev, "done"); +} + +static int aw_cali_svc_get_dev_re_range(struct aw_device *aw_dev, + uint32_t *data_buf) +{ + data_buf[RE_MIN_FLAG] = aw_dev->re_min; + data_buf[RE_MAX_FLAG] = aw_dev->re_max; + + return 0; +} + +static int aw_cali_svc_get_devs_re_range(struct aw_device *aw_dev, + uint32_t *data_buf, int num) +{ + int ret, cnt = 0; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + /*get dev list*/ + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed"); + return ret; + } + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel < num) { + /*buf[0]:pri_l_re_min, buf[1]:pri_l_re_min, buf[2]:pri_r_re_min, buf[3]:pri_r_re_min*/ + data_buf[RE_MIN_FLAG + local_dev->channel * 2] = + local_dev->re_min; + data_buf[RE_MAX_FLAG + local_dev->channel * 2] = + local_dev->re_max; + cnt++; + } else { + aw_dev_err(local_dev->dev, "channel num[%d] overflow buf num[%d]", + local_dev->channel, num); + return -EINVAL; + } + } + + return cnt; +} + +static int aw_cali_store_cali_re(struct aw_device *aw_dev, int32_t re) +{ + int ret = 0; + + if (((re >= aw_dev->re_min) && (re <= aw_dev->re_max)) || + aw_dev->cali_desc.cali_check_st) { + aw_dev->cali_desc.cali_re = re; + ret = aw_cali_write_re_to_nvram(re, aw_dev->channel); + if (ret) { + aw_dev_err(aw_dev->dev, "write re to nvram failed!"); + goto store_cali_re_failed; + } + aw_dev_info(aw_dev->dev, "store cali re is %d", re); + } + + if ((re < aw_dev->re_min) || (re > aw_dev->re_max)) { + aw_dev_info(aw_dev->dev, "re[%d] out of range {%d, %d}", + re, aw_dev->re_min, aw_dev->re_max); + ret = -EINVAL; + goto store_cali_re_failed; + } + + if (aw_dev->cali_desc.cali_check_st) + aw_dev->cali_desc.cali_result = CALI_RESULT_NORMAL; + + return 0; + +store_cali_re_failed: + if (aw_dev->cali_desc.cali_check_st) { + aw_dev->cali_desc.cali_result = CALI_RESULT_ERROR; + aw_cali_svc_run_mute(aw_dev, aw_dev->cali_desc.cali_result); + } + return ret; +} + +/*********************************aw_cali_sevice*********************************************************/ +static void aw_cali_svc_set_cali_status(struct aw_device *aw_dev, int status) +{ + if (status) + g_cali_status = true; + else + g_cali_status = false; + + aw_dev_info(aw_dev->dev, "cali %s", + (status == 0) ? ("disable") : ("enable")); +} + +int aw882xx_cali_svc_get_cali_status(void) +{ + return g_cali_status; +} + +static int aw_cali_svc_dev_get_re(struct aw_device *aw_dev) +{ + int ret, i; + int32_t re[AW_CALI_READ_RE_TIMES] = {0}; + int32_t sum = 0; + + for (i = 0; i < AW_CALI_READ_RE_TIMES; i++) { + ret = aw882xx_dsp_read_r0(aw_dev, &re[i]); + if (ret) { + aw_dev_err(aw_dev->dev, "get re failed!"); + if (aw_dev->cali_desc.cali_check_st) { + aw_dev->cali_desc.cali_result = CALI_RESULT_ERROR; + aw_cali_svc_run_mute(aw_dev, aw_dev->cali_desc.cali_result); + } + return ret; + } + sum += re[i]; + usleep_range(AW_32000_US, AW_32000_US + 10); + } + re[0] = sum / AW_CALI_READ_RE_TIMES; + + aw_dev->cali_desc.cali_re = re[0]; + + ret = aw_cali_store_cali_re(aw_dev, aw_dev->cali_desc.cali_re); + return ret; +} + +static int aw_cali_svc_dev_get_f0(struct aw_device *aw_dev) +{ + int ret, i; + int32_t f0[AW_CALI_READ_F0_Q_TIMES] = {0}; + int32_t sum = 0; + + for (i = 0; i < AW_CALI_READ_F0_Q_TIMES; i++) { + ret = aw882xx_dsp_read_f0(aw_dev, &f0[i]); + if (ret) { + aw_dev_err(aw_dev->dev, "get f0 failed!"); + return ret; + } + sum += f0[i]; + usleep_range(AW_70000_US, AW_70000_US + 10); + } + f0[0] = sum / AW_CALI_READ_F0_Q_TIMES; + + aw_dev->cali_desc.cali_f0 = f0[0]; + return 0; +} + +static int aw_cali_svc_dev_get_f0_q(struct aw_device *aw_dev) +{ + int ret, i; + int32_t f0[AW_CALI_READ_F0_Q_TIMES] = {0}; + int32_t q[AW_CALI_READ_F0_Q_TIMES] = {0}; + int32_t sum_f0 = 0, sum_q = 0; + + for (i = 0; i < AW_CALI_READ_F0_Q_TIMES; i++) { + ret = aw882xx_dsp_read_f0_q(aw_dev, &f0[i], &q[i]); + if (ret) { + aw_dev_err(aw_dev->dev, "get f0 failed!"); + return ret; + } + sum_f0 += f0[i]; + sum_q += q[i]; + usleep_range(AW_70000_US, AW_70000_US + 10); + } + f0[0] = sum_f0 / AW_CALI_READ_F0_Q_TIMES; + q[0] = sum_q / AW_CALI_READ_F0_Q_TIMES; + aw_dev->cali_desc.cali_f0 = f0[0]; + aw_dev->cali_desc.cali_q = q[0]; + aw_dev_dbg(aw_dev->dev, "cali f0 is %d, q is %d", + aw_dev->cali_desc.cali_f0, aw_dev->cali_desc.cali_q); + return 0; +} + + +static int aw_cali_svc_dev_cali_mode_en(struct aw_device *aw_dev, int type, bool is_enable, unsigned int flag) +{ + int ret; + + /* open cali mode */ + if (is_enable) { + aw882xx_dev_iv_forbidden_output(aw_dev, false); + + aw_cali_svc_set_cali_status(aw_dev, true); + + if (type == CALI_TYPE_RE) { + if (flag & CALI_OPS_HMUTE) { + ret = aw882xx_dsp_hmute_en(aw_dev, true); + if (ret < 0) + return ret; + } + ret = aw882xx_dsp_cali_en(aw_dev, MSG_CALI_RE_ENABLE_DATA); + if (ret < 0) + return ret; + } else { + if (flag & CALI_OPS_NOISE) { + ret = aw882xx_dsp_noise_en(aw_dev, true); + if (ret < 0) + return ret; + } + ret = aw882xx_dsp_cali_en(aw_dev, MSG_CALI_F0_ENABLE_DATA); + if (ret < 0) + return ret; + } + } else { + aw882xx_dsp_cali_en(aw_dev, MSG_CALI_DISABLE_DATA); + + if (type == CALI_TYPE_RE) { + /*close mute*/ + if (flag & CALI_OPS_HMUTE) + aw882xx_dsp_hmute_en(aw_dev, false); + } else { + /*close mute*/ + if (flag & CALI_OPS_NOISE) + aw882xx_dsp_noise_en(aw_dev, false); + } + + /*close cali mode*/ + aw_cali_svc_set_cali_status(aw_dev, false); + + aw882xx_dev_iv_forbidden_output(aw_dev, true); + } + return 0; +} + +static int aw_cali_svc_dev_cali_re(struct aw_device *aw_dev, unsigned int flag) +{ + int ret; + + aw_cali_svc_run_mute(aw_dev, CALI_RESULT_NORMAL); + + ret = aw_cali_svc_dev_cali_mode_en(aw_dev, CALI_TYPE_RE, true, flag); + if (ret < 0) + goto exit; + + /*wait time*/ + msleep(g_cali_re_time); + + /*dev get echo cali re*/ + ret = aw_cali_svc_dev_get_re(aw_dev); +exit: + aw_cali_svc_dev_cali_mode_en(aw_dev, CALI_TYPE_RE, false, flag); + return ret; +} + +static int aw_cali_svc_devs_get_cali_cali_data(struct list_head *dev_list, + unsigned int data_type) +{ + int ret = -1; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (data_type == CALI_DATA_RE) { + ret = aw_cali_svc_dev_get_re(local_dev); + } else if (data_type == CALI_DATA_F0) { + ret = aw_cali_svc_dev_get_f0(local_dev); + } else if (data_type == CALI_DATA_F0_Q) { + ret = aw_cali_svc_dev_get_f0_q(local_dev); + } else { + aw_dev_err(local_dev->dev, "unsupport cali data type :%d", data_type); + return -EINVAL; + } + if (ret < 0) { + aw_dev_err(local_dev->dev, "get cali data type[%d] failed", data_type); + return ret; + } + } + + return ret; +} + +static int aw_cali_svc_devs_cali_mode_enable(struct list_head *dev_list, + int type, unsigned int flag, + bool is_enable) +{ + int ret = -1; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (is_enable) + aw_cali_svc_run_mute(local_dev, CALI_RESULT_NORMAL); + ret = aw_cali_svc_dev_cali_mode_en(local_dev, type, is_enable, flag); + if (ret < 0) + return ret; + if (!is_enable && (type == CALI_TYPE_F0)) + aw_cali_svc_run_mute(local_dev, local_dev->cali_desc.cali_result); + } + + return ret; +} + +static int aw_cali_svc_devs_cali_re(struct aw_device *aw_dev, unsigned int flag) +{ + int ret; + struct list_head *dev_list = NULL; + + aw_dev_info(aw_dev->dev, "enter"); + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, " get dev list failed"); + return ret; + } + + ret = aw_cali_svc_devs_cali_mode_enable(dev_list, CALI_TYPE_RE, flag, true); + if (ret < 0) + goto exit; + + msleep(g_cali_re_time); + + ret = aw_cali_svc_devs_get_cali_cali_data(dev_list, CALI_DATA_RE); +exit: + aw_cali_svc_devs_cali_mode_enable(dev_list, CALI_TYPE_RE, flag, false); + return ret; +} + + +static int aw_cali_svc_cali_re(struct aw_device *aw_dev, bool is_single, unsigned int flag) +{ + if (is_single) + return aw_cali_svc_dev_cali_re(aw_dev, flag); + else + return aw_cali_svc_devs_cali_re(aw_dev, flag); + return 0; +} + +static int aw_cali_svc_dev_cali_f0(struct aw_device *aw_dev, unsigned int flag) +{ + int ret; + + aw_cali_svc_run_mute(aw_dev, CALI_RESULT_NORMAL); + + ret = aw_cali_svc_dev_cali_mode_en(aw_dev, CALI_TYPE_F0, true, flag); + if (ret < 0) + goto exit; + + /*wait time*/ + msleep(5 * 1000); + + /*dev get cali f0*/ + ret = aw_cali_svc_dev_get_f0(aw_dev); +exit: + aw_cali_svc_dev_cali_mode_en(aw_dev, CALI_TYPE_F0, false, flag); + aw_cali_svc_run_mute(aw_dev, aw_dev->cali_desc.cali_result); + return ret; +} + +static int aw_cali_svc_devs_cali_f0(struct aw_device *aw_dev, unsigned int flag) +{ + int ret; + struct list_head *dev_list = NULL; + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, " get dev list failed"); + return ret; + } + + ret = aw_cali_svc_devs_cali_mode_enable(dev_list, CALI_TYPE_F0, flag, true); + if (ret < 0) + goto exit; + + /*wait time*/ + msleep(5 * 1000); + + ret = aw_cali_svc_devs_get_cali_cali_data(dev_list, CALI_DATA_F0); +exit: + aw_cali_svc_devs_cali_mode_enable(dev_list, CALI_TYPE_F0, flag, false); + return ret; +} + +static int aw_cali_svc_cali_f0(struct aw_device *aw_dev, bool is_single, unsigned int flag) +{ + if (is_single) + return aw_cali_svc_dev_cali_f0(aw_dev, flag); + else + return aw_cali_svc_devs_cali_f0(aw_dev, flag); + return 0; +} + +static int aw_cali_svc_dev_cali_f0_q(struct aw_device *aw_dev, unsigned int flag) +{ + int ret; + + aw_cali_svc_run_mute(aw_dev, CALI_RESULT_NORMAL); + + ret = aw_cali_svc_dev_cali_mode_en(aw_dev, CALI_TYPE_F0, true, flag); + if (ret < 0) + goto exit; + + + /*wait time*/ + msleep(5 * 1000); + + /*dev get cali f0 q*/ + ret = aw_cali_svc_dev_get_f0_q(aw_dev); +exit: + aw_cali_svc_dev_cali_mode_en(aw_dev, CALI_TYPE_F0, false, flag); + aw_cali_svc_run_mute(aw_dev, aw_dev->cali_desc.cali_result); + return ret; + +} + +static int aw_cali_svc_devs_cali_f0_q(struct aw_device *aw_dev, unsigned int flag) +{ + int ret; + struct list_head *dev_list = NULL; + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed "); + return ret; + } + + ret = aw_cali_svc_devs_cali_mode_enable(dev_list, CALI_TYPE_F0, flag, true); + if (ret < 0) + goto exit; + + /*wait time*/ + msleep(5 * 1000); + + /*dev get cali f0 q*/ + ret = aw_cali_svc_devs_get_cali_cali_data(dev_list, CALI_DATA_F0_Q); +exit: + aw_cali_svc_devs_cali_mode_enable(dev_list, CALI_TYPE_F0, flag, false); + return ret; +} + +static int aw_cali_svc_cali_f0_q(struct aw_device *aw_dev, bool is_single, unsigned int flag) +{ + if (is_single) + return aw_cali_svc_dev_cali_f0_q(aw_dev, flag); + else + return aw_cali_svc_devs_cali_f0_q(aw_dev, flag); + + return 0; +} + +static int aw_cali_svc_cali_re_f0(struct aw_device *aw_dev, bool is_single, unsigned int flag) +{ + int ret; + + ret = aw_cali_svc_cali_re(aw_dev, is_single, flag); + if (ret) + return ret; + + ret = aw_cali_svc_cali_f0(aw_dev, is_single, flag); + if (ret) + return ret; + + return 0; +} + +static int aw_cali_svc_cali_re_f0_q(struct aw_device *aw_dev, bool is_single, unsigned int flag) +{ + int ret; + + ret = aw_cali_svc_cali_re(aw_dev, is_single, flag); + if (ret) + return ret; + + ret = aw_cali_svc_cali_f0_q(aw_dev, is_single, flag); + if (ret) + return ret; + + return 0; +} + +static int aw_cali_svc_cali_cmd(struct aw_device *aw_dev, int cali_cmd, bool is_single, unsigned int flag) +{ + switch (cali_cmd) { + case AW_CALI_CMD_RE: + return aw_cali_svc_cali_re(aw_dev, is_single, flag); + case AW_CALI_CMD_F0: + return aw_cali_svc_cali_f0(aw_dev, is_single, flag); + case AW_CALI_CMD_F0_Q: + return aw_cali_svc_cali_f0_q(aw_dev, is_single, flag); + case AW_CALI_CMD_RE_F0: + return aw_cali_svc_cali_re_f0(aw_dev, is_single, flag); + case AW_CALI_CMD_RE_F0_Q: + return aw_cali_svc_cali_re_f0_q(aw_dev, is_single, flag); + default: + aw_dev_err(aw_dev->dev, "unsupported cmd %d", cali_cmd); + return -EINVAL; + } + return 0; +} + +static int aw_cali_svc_get_devs_cali_re(struct aw_device *aw_dev, int32_t *re_buf, int num) +{ + int ret, cnt = 0; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + /* get dev list */ + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed"); + return ret; + } + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel < num) { + re_buf[local_dev->channel] = local_dev->cali_desc.cali_re; + cnt++; + } else { + aw_dev_err(aw_dev->dev, "channel num[%d] overflow buf num[%d]", + local_dev->channel, num); + return -EINVAL; + } + } + + return cnt; +} + +static int aw_cali_svc_get_devs_r0(struct aw_device *aw_dev, int32_t *re_buf, int num) +{ + int ret, cnt = 0; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + /* get dev list */ + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed"); + return ret; + } + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel < num) { + ret = aw882xx_dsp_read_r0(local_dev, &re_buf[local_dev->channel]); + if (ret) { + aw_dev_err(local_dev->dev, "get re failed!"); + return ret; + } + cnt++; + } else { + aw_dev_err(aw_dev->dev, "channel num[%d] overflow buf num[%d] ", + local_dev->channel, num); + } + } + return cnt; +} + +static int aw_cali_svc_get_devs_te(struct aw_device *aw_dev, int32_t *te_buf, int num) +{ + int ret, cnt = 0; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + /* get dev list */ + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed"); + return ret; + } + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel < num) { + ret = aw882xx_dsp_read_te(local_dev, &te_buf[local_dev->channel]); + if (ret) { + aw_dev_err(local_dev->dev, "get re failed!"); + return ret; + } + cnt++; + } else { + aw_dev_err(aw_dev->dev, "channel num[%d] overflow buf num[%d]", + local_dev->channel, num); + } + } + + return cnt; +} + +static int aw_cali_svc_get_devs_st(struct aw_device *aw_dev, int32_t *st_buf, int num) +{ + int ret, cnt = 0; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + /*get dev list*/ + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed"); + return ret; + } + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel < num) { + ret = aw882xx_dsp_read_st(local_dev, &st_buf[local_dev->channel << 1], &st_buf[(local_dev->channel << 1) + 1]); + if (ret) { + aw_dev_err(local_dev->dev, "get re failed!"); + return ret; + } + cnt++; + } else { + aw_dev_err(aw_dev->dev, "channel num[%d] overflow buf num[%d]", + local_dev->channel, num); + } + } + return cnt; +} + +static int aw_cali_svc_get_devs_cali_f0(struct aw_device *aw_dev, int32_t *f0_buf, int num) +{ + int ret, cnt = 0; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + /*get dev list*/ + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed"); + return ret; + } + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel < num) { + f0_buf[local_dev->channel] = local_dev->cali_desc.cali_f0; + cnt++; + } else { + aw_dev_err(aw_dev->dev, "channel num[%d] overflow buf num[%d]", + local_dev->channel, num); + } + } + + return cnt; +} + +static int aw_cali_svc_get_devs_f0(struct aw_device *aw_dev, int32_t *f0_buf, int num) +{ + int ret, cnt = 0; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + /* get dev list */ + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed"); + return ret; + } + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel < num) { + ret = aw882xx_dsp_read_f0(local_dev, &f0_buf[local_dev->channel]); + if (ret) { + aw_dev_err(local_dev->dev, "get re failed!"); + return ret; + } + cnt++; + } else { + aw_dev_err(aw_dev->dev, "channel num[%d] overflow buf num[%d]", + local_dev->channel, num); + } + } + return cnt; +} + +static int aw_cali_svc_get_devs_cali_f0_q(struct aw_device *aw_dev, + int32_t *f0_buf, int32_t *q_buf, int num) +{ + int ret, cnt = 0; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + /*get dev list*/ + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed"); + return ret; + } + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel < num) { + f0_buf[local_dev->channel] = local_dev->cali_desc.cali_f0; + q_buf[local_dev->channel] = local_dev->cali_desc.cali_q; + cnt++; + } else { + aw_dev_err(aw_dev->dev, "channel num[%d] overflow buf num[%d]", + local_dev->channel, num); + } + } + return cnt; +} + +static int aw_cali_svc_set_devs_re_str(struct aw_device *aw_dev, const char *re_str) +{ + int ret, cnt = 0; + struct list_head *dev_list, *pos = NULL; + struct aw_device *local_dev = NULL; + int re_data[AW_DEV_CH_MAX] = {0}; + + /* get dev list */ + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed"); + return ret; + } + + ret = sscanf(re_str, "pri_l:%d pri_r:%d sec_l:%d sec_r:%d tert_l:%d tert_r:%d quat_l:%d quat_r:%d", + &re_data[AW_DEV_CH_PRI_L], + &re_data[AW_DEV_CH_PRI_R], + &re_data[AW_DEV_CH_SEC_L], + &re_data[AW_DEV_CH_SEC_R], + &re_data[AW_DEV_CH_TERT_L], + &re_data[AW_DEV_CH_TERT_R], + &re_data[AW_DEV_CH_QUAT_L], + &re_data[AW_DEV_CH_QUAT_R]); + + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "unsupport str[%s]", re_str); + return -EINVAL; + } + + aw_dev_dbg(aw_dev->dev, "pri_l:%d pri_r:%d sec_l:%d sec_r:%d tert_l:%d tert_r:%d quat_l:%d quat_r:%d", + re_data[AW_DEV_CH_PRI_L], + re_data[AW_DEV_CH_PRI_R], + re_data[AW_DEV_CH_SEC_L], + re_data[AW_DEV_CH_SEC_R], + re_data[AW_DEV_CH_TERT_L], + re_data[AW_DEV_CH_TERT_R], + re_data[AW_DEV_CH_QUAT_L], + re_data[AW_DEV_CH_QUAT_R]); + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel < AW_DEV_CH_MAX) { + ret = aw_cali_store_cali_re(local_dev, re_data[local_dev->channel]); + if (ret < 0) + return ret; + cnt++; + } + } + return cnt; + +} + +static int aw_cali_svc_get_cmd_form_str(struct aw_device *aw_dev, const char *buf) +{ + int i; + + for (i = 0; i < CALI_STR_MAX; i++) { + if (!strncmp(cali_str[i], buf, strlen(cali_str[i]))) + break; + + } + + if (i == CALI_STR_MAX) { + aw_dev_err(aw_dev->dev, "supported cmd [%s]!", buf); + return -EINVAL; + } + + aw_dev_info(aw_dev->dev, "find str [%s]", cali_str[i]); + return i; +} + +/*********************************aw_cali_sevice*********************************************************/ + + +/*****************************attr start***************************************************/ +static ssize_t cali_time_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + uint32_t time; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + + ret = kstrtoint(buf, 0, &time); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "read buf %s failed\n", + buf); + return ret; + } + + if (time < 400) { + aw_dev_err(aw_dev->dev, "time:%d is too short, no set", + time); + return -EINVAL; + } + + g_cali_re_time = time; + aw_dev_dbg(aw_dev->dev, "time:%d", time); + + return count; +} + +static ssize_t cali_time_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, + "time: %d\n", g_cali_re_time); + + return len; +} + +static ssize_t cali_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + + ret = aw_cali_svc_get_cmd_form_str(aw_dev, buf); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "supported cmd [%s]!", buf); + return -EPERM; + } + + switch (ret) { + case CALI_STR_CALI_RE_F0: + aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_RE_F0, + is_single_cali, CALI_OPS_HMUTE|CALI_OPS_NOISE); + return count; + case CALI_STR_CALI_RE: + aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_RE, + is_single_cali, CALI_OPS_HMUTE); + return count; + case CALI_STR_CALI_F0: + aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_F0, + is_single_cali, CALI_OPS_NOISE); + return count; + default: + aw_dev_err(aw_dev->dev, "supported cmd [%s]!", buf); + return -EPERM; + } +} + +static ssize_t cali_re_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + int data = 0; + + if (is_single_cali) { + ret = kstrtoint(buf, 0, &data); + if (ret < 0) { + aw_dev_err(aw882xx->dev, " read buf %s failed", buf); + return ret; + } + ret = aw_cali_store_cali_re(aw_dev, data); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "set re %d failed", data); + return -EPERM; + } + } else { + ret = aw_cali_svc_set_devs_re_str(aw_dev, buf); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "set re str %s failed", buf); + return -EPERM; + } + } + + return count; +} + +static ssize_t cali_re_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret, i; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + ssize_t len = 0; + int32_t cali_re[AW_DEV_CH_MAX] = {0}; + + ret = aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_RE, is_single_cali, CALI_OPS_HMUTE); + if (ret < 0) { + len += snprintf(buf+len, PAGE_SIZE-len, "cali Re cmd failed\n"); + return len; + } + + if (is_single_cali) { + len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw_dev->cali_desc.cali_re); + } else { + ret = aw_cali_svc_get_devs_cali_re(aw_dev, cali_re, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get re failed "); + len += snprintf(buf+len, PAGE_SIZE-len, "get re failed\n"); + } else { + for (i = 0; i < ret; i++) + len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d mOhms ", ch_name[i], cali_re[i]); + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + } + } + + return len; +} + +static ssize_t cali_f0_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + + aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_F0, is_single_cali, CALI_OPS_NOISE); + return count; +} + +static ssize_t cali_f0_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret, i; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + ssize_t len = 0; + int32_t cali_f0[AW_DEV_CH_MAX] = {0}; + + ret = aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_F0, is_single_cali, CALI_OPS_NOISE); + if (ret < 0) { + len += snprintf(buf+len, PAGE_SIZE-len, "cali f0 cmd failed\n"); + return len; + } + + if (is_single_cali) { + len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw_dev->cali_desc.cali_f0); + } else { + ret = aw_cali_svc_get_devs_cali_f0(aw_dev, cali_f0, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get f0 failed "); + len += snprintf(buf+len, PAGE_SIZE-len, "get f0 failed\n"); + } else { + for (i = 0; i < ret; i++) + len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d ", ch_name[i], cali_f0[i]); + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + } + } + + return len; +} + +static ssize_t re_show_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret, i; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + ssize_t len = 0; + int32_t cali_re[AW_DEV_CH_MAX] = {0}; + + if (is_single_cali) { + len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw_dev->cali_desc.cali_re); + } else { + ret = aw_cali_svc_get_devs_cali_re(aw_dev, cali_re, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get re failed "); + } else { + for (i = 0; i < ret; i++) + len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d mOhms ", ch_name[i], cali_re[i]); + } + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + } + + return len; +} + +static ssize_t f0_show_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret, i; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + ssize_t len = 0; + int32_t cali_f0[AW_DEV_CH_MAX] = {0}; + + if (is_single_cali) { + len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw_dev->cali_desc.cali_f0); + } else { + ret = aw_cali_svc_get_devs_cali_f0(aw_dev, cali_f0, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get f0 failed"); + } else { + for (i = 0; i < ret; i++) + len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d", ch_name[i], cali_f0[i]); + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + } + } + + return len; +} + +static ssize_t re_range_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + uint32_t range_buf[RE_RANGE_NUM] = { 0 }; + + aw_cali_svc_get_dev_re_range(aw_dev, range_buf); + + len += snprintf(buf + len, PAGE_SIZE - len, + "re_min value: [%d] mOhms\n", range_buf[RE_MIN_FLAG]); + len += snprintf(buf + len, PAGE_SIZE - len, + "re_max value: [%d] mOhms\n", range_buf[RE_MAX_FLAG]); + + return len; +} + +/*set cali time*/ +static DEVICE_ATTR_RW(cali_time); +/*start cali*/ +static DEVICE_ATTR_WO(cali); +/*cali re*/ +static DEVICE_ATTR_RW(cali_re); +/*cali_f0*/ +static DEVICE_ATTR_RW(cali_f0); +/*show cali_re*/ +static DEVICE_ATTR_RO(re_show); +/*show cali_f0*/ +static DEVICE_ATTR_RO(f0_show); +/*show re_range*/ +static DEVICE_ATTR_RO(re_range); + +static struct attribute *aw_cali_attr[] = { + &dev_attr_cali_time.attr, + &dev_attr_cali.attr, + &dev_attr_cali_re.attr, + &dev_attr_cali_f0.attr, + &dev_attr_re_show.attr, + &dev_attr_f0_show.attr, + &dev_attr_re_range.attr, + NULL +}; + +static struct attribute_group aw_cali_attr_group = { + .attrs = aw_cali_attr +}; + +static void aw_cali_attr_init(struct aw_device *aw_dev) +{ + int ret; + + aw_dev_info(aw_dev->dev, "enter"); + + ret = sysfs_create_group(&aw_dev->dev->kobj, &aw_cali_attr_group); + if (ret < 0) + aw_dev_info(aw_dev->dev, "error creating sysfs cali attr files"); +} + +static void aw_cali_attr_deinit(struct aw_device *aw_dev) +{ + sysfs_remove_group(&aw_dev->dev->kobj, &aw_cali_attr_group); + aw_dev_info(aw_dev->dev, "attr files deinit"); +} + +/*****************************attr end***************************************************/ + +/*****************************class node******************************************************/ +static ssize_t aw_cali_class_time_show(struct class *class, struct class_attribute *attr, char *buf) +{ + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, + "time: %d\n", g_cali_re_time); + + return len; +} + +static ssize_t aw_cali_class_time_store(struct class *class, + struct class_attribute *attr, const char *buf, size_t len) +{ + int ret; + uint32_t time; + + ret = kstrtoint(buf, 0, &time); + if (ret < 0) { + aw_pr_err("read buf %s failed", buf); + return ret; + } + + if (time < 400) { + aw_pr_err("time:%d is too short, no set", time); + return -EINVAL; + } + + g_cali_re_time = time; + aw_pr_dbg("time:%d", time); + + return len; +} + +static ssize_t aw_cali_class_cali_re_show(struct class *class, struct class_attribute *attr, char *buf) +{ + int ret, i; + struct list_head *dev_list = NULL; + struct aw_device *local_dev = NULL; + ssize_t len = 0; + int32_t cali_re[AW_DEV_CH_MAX] = {0}; + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_pr_err("get dev list failed"); + return ret; + } + + local_dev = list_first_entry(dev_list, struct aw_device, list_node); + + ret = aw_cali_svc_cali_cmd(local_dev, AW_CALI_CMD_RE, false, CALI_OPS_HMUTE); + if (ret < 0) { + len += snprintf(buf+len, PAGE_SIZE-len, "cali Re cmd failed\n"); + return len; + } + + ret = aw_cali_svc_get_devs_cali_re(local_dev, cali_re, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(local_dev->dev, "get re failed"); + len += snprintf(buf+len, PAGE_SIZE-len, "get re failed\n"); + } else { + for (i = 0; i < ret; i++) + len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d mOhms ", ch_name[i], cali_re[i]); + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + } + + return len; +} + +static ssize_t aw_cali_class_cali_re_store(struct class *class, + struct class_attribute *attr, const char *buf, size_t len) +{ + int ret; + struct list_head *dev_list = NULL; + struct aw_device *local_dev = NULL; + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_pr_err("get dev list failed"); + return ret; + } + + local_dev = list_first_entry(dev_list, struct aw_device, list_node); + + ret = aw_cali_svc_set_devs_re_str(local_dev, buf); + if (ret <= 0) { + aw_dev_err(local_dev->dev, "set re str %s failed", buf); + return -EPERM; + } + + return len; +} + +static ssize_t aw_cali_class_cali_f0_show(struct class *class, struct class_attribute *attr, char *buf) +{ + int ret, i; + struct list_head *dev_list = NULL; + struct aw_device *local_dev = NULL; + ssize_t len = 0; + int32_t cali_f0[AW_DEV_CH_MAX] = {0}; + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_pr_err("get dev list failed"); + return ret; + } + + local_dev = list_first_entry(dev_list, struct aw_device, list_node); + + ret = aw_cali_svc_cali_cmd(local_dev, AW_CALI_CMD_F0, false, CALI_OPS_NOISE); + if (ret < 0) { + len += snprintf(buf+len, PAGE_SIZE-len, "cali f0 cmd failed\n"); + return len; + } + + ret = aw_cali_svc_get_devs_cali_f0(local_dev, cali_f0, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(local_dev->dev, "get f0 failed "); + len += snprintf(buf+len, PAGE_SIZE-len, "get f0 failed\n"); + } else { + for (i = 0; i < ret; i++) + len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d ", ch_name[i], cali_f0[i]); + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + } + + return len; +} + +static ssize_t aw_cali_class_cali_f0_store(struct class *class, + struct class_attribute *attr, const char *buf, size_t len) +{ + int ret; + struct list_head *dev_list = NULL; + struct aw_device *local_dev = NULL; + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_pr_err("get dev list failed"); + return ret; + } + + local_dev = list_first_entry(dev_list, struct aw_device, list_node); + + aw_cali_svc_cali_cmd(local_dev, AW_CALI_CMD_F0, false, CALI_OPS_NOISE); + + return len; +} + +static ssize_t aw_cali_class_f0_show(struct class *class, struct class_attribute *attr, char *buf) +{ + int ret, i; + struct list_head *dev_list = NULL; + struct aw_device *local_dev = NULL; + ssize_t len = 0; + int32_t cali_f0[AW_DEV_CH_MAX] = {0}; + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_pr_err("get dev list failed"); + return ret; + } + + local_dev = list_first_entry(dev_list, struct aw_device, list_node); + + ret = aw_cali_svc_get_devs_cali_f0(local_dev, cali_f0, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(local_dev->dev, "get re failed"); + } else { + for (i = 0; i < ret; i++) + len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d", ch_name[i], cali_f0[i]); + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + } + + return len; +} + +static ssize_t aw_cali_class_re_show(struct class *class, struct class_attribute *attr, char *buf) +{ + int ret, i; + struct list_head *dev_list = NULL; + struct aw_device *local_dev = NULL; + ssize_t len = 0; + int32_t cali_re[AW_DEV_CH_MAX] = {0}; + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_pr_err("get dev list failed"); + return ret; + } + + local_dev = list_first_entry(dev_list, struct aw_device, list_node); + + ret = aw_cali_svc_get_devs_cali_re(local_dev, cali_re, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(local_dev->dev, "get re failed"); + } else { + for (i = 0; i < ret; i++) + len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d mOhms", ch_name[i], cali_re[i]); + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + } + + return len; +} + +static ssize_t aw_class_re_range_show(struct class *class, struct class_attribute *attr, char *buf) +{ + int ret, i; + ssize_t len = 0; + struct list_head *dev_list = NULL; + struct aw_device *local_dev = NULL; + uint32_t re_value[AW_DEV_RE_RANGE] = { 0 }; + + aw_pr_info("enter"); + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret < 0) { + aw_pr_err("get dev list failed"); + return ret; + } + + local_dev = list_first_entry(dev_list, struct aw_device, list_node); + ret = aw_cali_svc_get_devs_re_range(local_dev, re_value, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(local_dev->dev, "get re range failed"); + return -EINVAL; + } + + for (i = 0; i < ret; i++) { + len += snprintf(buf+len, PAGE_SIZE-len, "%s:re_min:%d mOhms re_max:%d mOhms ", + ch_name[i], re_value[RE_MIN_FLAG + i * RE_RANGE_NUM], + re_value[RE_MAX_FLAG + i * RE_RANGE_NUM]); + } + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + + return len; +} + +static struct class_attribute class_attr_cali_time = + __ATTR(cali_time, 0644, + aw_cali_class_time_show, aw_cali_class_time_store); + +static struct class_attribute class_attr_re25_calib = + __ATTR(re25_calib, 0644, + aw_cali_class_cali_re_show, aw_cali_class_cali_re_store); + +static struct class_attribute class_attr_f0_calib = + __ATTR(f0_calib, 0644, + aw_cali_class_cali_f0_show, aw_cali_class_cali_f0_store); + +static struct class_attribute class_attr_re_show = + __ATTR(re_show, 0444, + aw_cali_class_re_show, NULL); + +static struct class_attribute class_attr_f0_show = + __ATTR(f0_show, 0444, + aw_cali_class_f0_show, NULL); + +static struct class_attribute class_att_re_range = + __ATTR(re_range, 0444, + aw_class_re_range_show, NULL); + +static struct class aw_cali_class = { + .name = "smartpa", + .owner = THIS_MODULE, +}; + +static void aw_cali_class_attr_init(struct aw_device *aw_dev) +{ + int ret; + + if (aw_dev->channel != 0) { + aw_dev_info(aw_dev->dev, "class node already register"); + return; + } + + ret = class_register(&aw_cali_class); + if (ret < 0) { + aw_dev_info(aw_dev->dev, "error creating class node"); + return; + } + ret = class_create_file(&aw_cali_class, &class_attr_re25_calib); + if (ret) + aw_dev_info(aw_dev->dev, "creat class_attr_re25_calib fail"); + + ret = class_create_file(&aw_cali_class, &class_attr_f0_calib); + if (ret) + aw_dev_info(aw_dev->dev, "creat class_attr_re25_calib fail"); + + ret = class_create_file(&aw_cali_class, &class_attr_cali_time); + if (ret) + aw_dev_info(aw_dev->dev, "creat class_attr_cali_time fail"); + + ret = class_create_file(&aw_cali_class, &class_attr_re_show); + if (ret) + aw_dev_info(aw_dev->dev, "creat class_attr_re_show fail"); + + ret = class_create_file(&aw_cali_class, &class_attr_f0_show); + if (ret) + aw_dev_info(aw_dev->dev, "creat class_attr_f0_show fail"); + + ret = class_create_file(&aw_cali_class, &class_att_re_range); + if (ret) + aw_dev_err(aw_dev->dev, "creat class_att_re_range fail"); +} + +static void aw_cali_class_attr_deinit(struct aw_device *aw_dev) +{ + class_remove_file(&aw_cali_class, &class_att_re_range); + class_remove_file(&aw_cali_class, &class_attr_re25_calib); + class_remove_file(&aw_cali_class, &class_attr_f0_calib); + class_remove_file(&aw_cali_class, &class_attr_cali_time); + class_remove_file(&aw_cali_class, &class_attr_re_show); + class_remove_file(&aw_cali_class, &class_attr_f0_show); + + class_unregister(&aw_cali_class); + aw_dev_info(aw_dev->dev, "unregister class node"); +} +/*****************************class node******************************************************/ + +/*****************************misc node******************************************************/ +static int aw_cali_misc_open(struct inode *inode, struct file *file) +{ + int ret; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_pr_err("get dev list failed"); + file->private_data = NULL; + return -EINVAL; + } + + /* find select dev */ + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel == g_dev_select) + break; + + } + + if (local_dev == NULL) { + aw_pr_err("can't find dev num %d", g_dev_select); + return -EINVAL; + } + + /* cannot find sel dev, use list first dev */ + if (local_dev->channel != g_dev_select) { + local_dev = list_first_entry(dev_list, struct aw_device, list_node); + aw_dev_dbg(local_dev->dev, "can not find dev num %d, use default", g_dev_select); + } + + file->private_data = (void *)local_dev; + + aw_dev_dbg(local_dev->dev, "misc open success"); + return 0; +} + +static int aw_cali_misc_release(struct inode *inode, struct file *file) +{ + file->private_data = (void *)NULL; + + aw_pr_dbg("misc release success"); + return 0; +} + +static int aw_cali_misc_params_ptr(struct aw_device *aw_dev, struct ptr_params_data *p_params) +{ + int ret = 0; + char *p_data = NULL; + + if (p_params->data == NULL || (!p_params->len)) { + aw_dev_err(aw_dev->dev, "p_params error"); + ret = -EFAULT; + return ret; + } + + p_data = kzalloc(p_params->len, GFP_KERNEL); + if (p_data == NULL) { + ret = -ENOMEM; + goto exit; + } + + if (copy_from_user(p_data, + (void __user *)p_params->data, + p_params->len)) { + ret = -EFAULT; + goto exit; + } + + ret = aw882xx_dsp_write_params(aw_dev, p_data, p_params->len); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "write params failed "); + ret = -EFAULT; + goto exit; + } + +exit: + if (p_data != NULL) { + kfree(p_data); + p_data = NULL; + } + + return ret; +} + +static int aw_cali_misc_ops_write(struct aw_device *aw_dev, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + unsigned int data_len = _IOC_SIZE(cmd); + char *data_ptr = NULL; + int32_t data = 0; + + data_ptr = kzalloc(data_len, GFP_KERNEL); + if (!data_ptr) + return -ENOMEM; + + + if (copy_from_user(data_ptr, (void __user *)arg, data_len)) { + ret = -EFAULT; + goto exit; + } + + switch (cmd) { + case AW_IOCTL_ENABLE_CALI: { + if (aw_dev->cali_desc.cali_check_st) { + if (data_ptr[0]) + aw_cali_svc_run_mute(aw_dev, CALI_RESULT_NORMAL); + else + aw_cali_svc_run_mute(aw_dev, aw_dev->cali_desc.cali_result); + } + aw_cali_svc_set_cali_status(aw_dev, data_ptr[0]); + } break; + case AW_IOCTL_SET_CALI_CFG: { + ret = aw882xx_dsp_write_cali_cfg(aw_dev, data_ptr, data_len); + } break; + case AW_IOCTL_SET_NOISE: { + data = *(int32_t *)data_ptr; + ret = aw882xx_dsp_noise_en(aw_dev, data); + } break; + case AW_IOCTL_SET_VMAX: { + ret = aw882xx_dsp_write_vmax(aw_dev, data_ptr, data_len); + } break; + case AW_IOCTL_SET_PARAM: { + ret = aw882xx_dsp_write_params(aw_dev, data_ptr, data_len); + } break; + case AW_IOCTL_SET_PTR_PARAM_NUM: { + ret = aw_cali_misc_params_ptr(aw_dev, (struct ptr_params_data *)data_ptr); + } break; + case AW_IOCTL_SET_CALI_RE: { + ret = aw_cali_store_cali_re(aw_dev, *((int32_t *)data_ptr)); + /*ret = aw882xx_dsp_write_cali_re(aw_dev, *(int32_t *)data_ptr);*/ + } break; + case AW_IOCTL_SET_DSP_HMUTE: { + data = *(int32_t *)data_ptr; + ret = aw882xx_dsp_hmute_en(aw_dev, data); + } break; + case AW_IOCTL_SET_CALI_CFG_FLAG: { + data = *(int32_t *)data_ptr; + /*aw_cali_svc_set_cali_status(aw_dev, data);*/ + ret = aw882xx_dsp_cali_en(aw_dev, data); + } break; + default:{ + aw_dev_err(aw_dev->dev, "unsupported cmd %d", cmd); + ret = -EINVAL; + } break; + } + +exit: + kfree(data_ptr); + return ret; +} + +static int aw_cali_misc_ops_read(struct aw_device *aw_dev, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + int16_t data_len = _IOC_SIZE(cmd); + char *data_ptr = NULL; + int32_t *data_32_ptr = NULL; + + data_ptr = kzalloc(data_len, GFP_KERNEL); + if (!data_ptr) + return -ENOMEM; + + + switch (cmd) { + case AW_IOCTL_GET_CALI_CFG: { + ret = aw882xx_dsp_read_cali_cfg(aw_dev, data_ptr, data_len); + } break; + case AW_IOCTL_GET_CALI_DATA: { + ret = aw882xx_dsp_read_cali_data(aw_dev, data_ptr, data_len); + } break; + case AW_IOCTL_GET_F0: { + data_32_ptr = (int32_t *)data_ptr; + ret = aw882xx_dsp_read_f0(aw_dev, data_32_ptr); + } break; + case AW_IOCTL_GET_CALI_RE: { + data_32_ptr = (int32_t *)data_ptr; + ret = aw882xx_dsp_read_cali_re(aw_dev, data_32_ptr); + } break; + case AW_IOCTL_GET_VMAX: { + ret = aw882xx_dsp_read_vmax(aw_dev, data_ptr, data_len); + } break; + case AW_IOCTL_GET_F0_Q: { + data_32_ptr = (int32_t *)data_ptr; + ret = aw882xx_dsp_read_f0_q(aw_dev, &data_32_ptr[0], &data_32_ptr[1]); + } break; + case AW_IOCTL_GET_RE_RANGE: { + data_32_ptr = (uint32_t *)data_ptr; + ret = aw_cali_svc_get_dev_re_range(aw_dev, data_32_ptr); + } break; + default:{ + aw_dev_err(aw_dev->dev, "unsupported cmd %d", cmd); + ret = -EINVAL; + } break; + } + + if (copy_to_user((void __user *)arg, + data_ptr, data_len)) { + ret = -EFAULT; + } + + kfree(data_ptr); + return ret; +} + +static int aw_cali_misc_read_dsp(struct aw_device *aw_dev, aw_ioctl_msg_t *msg) +{ + int ret; + char __user *user_data = (char __user *)msg->data_buf; + uint32_t dsp_msg_id = (uint32_t)msg->opcode_id; + int data_len = msg->data_len; + char *data_ptr = NULL; + + data_ptr = kzalloc(data_len, GFP_KERNEL); + if (!data_ptr) + return -ENOMEM; + + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, dsp_msg_id, data_ptr, data_len); + if (ret) { + aw_dev_err(aw_dev->dev, " write failed"); + goto exit; + } + + if (copy_to_user((void __user *)user_data, + data_ptr, data_len)) + ret = -EFAULT; +exit: + kfree(data_ptr); + return ret; +} + +static int aw_cali_misc_write_dsp(struct aw_device *aw_dev, aw_ioctl_msg_t *msg) +{ + int ret; + char __user *user_data = (char __user *)msg->data_buf; + uint32_t dsp_msg_id = (uint32_t)msg->opcode_id; + int data_len = msg->data_len; + char *data_ptr = NULL; + + data_ptr = kzalloc(data_len, GFP_KERNEL); + if (!data_ptr) + return -ENOMEM; + + + if (copy_from_user(data_ptr, (void __user *)user_data, data_len)) { + aw_dev_err(aw_dev->dev, "copy data failed"); + ret = -EFAULT; + goto exit; + } + + ret = aw882xx_dsp_write_dsp_msg(aw_dev, dsp_msg_id, data_ptr, data_len); + if (ret) + aw_dev_err(aw_dev->dev, "write failed"); + +exit: + kfree(data_ptr); + return ret; +} + + +static int aw_cali_misc_ops(struct aw_device *aw_dev, + unsigned int cmd, unsigned long arg); +static int aw_cali_misc_ops_msg(struct aw_device *aw_dev, unsigned long arg) +{ + aw_ioctl_msg_t ioctl_msg; + + if (copy_from_user(&ioctl_msg, (void __user *)arg, sizeof(aw_ioctl_msg_t))) + return -EFAULT; + + if (ioctl_msg.version != AW_IOCTL_MSG_VERSION) { + aw_dev_err(aw_dev->dev, "unsupported msg version %d", ioctl_msg.version); + return -EINVAL; + } + + switch (ioctl_msg.type) { + case AW_IOCTL_MSG_RD_DSP: + return aw_cali_misc_read_dsp(aw_dev, &ioctl_msg); + case AW_IOCTL_MSG_WR_DSP: + return aw_cali_misc_write_dsp(aw_dev, &ioctl_msg); + case AW_IOCTL_MSG_IOCTL: + return aw_cali_misc_ops(aw_dev, ioctl_msg.opcode_id, (unsigned long)ioctl_msg.data_buf); + default: + aw_dev_err(aw_dev->dev, "unsupported msg type %d", ioctl_msg.type); + return -EINVAL; + } +} + +static int aw_cali_misc_ops(struct aw_device *aw_dev, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + + switch (cmd) { + case AW_IOCTL_ENABLE_CALI: + case AW_IOCTL_SET_CALI_CFG: + case AW_IOCTL_SET_NOISE: + case AW_IOCTL_SET_VMAX: + case AW_IOCTL_SET_PARAM: + case AW_IOCTL_SET_PTR_PARAM_NUM: + case AW_IOCTL_SET_CALI_RE: + case AW_IOCTL_SET_DSP_HMUTE: + case AW_IOCTL_SET_CALI_CFG_FLAG: + ret = aw_cali_misc_ops_write(aw_dev, cmd, arg); + break; + case AW_IOCTL_GET_CALI_CFG: + case AW_IOCTL_GET_CALI_DATA: + case AW_IOCTL_GET_F0: + case AW_IOCTL_GET_CALI_RE: + case AW_IOCTL_GET_VMAX: + case AW_IOCTL_GET_F0_Q: + case AW_IOCTL_GET_RE_RANGE: + ret = aw_cali_misc_ops_read(aw_dev, cmd, arg); + break; + case AW_IOCTL_MSG: { + ret = aw_cali_misc_ops_msg(aw_dev, arg); + } break; + default: + aw_dev_err(aw_dev->dev, "unsupported cmd %d", cmd); + ret = -EINVAL; + break; + } + + return ret; +} + +static long aw_cali_misc_unlocked_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + struct aw_device *aw_dev = NULL; + + if (((_IOC_TYPE(cmd)) != (AW_IOCTL_MAGIC))) { + aw_pr_err("cmd magic err"); + return -EINVAL; + } + aw_dev = (struct aw_device *)file->private_data; + ret = aw_cali_misc_ops(aw_dev, cmd, arg); + if (ret) + return -EINVAL; + + return 0; +} + +#ifdef CONFIG_COMPAT +static long aw_cali_misc_compat_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + struct aw_device *aw_dev = NULL; + + if (((_IOC_TYPE(cmd)) != (AW_IOCTL_MAGIC))) { + aw_pr_err("cmd magic err"); + return -EINVAL; + } + aw_dev = (struct aw_device *)file->private_data; + ret = aw_cali_misc_ops(aw_dev, cmd, arg); + if (ret) + return -EINVAL; + + return 0; +} +#endif + +static ssize_t aw_cali_misc_read(struct file *filp, char __user *buf, size_t size, loff_t *pos) +{ + int i, ret; + int len = 0; + struct aw_device *aw_dev = (struct aw_device *)filp->private_data; + char local_buf[256] = { 0 }; + unsigned int dev_num; + int32_t temp_data[AW_DEV_CH_MAX << 1] = {0}; + int32_t temp_data1[AW_DEV_CH_MAX << 1] = {0}; + uint32_t re_value[AW_DEV_RE_RANGE] = { 0 }; + + aw_dev_info(aw_dev->dev, "enter"); + + if (*pos) { + *pos = 0; + return 0; + } + + switch (g_msic_wr_flag) { + case CALI_STR_SHOW_RE: { + ret = aw_cali_svc_get_devs_cali_re(aw_dev, temp_data, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get cali_re failed"); + return ret; + } + for (i = 0; i < ret; i++) + len += snprintf(local_buf+len, sizeof(local_buf)-len, + "%s:%d mOhms ", ch_name[i], temp_data[i]); + + len += snprintf(local_buf+len, sizeof(local_buf)-len, "\n"); + + } break; + case CALI_STR_SHOW_CALI_F0: { + ret = aw_cali_svc_get_devs_cali_f0(aw_dev, temp_data, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get cali f0 failed"); + return ret; + } + for (i = 0; i < ret; i++) + len += snprintf(local_buf+len, sizeof(local_buf)-len, + "%s:%d ", ch_name[i], temp_data[i]); + + len += snprintf(local_buf+len, sizeof(local_buf)-len, "\n"); + + } break; + case CALI_STR_SHOW_R0: { + ret = aw_cali_svc_get_devs_r0(aw_dev, temp_data, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get r0 failed"); + return ret; + } + for (i = 0; i < ret; i++) + len += snprintf(local_buf+len, sizeof(local_buf)-len, + "%s:%d mOhms ", ch_name[i], temp_data[i]); + len += snprintf(local_buf+len, sizeof(local_buf)-len, "\n"); + + } break; + case CALI_STR_SHOW_TE: { + ret = aw_cali_svc_get_devs_te(aw_dev, temp_data, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get te failed"); + return ret; + } + for (i = 0; i < ret; i++) + len += snprintf(local_buf+len, sizeof(local_buf)-len, + "%s:%d ", ch_name[i], temp_data[i]); + len += snprintf(local_buf+len, sizeof(local_buf)-len, "\n"); + + } break; + case CALI_STR_SHOW_ST: { + ret = aw_cali_svc_get_devs_st(aw_dev, temp_data, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get spkr status failed"); + return ret; + } + for (i = 0; i < ret; i++) { + len += snprintf(local_buf+len, sizeof(local_buf)-len, + "%s:R0 %d mOhms Te %d ", + ch_name[i], temp_data[i << 1], temp_data[(i << 1) + 1]); + } + len += snprintf(local_buf+len, sizeof(local_buf)-len, "\n"); + + } break; + case CALI_STR_SHOW_F0: { + ret = aw_cali_svc_get_devs_f0(aw_dev, temp_data, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get f0 failed"); + return ret; + } + for (i = 0; i < ret; i++) + len += snprintf(local_buf+len, sizeof(local_buf)-len, + "%s:%d ", ch_name[i], temp_data[i]); + + len += snprintf(local_buf+len, sizeof(local_buf) - len, "\n"); + + } break; + case CALI_STR_VER: { + if (aw_dev->ops.aw_get_version) { + len = aw_dev->ops.aw_get_version(local_buf, sizeof(local_buf)); + if (len < 0) { + aw_dev_err(aw_dev->dev, "get version failed"); + return -EINVAL; + } + len += snprintf(local_buf+len, sizeof(local_buf) - len, "\n"); + } else { + aw_dev_err(aw_dev->dev, "get version is NULL"); + return -EINVAL; + } + } break; + case CALI_STR_DEV_NUM: { + if (aw_dev->ops.aw_get_dev_num) { + dev_num = aw_dev->ops.aw_get_dev_num(); + len += snprintf(local_buf + len, sizeof(local_buf) - len, "dev_num:%d\n", dev_num); + } else { + aw_dev_err(aw_dev->dev, "get dev num is NULL"); + return -EINVAL; + } + break; + } + case CALI_STR_SHOW_F0_Q: { + ret = aw_cali_svc_get_devs_cali_f0_q(aw_dev, + temp_data, temp_data1, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get q f0 failed"); + return ret; + } + for (i = 0; i < ret; i++) + len += snprintf(local_buf + len, sizeof(local_buf)-len, + "%s:f0:%d q:%d", ch_name[i], temp_data[i], temp_data1[i]); + + len += snprintf(local_buf+len, sizeof(local_buf) - len, "\n"); + + } break; + case CALI_STR_SHOW_RE_RANGE: { + ret = aw_cali_svc_get_devs_re_range(aw_dev, re_value, AW_DEV_CH_MAX); + if (ret <= 0) { + aw_dev_err(aw_dev->dev, "get re range failed"); + return -EINVAL; + } + for (i = 0; i < ret; i++) + len += snprintf(local_buf + len, sizeof(local_buf) - len, + "%s:re_min:%d re_max:%d ", + ch_name[i], re_value[RE_MIN_FLAG + i * RE_RANGE_NUM], + re_value[RE_MAX_FLAG + i * RE_RANGE_NUM]); + + len += snprintf(local_buf + len, sizeof(local_buf) - len, "\n"); + + } break; + default: { + if (g_msic_wr_flag == CALI_STR_NONE) { + aw_dev_info(aw_dev->dev, "please write cmd first"); + return -EINVAL; + } + aw_dev_err(aw_dev->dev, "unsupported flag [%d]", g_msic_wr_flag); + g_msic_wr_flag = CALI_STR_NONE; + return -EINVAL; + + } break; + } + + if (copy_to_user((void __user *)buf, local_buf, len)) { + aw_dev_err(aw_dev->dev, "copy_to_user error"); + g_msic_wr_flag = CALI_STR_NONE; + return -EFAULT; + } + + g_msic_wr_flag = CALI_STR_NONE; + *pos += len; + return len; +} + +static int aw_cali_misc_switch_dev(struct file *filp, struct aw_device *aw_dev, char *cmd_buf) +{ + int ret; + int i; + char dev_select[50] = { 0 }; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + /* get sel dev str */ + ret = sscanf(cmd_buf, "dev_sel:%s", dev_select); + if (ret <= 0) + return -EINVAL; + + for (i = 0; i < AW_DEV_CH_MAX; i++) { + if (strnstr(dev_select, ch_name[i], strlen(ch_name[i]))) + break; + } + + if (i == AW_DEV_CH_MAX) { + aw_dev_err(aw_dev->dev, "unsupport dev [%s]", dev_select); + return -EINVAL; + } + + /* get dev list */ + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed "); + return ret; + } + + /* find sel dev */ + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel == i) { + filp->private_data = (void *)local_dev; + g_dev_select = i; + aw_dev_info(local_dev->dev, "switch dev to [%s]", ch_name[i]); + return 0; + } + } + aw_dev_err(aw_dev->dev, " unsupport [%s]", dev_select); + return -EINVAL; +} + +static ssize_t aw_cali_misc_write(struct file *filp, const char __user *buf, size_t size, loff_t *pos) +{ + int ret = 0; + char *kernel_buf = NULL; + struct aw_device *aw_dev = (struct aw_device *)filp->private_data; + + aw_dev_info(aw_dev->dev, "enter, write size:%d", (int)size); + + kernel_buf = kzalloc(size + 1, GFP_KERNEL); + if (kernel_buf == NULL) + return -ENOMEM; + + + if (copy_from_user(kernel_buf, + (void __user *)buf, + size)) { + ret = -EFAULT; + goto exit; + } + + ret = aw_cali_svc_get_cmd_form_str(aw_dev, kernel_buf); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "upported cmd [%s]! ", kernel_buf); + ret = -EINVAL; + goto exit; + } + + switch (ret) { + case CALI_STR_CALI_RE_F0: { + ret = aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_RE_F0, + is_single_cali, CALI_OPS_HMUTE|CALI_OPS_NOISE); + } break; + case CALI_STR_CALI_RE: { + ret = aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_RE, + is_single_cali, CALI_OPS_HMUTE); + } break; + case CALI_STR_CALI_F0: { + ret = aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_F0, + is_single_cali, CALI_OPS_HMUTE|CALI_OPS_NOISE); + } break; + case CALI_STR_SET_RE: { + /*skip store_re*/ + kernel_buf[size] = '\0'; + ret = aw_cali_svc_set_devs_re_str(aw_dev, + kernel_buf + strlen(cali_str[CALI_STR_SET_RE]) + 1); + } break; + case CALI_STR_DEV_SEL: { + ret = aw_cali_misc_switch_dev(filp, aw_dev, kernel_buf); + } break; + case CALI_STR_CALI_F0_Q: { + ret = aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_F0_Q, + is_single_cali, CALI_OPS_HMUTE|CALI_OPS_NOISE); + } break; + case CALI_STR_SHOW_RE: /*show cali_re*/ + case CALI_STR_SHOW_R0: /*show real r0*/ + case CALI_STR_SHOW_CALI_F0: /*GET DEV CALI_F0*/ + case CALI_STR_SHOW_F0: /*SHOW REAL F0*/ + case CALI_STR_SHOW_TE: + case CALI_STR_SHOW_ST: + case CALI_STR_VER: + case CALI_STR_DEV_NUM: + case CALI_STR_SHOW_F0_Q: + case CALI_STR_SHOW_RE_RANGE:{ + g_msic_wr_flag = ret; + ret = 0; + } break; + default: { + aw_dev_err(aw_dev->dev, "unsupported [%s]! ", kernel_buf); + ret = -EINVAL; + } break; + }; + +exit: + aw_dev_info(aw_dev->dev, "cmd [%s]! ", kernel_buf); + + kfree(kernel_buf); + kernel_buf = NULL; + + if (ret < 0) + return -EINVAL; + else + return size; +} + +static const struct file_operations aw_cali_misc_fops = { + .owner = THIS_MODULE, + .open = aw_cali_misc_open, + .read = aw_cali_misc_read, + .write = aw_cali_misc_write, + .release = aw_cali_misc_release, + .unlocked_ioctl = aw_cali_misc_unlocked_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = aw_cali_misc_compat_ioctl, +#endif + +}; + +static struct miscdevice misc_cali = { + .name = "aw882xx_smartpa", + .minor = MISC_DYNAMIC_MINOR, + .fops = &aw_cali_misc_fops, +}; + +static int aw_cali_misc_init(struct aw_device *aw_dev) +{ + int ret; + + mutex_lock(&g_cali_lock); + if (g_misc_dev == NULL) { + ret = misc_register(&misc_cali); + if (ret) { + aw_dev_err(aw_dev->dev, "misc register fail: %d\n", ret); + mutex_unlock(&g_cali_lock); + return -EINVAL; + } + g_misc_dev = &misc_cali; + aw_dev_dbg(aw_dev->dev, "misc register success"); + } else { + aw_dev_dbg(aw_dev->dev, "misc already register"); + } + mutex_unlock(&g_cali_lock); + + return 0; +} + +static void aw_cali_misc_deinit(struct aw_device *aw_dev) +{ + mutex_lock(&g_cali_lock); + if (g_misc_dev) { + misc_deregister(g_misc_dev); + g_misc_dev = NULL; + } + mutex_unlock(&g_cali_lock); + aw_dev_dbg(aw_dev->dev, " misc unregister done"); +} + +/*****************************misc node******************************************************/ +static void aw_cali_parse_dt(struct aw_device *aw_dev) +{ + int ret = -1; + struct device_node *np = aw_dev->dev->of_node; + const char *cali_mode_str = NULL; + uint32_t cali_check = CALI_CHECK_DISABLE; + struct aw_cali_desc *desc = &aw_dev->cali_desc; + + ret = of_property_read_u32(np, "aw-cali-check", &cali_check); + if (ret < 0) { + aw_dev_info(aw_dev->dev, "cali-check get failed ,default turn off"); + cali_check = CALI_CHECK_DISABLE; + } + + desc->cali_check_st = cali_check; + aw_dev_info(aw_dev->dev, "cali check :%s", + (desc->cali_check_st) ? "enable" : "disable"); + + ret = of_property_read_string(np, "aw-cali-mode", &cali_mode_str); + if (ret < 0) { + desc->mode = AW_CALI_MODE_ALL; + aw_dev_info(aw_dev->dev, "cali function in use"); + return; + } + + if (!strcmp(cali_mode_str, "none")) + desc->mode = AW_CALI_MODE_NONE; + else + desc->mode = AW_CALI_MODE_ALL; + + aw_dev_info(aw_dev->dev, "cali mode is %d", desc->mode); +} + +static int aw_cali_parse_re_dt(struct aw_device *aw_dev) +{ + int ret; + + ret = of_property_read_u32(aw_dev->dev->of_node, "aw-re-min", &aw_dev->re_min); + if (ret < 0) { + aw_dev->re_min = AW_CALI_RE_DEFAULT_MIN; + aw_dev_info(aw_dev->dev, "read aw-re-min failed, use default"); + } + + ret = of_property_read_u32(aw_dev->dev->of_node, "aw-re-max", &aw_dev->re_max); + if (ret < 0) { + aw_dev->re_max = AW_CALI_RE_DEFAULT_MAX; + aw_dev_info(aw_dev->dev, "read aw-re-max failed, use default"); + } + + if (aw_dev->re_min >= aw_dev->re_max) { + aw_dev_err(aw_dev->dev, "re max must be greater than re min"); + return -EINVAL; + } + + aw_dev_info(aw_dev->dev, "re min: %d, re max: %d", + aw_dev->re_min, aw_dev->re_max); + return 0; +} + +int aw882xx_cali_init(struct aw_cali_desc *cali_desc) +{ + int ret; + + struct aw_device *aw_dev = + container_of(cali_desc, struct aw_device, cali_desc); + + cali_desc->cali_f0 = 0; + cali_desc->cali_re = 0; + cali_desc->cali_q = 0; + cali_desc->status = 0; + + aw_cali_parse_dt(aw_dev); + + if (cali_desc->mode == AW_CALI_MODE_ALL) { + aw_cali_attr_init(aw_dev); + aw_cali_class_attr_init(aw_dev); + } else { + aw_dev_info(aw_dev->dev, "cali mode is %d", cali_desc->mode); + } + + aw_cali_misc_init(aw_dev); + + ret = aw_cali_parse_re_dt(aw_dev); + + cali_desc->cali_result = CALI_RESULT_NONE; + + return ret; +} + +void aw882xx_cali_deinit(struct aw_cali_desc *cali_desc) +{ + struct aw_device *aw_dev = + container_of(cali_desc, struct aw_device, cali_desc); + + if (cali_desc->mode == AW_CALI_MODE_ALL) { + aw_cali_attr_deinit(aw_dev); + aw_cali_class_attr_deinit(aw_dev); + } + + aw_cali_misc_deinit(aw_dev); +} + diff --git a/sound/soc/codecs/aw882xx/aw882xx_calib.h b/sound/soc/codecs/aw882xx/aw882xx_calib.h new file mode 100644 index 000000000000..c26ca8f74ec4 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_calib.h @@ -0,0 +1,193 @@ +/* SPDX-License-Identifier: GPL-2.0 + * aw882xx_calib.h + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_CALIBRATION_H__ +#define __AW882XX_CALIBRATION_H__ + +#define AW_CALI_READ_RE_TIMES (8) +#define AW_CALI_READ_F0_Q_TIMES (5) +#define AW_ERRO_CALI_VALUE (0) +#define AW_CALI_RE_DEFAULT_TIMER (3000) + +#define AW_CALI_RE_MAX (15000) +#define AW_CALI_RE_MIN (4000) + +#define AW_CALI_CFG_NUM (3) +#define AW_CALI_DATA_NUM (6) +#define AW_PARAMS_NUM (600) +#define AW_KILO_PARAMS_NUM (1000) + +#define AW_CALI_RE_DEFAULT_MAX (50000) +#define AW_CALI_RE_DEFAULT_MIN (1000) + +#define AW_DEV_RE_RANGE (RE_RANGE_NUM * AW_DEV_CH_MAX) + +struct aw_device; + +enum afe_module_type { + AW_RX_MODULE = 0, + AW_TX_MODULE = 1, +}; + +enum { + MSG_CALI_DISABLE_DATA = 0, + MSG_CALI_RE_ENABLE_DATA, + MSG_CALI_F0_ENABLE_DATA, +}; + +struct cali_cfg { + int32_t data[AW_CALI_CFG_NUM]; +}; + +struct cali_data { + int32_t data[AW_CALI_DATA_NUM]; +}; + +struct params_data { + int32_t data[AW_PARAMS_NUM]; +}; + +struct ptr_params_data { + int len; + int32_t *data; +}; + +struct f0_q_data { + int32_t data[4]; +}; + +enum { + AW_IOCTL_MSG_IOCTL = 0, + AW_IOCTL_MSG_RD_DSP, + AW_IOCTL_MSG_WR_DSP +}; + +enum { + CALI_CHECK_DISABLE = 0, + CALI_CHECK_ENABLE = 1, +}; + +enum { + CALI_RESULT_NONE = 0, + CALI_RESULT_NORMAL = 1, + CALI_RESULT_ERROR = -1, +}; + +enum { + RE_MIN_FLAG = 0, + RE_MAX_FLAG = 1, + RE_RANGE_NUM = 2, +}; + +enum { + CALI_DATA_RE = 0, + CALI_DATA_F0, + CALI_DATA_F0_Q, +}; + +struct re_data { + uint32_t re_range[2]; +}; + +#define AW_IOCTL_MSG_VERSION (0) +typedef struct { + int32_t type; + int32_t opcode_id; + int32_t version; + int32_t data_len; + char *data_buf; + int32_t reseriver[2]; +} aw_ioctl_msg_t; + +#define AW_IOCTL_MAGIC 'a' +#define AW_IOCTL_SET_CALI_CFG _IOWR(AW_IOCTL_MAGIC, 1, struct cali_cfg) +#define AW_IOCTL_GET_CALI_CFG _IOWR(AW_IOCTL_MAGIC, 2, struct cali_cfg) +#define AW_IOCTL_GET_CALI_DATA _IOWR(AW_IOCTL_MAGIC, 3, struct cali_data) +#define AW_IOCTL_SET_NOISE _IOWR(AW_IOCTL_MAGIC, 4, int32_t) +#define AW_IOCTL_GET_F0 _IOWR(AW_IOCTL_MAGIC, 5, int32_t) +#define AW_IOCTL_SET_CALI_RE _IOWR(AW_IOCTL_MAGIC, 6, int32_t) +#define AW_IOCTL_GET_CALI_RE _IOWR(AW_IOCTL_MAGIC, 7, int32_t) +#define AW_IOCTL_SET_VMAX _IOWR(AW_IOCTL_MAGIC, 8, int32_t) +#define AW_IOCTL_GET_VMAX _IOWR(AW_IOCTL_MAGIC, 9, int32_t) +#define AW_IOCTL_SET_PARAM _IOWR(AW_IOCTL_MAGIC, 10, struct params_data) +#define AW_IOCTL_ENABLE_CALI _IOWR(AW_IOCTL_MAGIC, 11, int8_t) +#define AW_IOCTL_SET_PTR_PARAM_NUM _IOWR(AW_IOCTL_MAGIC, 12, struct ptr_params_data) +#define AW_IOCTL_GET_F0_Q _IOWR(AW_IOCTL_MAGIC, 13, struct f0_q_data) +#define AW_IOCTL_SET_DSP_HMUTE _IOWR(AW_IOCTL_MAGIC, 14, int32_t) +#define AW_IOCTL_SET_CALI_CFG_FLAG _IOWR(AW_IOCTL_MAGIC, 15, int32_t) +#define AW_IOCTL_MSG _IOWR(AW_IOCTL_MAGIC, 16, aw_ioctl_msg_t) +#define AW_IOCTL_GET_RE_RANGE _IOWR(AW_IOCTL_MAGIC, 17, struct re_data) + +enum{ + AW_CALI_MODE_NONE = 0, + AW_CALI_MODE_ALL, + AW_CALI_MODE_MAX, +}; + +enum { + AW_CALI_CMD_RE = 0, + AW_CALI_CMD_F0, + AW_CALI_CMD_RE_F0, + AW_CALI_CMD_F0_Q, + AW_CALI_CMD_RE_F0_Q, +}; + +enum { + CALI_OPS_HMUTE = 0X0001, + CALI_OPS_NOISE = 0X0002, +}; + +enum { + CALI_TYPE_RE = 0, + CALI_TYPE_F0, +}; + +enum { + CALI_STR_NONE = 0, + CALI_STR_CALI_RE_F0, + CALI_STR_CALI_RE, + CALI_STR_CALI_F0, + CALI_STR_SET_RE, + CALI_STR_SHOW_RE, /*show cali_re*/ + CALI_STR_SHOW_R0, /*show real r0*/ + CALI_STR_SHOW_CALI_F0, /*GET DEV CALI_F0*/ + CALI_STR_SHOW_F0, /*SHOW REAL F0*/ + CALI_STR_SHOW_TE, + CALI_STR_SHOW_ST, + CALI_STR_DEV_SEL, /*switch device*/ + CALI_STR_VER, + CALI_STR_DEV_NUM, + CALI_STR_CALI_F0_Q, + CALI_STR_SHOW_F0_Q, + CALI_STR_SHOW_RE_RANGE, + CALI_STR_MAX, +}; + +struct aw_cali_desc { + unsigned char status; + unsigned char mode; /*0:NONE 1:ATTR 2:CLASS 3:MISC */ + int32_t cali_re; /*set cali_re*/ + int32_t cali_f0; /*store cali_f0*/ + int32_t cali_q; /*store cali q*/ + int8_t cali_result; + uint8_t cali_check_st; +}; + +int aw882xx_cali_init(struct aw_cali_desc *cali_desc); +void aw882xx_cali_deinit(struct aw_cali_desc *cali_desc); +int aw882xx_cali_svc_get_cali_status(void); +int aw882xx_cali_read_re_from_nvram(int32_t *cali_re, int32_t ch_index); +bool aw882xx_cali_check_result(struct aw_cali_desc *cali_desc); + + +#endif diff --git a/sound/soc/codecs/aw882xx/aw882xx_data_type.h b/sound/soc/codecs/aw882xx/aw882xx_data_type.h new file mode 100644 index 000000000000..13213243b59a --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_data_type.h @@ -0,0 +1,165 @@ +/* SPDX-License-Identifier: GPL-2.0 + * aw882xx_data_type.h + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_DATA_TYPE_H__ +#define __AW882XX_DATA_TYPE_H__ + +#define AW_NAME_BUF_MAX (50) + +struct aw_msg_hdr { + int32_t type; + int32_t opcode_id; + int32_t version; + int32_t reseriver[3]; +}; + + +/****************************************************************** + * aw profile + *******************************************************************/ +#define PROJECT_NAME_MAX (24) +#define CUSTOMER_NAME_MAX (16) +#define CFG_VERSION_MAX (4) +#define DEV_NAME_MAX (16) +#define PROFILE_STR_MAX (32) +#define AW_INIT_PROFILE (0) + +#define ACF_FILE_ID (0xa15f908) + + +enum aw_cfg_hdr_version { + AW_CFG_HDR_VER_0_0_0_1 = 0x00000001, + AW_CFG_HDR_VER_1_0_0_0 = 0x01000000, +}; + +enum aw_cfg_dde_type { + AW_DEV_TYPE_ID = 0x00000000, + AW_SKT_TYPE_ID = 0x00000001, + AW_DEV_DEFAULT_TYPE_ID = 0x00000002, +}; + +enum aw_sec_type { + ACF_SEC_TYPE_REG = 0, + ACF_SEC_TYPE_DSP, + ACF_SEC_TYPE_DSP_CFG, + ACF_SEC_TYPE_DSP_FW, + ACF_SEC_TYPE_HDR_REG, + ACF_SEC_TYPE_HDR_DSP_CFG, + ACF_SEC_TYPE_HDR_DSP_FW, + ACF_SEC_TYPE_MUTLBIN, + ACF_SEC_TYPE_SKT_PROJECT, + ACF_SEC_TYPE_DSP_PROJECT, + ACF_SEC_TYPE_MONITOR, + ACF_SEC_TYPE_MAX, +}; + +enum profile_data_type { + AW_PROFILE_DATA_TYPE_REG = 0, + AW_PROFILE_DATA_TYPE_DSP, + AW_PROFILE_DATA_TYPE_MAX, +}; + +enum aw_prof_type { + AW_PROFILE_MUSIC = 0, + AW_PROFILE_VOICE, + AW_PROFILE_VOIP, + AW_PROFILE_RINGTONE, + AW_PROFILE_RINGTONE_HS, + AW_PROFILE_LOWPOWER, + AW_PROFILE_BYPASS, + AW_PROFILE_MMI, + AW_PROFILE_FM, + AW_PROFILE_NOTIFICATION, + AW_PROFILE_RECEIVER, + AW_PROFILE_MAX, +}; + +enum aw_profile_status { + AW_PROFILE_WAIT = 0, + AW_PROFILE_OK, +}; + +struct aw_cfg_hdr { + uint32_t a_id; /*acf file ID 0xa15f908*/ + char a_project[PROJECT_NAME_MAX]; /*project name*/ + char a_custom[CUSTOMER_NAME_MAX]; /*custom name :huawei xiaomi vivo oppo*/ + char a_version[CFG_VERSION_MAX]; /*author update version*/ + uint32_t a_author_id; /*author id*/ + uint32_t a_ddt_size; /*sub section table entry size*/ + uint32_t a_ddt_num; /*sub section table entry num*/ + uint32_t a_hdr_offset; /*sub section table offset in file*/ + uint32_t a_hdr_version; /*sub section table version*/ + uint32_t reserve[3]; +}; + +struct aw_cfg_dde { + uint32_t type; /*DDE type id*/ + char dev_name[DEV_NAME_MAX]; + uint16_t dev_index; /*dev id*/ + uint16_t dev_bus; /*dev bus id*/ + uint16_t dev_addr; /*dev addr id*/ + uint16_t dev_profile; /*dev profile id*/ + uint32_t data_type; /*data type id*/ + uint32_t data_size; + uint32_t data_offset; + uint32_t data_crc; + uint32_t reserve[5]; +}; + +struct aw_cfg_dde_v_1_0_0_0 { + uint32_t type; /*DDE type id*/ + char dev_name[DEV_NAME_MAX]; + uint16_t dev_index; /*dev id*/ + uint16_t dev_bus; /*dev bus id*/ + uint16_t dev_addr; /*dev addr id*/ + uint16_t dev_profile; /*dev profile id*/ + uint32_t data_type; /*data type id*/ + uint32_t data_size; + uint32_t data_offset; + uint32_t data_crc; + char dev_profile_str[PROFILE_STR_MAX]; + uint32_t chip_id; + uint32_t reserve[4]; +}; + + +struct aw_container { + unsigned int len; + unsigned char data[]; +}; + +struct aw_sec_data_desc { + uint32_t len; + char *data; +}; + +struct aw_prof_desc { + uint32_t prof_st; /*Only used in V0.0.0.1 header*/ + uint32_t id; + char *prf_str; + struct aw_sec_data_desc sec_desc[AW_PROFILE_DATA_TYPE_MAX]; +}; + +struct aw_all_prof_info { + struct aw_prof_desc prof_desc[AW_PROFILE_MAX]; +}; + +struct aw_prof_info { + uint32_t count; + char **prof_name_list; + struct aw_prof_desc *prof_desc; +}; + + +#endif + diff --git a/sound/soc/codecs/aw882xx/aw882xx_device.c b/sound/soc/codecs/aw882xx/aw882xx_device.c new file mode 100644 index 000000000000..100ee6da8260 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_device.c @@ -0,0 +1,1593 @@ +// SPDX-License-Identifier: GPL-2.0 +/* aw882xx_device.c + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/* #define DEBUG */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "aw882xx_log.h" +#include "aw882xx_device.h" +#include "aw882xx_dsp.h" +/*#include "aw_afe.h"*/ +#include "aw882xx_bin_parse.h" +#include "aw882xx_spin.h" + +#define AW_DEV_SYSST_CHECK_MAX (10) + + +char ext_dsp_prof_write = AW_EXT_DSP_WRITE_NONE; +static DEFINE_MUTEX(g_ext_dsp_prof_wr_lock); /*lock ext wr flag*/ +static unsigned int g_fade_in_time = AW_1000_US / 10; +static unsigned int g_fade_out_time = AW_1000_US >> 1; +static LIST_HEAD(g_dev_list); +static DEFINE_MUTEX(g_dev_lock); + +static DEFINE_MUTEX(g_algo_auth_dsp_lock); +int g_algo_auth_st; + +/*********************************algo auth*************************************/ +static int aw882xx_dev_get_encrypted_value(struct aw_device *aw_dev, + unsigned int in, unsigned int *out) +{ + int ret = 0; + struct aw_auth_desc *desc = &aw_dev->auth_desc; + + if ((!desc->reg_in) || (!desc->reg_out)) { + aw_dev_dbg(aw_dev->dev, "Missing encryption register"); + return -EINVAL; + } + + ret = aw_dev->ops.aw_i2c_write(aw_dev, desc->reg_in, in); + if (ret < 0) + return ret; + + ret = aw_dev->ops.aw_i2c_read(aw_dev, desc->reg_out, out); + + return ret; +} + +int aw882xx_dev_algo_auth_mode(struct aw_device *aw_dev, struct algo_auth_data *algo_data) +{ + int ret = 0; + unsigned int encrypted_out = 0; + + aw_dev_info(aw_dev->dev, "algo auth mode: %d", algo_data->auth_mode); + + aw_dev->auth_desc.auth_mode = algo_data->auth_mode; + aw_dev->auth_desc.random = algo_data->random; + aw_dev->auth_desc.chip_id = AW_ALGO_AUTH_MAGIC_ID; + aw_dev->auth_desc.check_result = algo_data->check_result; + + switch (algo_data->auth_mode) { + case AW_ALGO_AUTH_MODE_MAGIC_ID: + aw_dev->auth_desc.reg_crc = algo_data->reg_crc; + break; + case AW_ALGO_AUTH_MODE_REG_CRC: + ret = aw882xx_dev_get_encrypted_value(aw_dev, algo_data->random, &encrypted_out); + if (ret < 0) + aw_dev_err(aw_dev->dev, "get encrypted value failed"); + + aw_dev->auth_desc.reg_crc = encrypted_out; + break; + default: + aw_dev_err(aw_dev->dev, "unsupport auth mode[%d]", algo_data->auth_mode); + ret = -EINVAL; + } + return ret; +} + +#ifdef AW_ALGO_AUTH_DSP +int aw882xx_dev_algo_auth_dsp_mode(struct aw_device *aw_dev, struct algo_auth_data *algo_data) +{ + int ret = 0; + unsigned int encrypted_out = 0; + + aw_dev_info(aw_dev->dev, "algo auth mode: %d", algo_data->auth_mode); + + algo_data->chip_id = AW_ALGO_AUTH_MAGIC_ID; + + if (algo_data->auth_mode == AW_ALGO_AUTH_MODE_REG_CRC) { + ret = aw882xx_dev_get_encrypted_value(aw_dev, algo_data->random, &encrypted_out); + if (ret < 0) + aw_dev_err(aw_dev->dev, "get encrypted value failed"); + + algo_data->reg_crc = encrypted_out; + } + + return ret; +} + +void aw882xx_dev_algo_authentication(struct aw_device *aw_dev) +{ + int ret = 0; + struct algo_auth_data algo_data; + + mutex_lock(&g_algo_auth_dsp_lock); + + aw_dev_dbg(aw_dev->dev, "g_algo_auth_st=%d", g_algo_auth_st); + + if (g_algo_auth_st == AW_ALGO_AUTH_OK) { + aw_dev_dbg(aw_dev->dev, "algo auth complete"); + goto exit; + } + + ret = aw882xx_dsp_read_algo_auth_data(aw_dev, (char *)&algo_data, sizeof(struct algo_auth_data)); + if (ret < 0) + goto exit; + + ret = aw882xx_dev_algo_auth_dsp_mode(aw_dev, &algo_data); + if (ret < 0) + goto exit; + + ret = aw882xx_dsp_write_algo_auth_data(aw_dev, (char *)&algo_data, sizeof(struct algo_auth_data)); + if (ret < 0) + goto exit; + + g_algo_auth_st = AW_ALGO_AUTH_OK; + aw_dev_info(aw_dev->dev, "g_algo_auth_st=%d", g_algo_auth_st); + + aw_dev_dbg(aw_dev->dev, "mode=%d,reg_crc=0x%x,random=0x%x,id=0x%x,res=%d", + algo_data.auth_mode, algo_data.reg_crc, algo_data.random, + algo_data.chip_id, algo_data.check_result); + +exit: + mutex_unlock(&g_algo_auth_dsp_lock); +} +#endif +/*********************************algo_auth_misc*************************************/ +static int aw_algo_auth_misc_ops_write(struct aw_device *aw_dev, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + unsigned int data_len = _IOC_SIZE(cmd); + struct algo_auth_data algo_data; + + aw_dev_dbg(aw_dev->dev, "write algo auth data, len=%d", data_len); + + if (copy_from_user(&algo_data, (void __user *)arg, data_len)) + ret = -EFAULT; + + aw882xx_dev_algo_auth_mode(aw_dev, &algo_data); + + aw_dev_dbg(aw_dev->dev, "ret=%d,mode=%d,reg_crc=0x%x,random=0x%x,id=0x%x,res=%d", + ret, algo_data.auth_mode, algo_data.reg_crc, algo_data.random, + algo_data.chip_id, algo_data.check_result); + + return ret; +} + +static int aw_algo_auth_misc_ops_read(struct aw_device *aw_dev, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + int16_t data_len = _IOC_SIZE(cmd); + struct algo_auth_data algo_data; + + aw_dev_dbg(aw_dev->dev, "read algo auth data, len=%d", data_len); + memset(&algo_data, 0x0, sizeof(struct algo_auth_data)); + + algo_data.auth_mode = aw_dev->auth_desc.auth_mode; + algo_data.chip_id = aw_dev->auth_desc.chip_id; + algo_data.random = aw_dev->auth_desc.random; + algo_data.reg_crc = aw_dev->auth_desc.reg_crc; + algo_data.check_result = aw_dev->auth_desc.check_result; + + if (copy_to_user((void __user *)arg, (char *)&algo_data, data_len)) + ret = -EFAULT; + + aw_dev_dbg(aw_dev->dev, "ret=%d,mode=%d,reg_crc=0x%x,random=0x%x,id=0x%x,res=%d", + ret, algo_data.auth_mode, algo_data.reg_crc, algo_data.random, + algo_data.chip_id, algo_data.check_result); + + return ret; +} + +static int aw_algo_auth_misc_ops(struct aw_device *aw_dev, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + + switch (cmd) { + case AW_IOCTL_SET_ALGO_AUTH: { + ret = aw_algo_auth_misc_ops_write(aw_dev, cmd, arg); + } break; + case AW_IOCTL_GET_ALGO_AUTH: { + ret = aw_algo_auth_misc_ops_read(aw_dev, cmd, arg); + } break; + default: + aw_dev_err(aw_dev->dev, "unsupported cmd %d", cmd); + ret = -EINVAL; + break; + } + + return ret; +} + +static long aw_algo_auth_misc_unlocked_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + struct aw_device *aw_dev = NULL; + + if (((_IOC_TYPE(cmd)) != (AW_IOCTL_MAGIC_S))) { + aw_pr_err("cmd magic err"); + return -EINVAL; + } + aw_dev = (struct aw_device *)file->private_data; + ret = aw_algo_auth_misc_ops(aw_dev, cmd, arg); + if (ret) + return -EINVAL; + + return 0; +} + +#ifdef CONFIG_COMPAT +static long aw_algo_auth_misc_compat_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + struct aw_device *aw_dev = NULL; + + if (((_IOC_TYPE(cmd)) != (AW_IOCTL_MAGIC_S))) { + aw_pr_err("cmd magic err"); + return -EINVAL; + } + aw_dev = (struct aw_device *)file->private_data; + ret = aw_algo_auth_misc_ops(aw_dev, cmd, arg); + if (ret) + return -EINVAL; + + return 0; +} +#endif + +static int aw_algo_auth_misc_open(struct inode *inode, struct file *file) +{ + int ret; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_pr_err("get dev list failed"); + file->private_data = NULL; + return -EINVAL; + } + + /* find select dev */ + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel == 0) + break; + } + + if (local_dev == NULL) { + aw_pr_err("can't find dev num %d", 0); + return -EINVAL; + } + + file->private_data = (void *)local_dev; + + aw_dev_dbg(local_dev->dev, "misc open success"); + return 0; +} + + +static int aw_algo_auth_misc_release(struct inode *inode, struct file *file) +{ + file->private_data = (void *)NULL; + + aw_pr_dbg("misc release success"); + return 0; +} + +static const struct file_operations aw_algo_auth_misc_fops = { + .owner = THIS_MODULE, + .open = aw_algo_auth_misc_open, + .release = aw_algo_auth_misc_release, + .unlocked_ioctl = aw_algo_auth_misc_unlocked_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = aw_algo_auth_misc_compat_ioctl, +#endif +}; + +static struct miscdevice misc_algo_auth = { + .name = "awinic_ctl", + .minor = MISC_DYNAMIC_MINOR, + .fops = &aw_algo_auth_misc_fops, +}; + +static int aw882xx_algo_auth_misc_init(struct aw_device *aw_dev) +{ + int ret; + + ret = misc_register(&misc_algo_auth); + if (ret) { + aw_dev_err(aw_dev->dev, "misc register fail: %d\n", ret); + return -EINVAL; + } + + return 0; +} + +static void aw882xx_algo_auth_misc_deinit(struct aw_device *aw_dev) +{ + misc_deregister(&misc_algo_auth); + + aw_dev_dbg(aw_dev->dev, " misc unregister done"); +} + +void aw882xx_dev_monitor_hal_get_time(struct aw_device *aw_dev, uint32_t *time) +{ + aw882xx_monitor_hal_get_time(&aw_dev->monitor_desc, time); +} + +void aw882xx_dev_monitor_hal_work(struct aw_device *aw_dev, uint32_t *vmax) +{ + aw882xx_monitor_hal_work(&aw_dev->monitor_desc, vmax); +} + +static void aw_dev_reg_dump(struct aw_device *aw_dev) +{ + int reg_num = aw_dev->ops.aw_get_reg_num(); + uint8_t i = 0; + unsigned int reg_val = 0; + + for (i = 0; i < reg_num; i++) { + if (aw_dev->ops.aw_check_rd_access(i)) { + aw_dev->ops.aw_i2c_read(aw_dev, i, ®_val); + aw_dev_info(aw_dev->dev, "read: reg = 0x%02x, val = 0x%04x", + i, reg_val); + } + } +} + +char *aw882xx_dev_get_ext_dsp_prof_write(void) +{ + return &ext_dsp_prof_write; +} + +struct mutex *aw882xx_dev_get_ext_dsp_prof_wr_lock(void) +{ + return &g_ext_dsp_prof_wr_lock; +} + +static int aw_dev_get_icalk(struct aw_device *aw_dev, int16_t *icalk) +{ + int ret = -1; + unsigned int reg_val = 0; + uint16_t reg_icalk = 0; + uint16_t reg_icalkl = 0; + struct aw_vcalb_desc *desc = &aw_dev->vcalb_desc; + + if (desc->icalkl_reg == AW_REG_NONE) { + ret = aw_dev->ops.aw_i2c_read(aw_dev, desc->icalk_reg, ®_val); + reg_icalk = (uint16_t)reg_val & (~desc->icalk_reg_mask); + } else { + ret = aw_dev->ops.aw_i2c_read(aw_dev, desc->icalk_reg, ®_val); + reg_icalk = (uint16_t)reg_val & (~desc->icalk_reg_mask); + ret = aw_dev->ops.aw_i2c_read(aw_dev, desc->icalkl_reg, ®_val); + reg_icalkl = (uint16_t)reg_val & (~desc->icalkl_reg_mask); + if (aw_dev->efuse_check == AW_EF_OR_CHECK) + reg_icalk = (reg_icalk >> desc->icalk_shift) | (reg_icalkl >> desc->icalkl_shift); + else + reg_icalk = (reg_icalk >> desc->icalk_shift) & (reg_icalkl >> desc->icalkl_shift); + } + + if (reg_icalk & (~desc->icalk_sign_mask)) + reg_icalk = reg_icalk | (~desc->icalk_neg_mask); + + *icalk = (int16_t)reg_icalk; + + return ret; +} + +static int aw_dev_get_vcalk(struct aw_device *aw_dev, int16_t *vcalk) +{ + int ret = -1; + unsigned int reg_val = 0; + uint16_t reg_vcalk = 0; + uint16_t reg_vcalkl = 0; + struct aw_vcalb_desc *desc = &aw_dev->vcalb_desc; + + if (desc->vcalkl_reg == AW_REG_NONE) { + ret = aw_dev->ops.aw_i2c_read(aw_dev, desc->vcalk_reg, ®_val); + reg_vcalk = (uint16_t)reg_val & (~desc->vcalk_reg_mask); + } else { + ret = aw_dev->ops.aw_i2c_read(aw_dev, desc->vcalk_reg, ®_val); + reg_vcalk = (uint16_t)reg_val & (~desc->vcalk_reg_mask); + ret = aw_dev->ops.aw_i2c_read(aw_dev, desc->vcalkl_reg, ®_val); + reg_vcalkl = (uint16_t)reg_val & (~desc->vcalkl_reg_mask); + if (aw_dev->efuse_check == AW_EF_OR_CHECK) + reg_vcalk = (reg_vcalk >> desc->vcalk_shift) | (reg_vcalkl >> desc->vcalkl_shift); + else + reg_vcalk = (reg_vcalk >> desc->vcalk_shift) & (reg_vcalkl >> desc->vcalkl_shift); + } + + if (reg_vcalk & (~desc->vcalk_sign_mask)) + reg_vcalk = reg_vcalk | (~desc->vcalk_neg_mask); + + *vcalk = (int16_t)reg_vcalk; + + return ret; +} + +static int aw_dev_set_vcalb(struct aw_device *aw_dev) +{ + int ret = -1; + unsigned int reg_val; + int vcalb; + int icalk; + int vcalk; + int16_t icalk_val = 0; + int16_t vcalk_val = 0; + + struct aw_vcalb_desc *desc = &aw_dev->vcalb_desc; + + if (desc->icalk_reg == AW_REG_NONE || desc->vcalb_reg == AW_REG_NONE) { + aw_dev_info(aw_dev->dev, "REG None!"); + return 0; + } + + ret = aw_dev_get_icalk(aw_dev, &icalk_val); + if (ret < 0) + return ret; + + ret = aw_dev_get_vcalk(aw_dev, &vcalk_val); + if (ret < 0) + return ret; + + icalk = desc->cabl_base_value + desc->icalk_value_factor * icalk_val; + vcalk = desc->cabl_base_value + desc->vcalk_value_factor * vcalk_val; + if (!vcalk) { + aw_dev_err(aw_dev->dev, "vcalk is 0"); + return -EINVAL; + } + + vcalb = desc->vcal_factor * icalk / vcalk; + + reg_val = (unsigned int)vcalb; + aw_dev_info(aw_dev->dev, "icalk=%d, vcalk=%d, vcalb=%d, reg_val=0x%04x", + icalk, vcalk, vcalb, reg_val); + + ret = aw_dev->ops.aw_i2c_write(aw_dev, desc->vcalb_reg, reg_val); + + aw_dev_info(aw_dev->dev, "done"); + + return ret; +} + +/*pwd enable update reg*/ +static int aw_dev_reg_fw_update(struct aw_device *aw_dev) +{ + int ret = -1; + int i = 0; + unsigned int reg_addr = 0; + unsigned int reg_val = 0; + unsigned int read_val = 0; + unsigned int read_vol = 0; + unsigned int efcheck_val = 0; + struct aw_int_desc *int_desc = &aw_dev->int_desc; + struct aw_profctrl_desc *profctrl_desc = &aw_dev->profctrl_desc; + struct aw_bstctrl_desc *bstctrl_desc = &aw_dev->bstctrl_desc; + struct aw_work_mode *work_mode = &aw_dev->work_mode; + struct aw_cali_desc *cali_desc = &aw_dev->cali_desc; + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + struct aw_sec_data_desc *reg_data; + int16_t *data; + int data_len; + + char *prof_name = aw882xx_dev_get_prof_name(aw_dev, aw_dev->set_prof); + + if (prof_name == NULL) { + aw_dev_err(aw_dev->dev, "get prof name failed"); + return -EINVAL; + } + + reg_data = aw882xx_dev_get_prof_data(aw_dev, aw_dev->set_prof, AW_PROFILE_DATA_TYPE_REG); + if (reg_data == NULL) + return -EINVAL; + + data = (int16_t *)reg_data->data; + data_len = reg_data->len >> 1; + + for (i = 0; i < data_len; i += 2) { + reg_addr = data[i]; + reg_val = data[i + 1]; + + if (reg_addr == int_desc->mask_reg) { + int_desc->int_mask = reg_val; + reg_val = int_desc->mask_default; + } + + if (aw_dev->bstcfg_enable) { + if (reg_addr == profctrl_desc->reg) { + profctrl_desc->cfg_prof_mode = + reg_val & (~profctrl_desc->mask); + } + + if (reg_addr == bstctrl_desc->reg) { + bstctrl_desc->cfg_bst_type = + reg_val & (~bstctrl_desc->mask); + } + } + + /*keep amppd status*/ + if (reg_addr == aw_dev->amppd_desc.reg) { + aw_dev->amppd_st = reg_val & (~aw_dev->amppd_desc.mask); + aw_dev_info(aw_dev->dev, "amppd_st=0x%04x", aw_dev->amppd_st); + aw_dev->ops.aw_i2c_read(aw_dev, + (unsigned char)reg_addr, + (unsigned int *)&read_val); + read_val &= (~aw_dev->amppd_desc.mask); + reg_val &= aw_dev->amppd_desc.mask; + reg_val |= read_val; + } + + if (reg_addr == aw_dev->efcheck_desc.reg) { + efcheck_val = reg_val & (~aw_dev->efcheck_desc.mask); + if (efcheck_val == aw_dev->efcheck_desc.or_val) + aw_dev->efuse_check = AW_EF_OR_CHECK; + else + aw_dev->efuse_check = AW_EF_AND_CHECK; + + aw_dev_info(aw_dev->dev, "efuse check: %d", aw_dev->efuse_check); + } + + if (reg_addr == work_mode->reg) { + if ((reg_val & (~work_mode->mask)) == work_mode->rcv_val) + aw_dev->monitor_start = false; + else + aw_dev->monitor_start = true; + } + + /*keep pwd status*/ + if (reg_addr == aw_dev->pwd_desc.reg) { + aw_dev->ops.aw_i2c_read(aw_dev, + (unsigned char)reg_addr, + (unsigned int *)&read_val); + read_val &= (~aw_dev->pwd_desc.mask); + reg_val &= aw_dev->pwd_desc.mask; + reg_val |= read_val; + } + /*keep mute status*/ + if (reg_addr == aw_dev->mute_desc.reg) { + /*get bin value*/ + aw_dev->mute_st = reg_val & (~aw_dev->mute_desc.mask); + aw_dev_info(aw_dev->dev, "mute_st=0x%04x", aw_dev->mute_st); + aw_dev->ops.aw_i2c_read(aw_dev, + (unsigned char)reg_addr, + (unsigned int *)&read_val); + read_val &= (~aw_dev->mute_desc.mask); + reg_val &= aw_dev->mute_desc.mask; + reg_val |= read_val; + } + + /*enable uls hmute*/ + if (reg_addr == aw_dev->uls_hmute_desc.reg) { + reg_val &= aw_dev->uls_hmute_desc.mask; + reg_val |= aw_dev->uls_hmute_desc.enable; + } + + if ((cali_desc->mode == AW_CALI_MODE_NONE) && + (reg_addr == aw_dev->txen_desc.reg)) { + aw_dev->txen_desc.reserve_val = reg_val & (~aw_dev->txen_desc.mask); + aw_dev_info(aw_dev->dev, "reserve_val = 0x%04x", + aw_dev->txen_desc.reserve_val); + } + + if (reg_addr == aw_dev->txen_desc.reg) { + /*get bin value*/ + aw_dev->txen_st = reg_val & (~aw_dev->txen_desc.mask); + aw_dev_dbg(aw_dev->dev, "txen_st=0x%04x", aw_dev->txen_st); + + reg_val &= aw_dev->txen_desc.mask; + reg_val |= aw_dev->txen_desc.disable; + } + + if (reg_addr == aw_dev->volume_desc.reg) { + read_vol = (reg_val & (~aw_dev->volume_desc.mask)) >> + aw_dev->volume_desc.shift; + aw_dev->volume_desc.init_volume = + aw_dev->ops.aw_reg_val_to_db(read_vol); + } + if (reg_addr == aw_dev->dither_desc.reg) { + aw_dev->dither_st = reg_val & (~aw_dev->dither_desc.mask); + aw_dev_info(aw_dev->dev, "dither_st=0x%04x", aw_dev->dither_st); + } + + if (reg_addr == aw_dev->vcalb_desc.vcalb_reg) + continue; + + aw_dev_dbg(aw_dev->dev, "reg=0x%04x, val = 0x%04x", + (uint16_t)reg_addr, (uint16_t)reg_val); + ret = aw_dev->ops.aw_i2c_write(aw_dev, + (unsigned char)reg_addr, + (unsigned int)reg_val); + if (ret < 0) + break; + } + + aw882xx_spin_set_record_val(aw_dev); + ret = aw_dev_set_vcalb(aw_dev); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "can't set vcalb"); + return ret; + } + + if (aw_dev->cur_prof != aw_dev->set_prof) + /*clear control volume when PA change profile*/ + vol_desc->ctl_volume = 0; + + + if (aw_dev->fade_en) { + /*keep min volume*/ + aw882xx_dev_set_volume(aw_dev, vol_desc->mute_volume); + } + + aw_dev_info(aw_dev->dev, "load %s done", prof_name); + + return ret; +} + +int aw882xx_dev_set_volume(struct aw_device *aw_dev, unsigned int set_vol) +{ + int ret = -1; + unsigned int hw_vol = 0; + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + + hw_vol = set_vol + vol_desc->init_volume; + + ret = aw_dev->ops.aw_set_hw_volume(aw_dev, hw_vol); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "set volume failed"); + return ret; + } + + return 0; +} + +int aw882xx_dev_get_volume(struct aw_device *aw_dev, unsigned int *get_vol) +{ + int ret = -1; + unsigned int hw_vol = 0; + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + + ret = aw_dev->ops.aw_get_hw_volume(aw_dev, &hw_vol); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "read volume failed"); + return ret; + } + + *get_vol = hw_vol - vol_desc->init_volume; + + return 0; +} + +static void aw_dev_fade_in(struct aw_device *aw_dev) +{ + int i = 0; + int fade_step = aw_dev->vol_step; + struct aw_volume_desc *desc = &aw_dev->volume_desc; + int fade_in_vol = desc->ctl_volume; + + if (!aw_dev->fade_en) + return; + + + if (fade_step == 0 || g_fade_in_time == 0) { + aw882xx_dev_set_volume(aw_dev, fade_in_vol); + return; + } + + /*volume up*/ + for (i = desc->mute_volume; i >= fade_in_vol; i -= fade_step) { + aw882xx_dev_set_volume(aw_dev, i); + usleep_range(g_fade_in_time, g_fade_in_time + 10); + } + + if (i != fade_in_vol) + aw882xx_dev_set_volume(aw_dev, fade_in_vol); + +} + +static void aw_dev_fade_out(struct aw_device *aw_dev) +{ + int i = 0; + int fade_step = aw_dev->vol_step; + struct aw_volume_desc *desc = &aw_dev->volume_desc; + + if (!aw_dev->fade_en) + return; + + + if (fade_step == 0 || g_fade_out_time == 0) { + aw882xx_dev_set_volume(aw_dev, desc->mute_volume); + return; + } + + for (i = desc->ctl_volume; i <= desc->mute_volume; i += fade_step) { + aw882xx_dev_set_volume(aw_dev, i); + usleep_range(g_fade_out_time, g_fade_out_time + 10); + } + + if (i != desc->mute_volume) { + aw882xx_dev_set_volume(aw_dev, desc->mute_volume); + usleep_range(g_fade_out_time, g_fade_out_time + 10); + } +} + +static void aw_dev_pwd(struct aw_device *aw_dev, bool pwd) +{ + struct aw_pwd_desc *pwd_desc = &aw_dev->pwd_desc; + + aw_dev_dbg(aw_dev->dev, "enter, pwd: %d", pwd); + + if (pwd) { + aw_dev->ops.aw_i2c_write_bits(aw_dev, pwd_desc->reg, + pwd_desc->mask, + pwd_desc->enable); + } else { + aw_dev->ops.aw_i2c_write_bits(aw_dev, pwd_desc->reg, + pwd_desc->mask, + pwd_desc->disable); + } + aw_dev_info(aw_dev->dev, "done"); +} + +static void aw_dev_amppd(struct aw_device *aw_dev, bool amppd) +{ + struct aw_amppd_desc *amppd_desc = &aw_dev->amppd_desc; + + aw_dev_dbg(aw_dev->dev, "enter, amppd: %d", amppd); + + if (amppd) { + aw_dev->ops.aw_i2c_write_bits(aw_dev, amppd_desc->reg, + amppd_desc->mask, + amppd_desc->enable); + } else { + aw_dev->ops.aw_i2c_write_bits(aw_dev, amppd_desc->reg, + amppd_desc->mask, + amppd_desc->disable); + } + aw_dev_info(aw_dev->dev, "done"); +} + +void aw882xx_dev_mute(struct aw_device *aw_dev, bool mute) +{ + struct aw_mute_desc *mute_desc = &aw_dev->mute_desc; + + aw_dev_dbg(aw_dev->dev, "enter, mute: %d, cali_result: %d", + mute, aw_dev->cali_desc.cali_result); + + if (mute) { + aw_dev_fade_out(aw_dev); + aw_dev->ops.aw_i2c_write_bits(aw_dev, mute_desc->reg, + mute_desc->mask, + mute_desc->enable); + usleep_range(AW_5000_US, AW_5000_US + 50); + } else { + aw_dev->ops.aw_i2c_write_bits(aw_dev, mute_desc->reg, + mute_desc->mask, + mute_desc->disable); + aw_dev_fade_in(aw_dev); + } + aw_dev_info(aw_dev->dev, "done"); +} + +static void aw_dev_uls_hmute(struct aw_device *aw_dev, bool uls_hmute) +{ + struct aw_uls_hmute_desc *uls_hmute_desc = &aw_dev->uls_hmute_desc; + + aw_dev_dbg(aw_dev->dev, "enter, uls_hmute: %d", uls_hmute); + + if (uls_hmute_desc->reg == AW_REG_NONE) + return; + + if (uls_hmute) { + aw_dev->ops.aw_i2c_write_bits(aw_dev, uls_hmute_desc->reg, + uls_hmute_desc->mask, + uls_hmute_desc->enable); + } else { + aw_dev->ops.aw_i2c_write_bits(aw_dev, uls_hmute_desc->reg, + uls_hmute_desc->mask, + uls_hmute_desc->disable); + } + aw_dev_info(aw_dev->dev, "done"); +} + +static void aw_dev_set_dither(struct aw_device *aw_dev, bool dither) +{ + struct aw_dither_desc *dither_desc = &aw_dev->dither_desc; + + aw_dev_dbg(aw_dev->dev, "enter, dither: %d", dither); + + if (dither_desc->reg == AW_REG_NONE) + return; + + if (dither) { + aw_dev->ops.aw_i2c_write_bits(aw_dev, dither_desc->reg, + dither_desc->mask, + dither_desc->enable); + } else { + aw_dev->ops.aw_i2c_write_bits(aw_dev, dither_desc->reg, + dither_desc->mask, + dither_desc->disable); + } + + aw_dev_info(aw_dev->dev, "done"); +} + +static void aw_dev_set_psm(struct aw_device *aw_dev, bool psm) +{ + struct aw_psm_desc *desc = &aw_dev->psm_desc; + + aw_dev_dbg(aw_dev->dev, "enter, psm: %d", psm); + if (desc->reg == AW_REG_NONE) + return; + + if (psm) + aw_dev->ops.aw_i2c_write_bits(aw_dev, desc->reg, + desc->mask, desc->enable); + else + aw_dev->ops.aw_i2c_write_bits(aw_dev, desc->reg, + desc->mask, desc->disable); + + aw_dev_info(aw_dev->dev, "done"); +} + +static void aw_dev_set_mpd(struct aw_device *aw_dev, bool mpd) +{ + struct aw_mpd_desc *desc = &aw_dev->mpd_desc; + + aw_dev_dbg(aw_dev->dev, "enter, mpd: %d", mpd); + if (desc->reg == AW_REG_NONE) + return; + + if (mpd) + aw_dev->ops.aw_i2c_write_bits(aw_dev, desc->reg, + desc->mask, desc->enable); + else + aw_dev->ops.aw_i2c_write_bits(aw_dev, desc->reg, + desc->mask, desc->disable); + + aw_dev_info(aw_dev->dev, "done"); +} + +static void aw_dev_set_dsmzth(struct aw_device *aw_dev, bool dsmzth) +{ + struct aw_dsmzth_desc *desc = &aw_dev->dsmzth_desc; + + aw_dev_dbg(aw_dev->dev, "enter, dsmzth: %d", dsmzth); + if (desc->reg == AW_REG_NONE) + return; + + if (dsmzth) + aw_dev->ops.aw_i2c_write_bits(aw_dev, desc->reg, + desc->mask, desc->enable); + else + aw_dev->ops.aw_i2c_write_bits(aw_dev, desc->reg, + desc->mask, desc->disable); + + aw_dev_info(aw_dev->dev, "done"); +} + +void aw882xx_dev_iv_forbidden_output(struct aw_device *aw_dev, bool power_waste) +{ + aw_dev_set_psm(aw_dev, power_waste); + aw_dev_set_mpd(aw_dev, power_waste); + aw_dev_set_dsmzth(aw_dev, power_waste); +} + +int aw882xx_dev_get_int_status(struct aw_device *aw_dev, uint16_t *int_status) +{ + int ret = -1; + unsigned int reg_val = 0; + + ret = aw_dev->ops.aw_i2c_read(aw_dev, aw_dev->int_desc.st_reg, ®_val); + if (ret < 0) + aw_dev_err(aw_dev->dev, "read interrupt reg fail, ret=%d", ret); + else + *int_status = reg_val; + + aw_dev_dbg(aw_dev->dev, "read interrupt reg = 0x%04x", *int_status); + return ret; +} + +void aw882xx_dev_clear_int_status(struct aw_device *aw_dev) +{ + uint16_t int_status = 0; + + /*read int status and clear*/ + aw882xx_dev_get_int_status(aw_dev, &int_status); + /*make suer int status is clear*/ + aw882xx_dev_get_int_status(aw_dev, &int_status); + aw_dev_info(aw_dev->dev, "done"); +} + +int aw882xx_dev_set_intmask(struct aw_device *aw_dev, bool flag) +{ + struct aw_int_desc *desc = &aw_dev->int_desc; + int ret = -1; + + if (flag) + ret = aw_dev->ops.aw_i2c_write(aw_dev, desc->mask_reg, + desc->int_mask); + else + ret = aw_dev->ops.aw_i2c_write(aw_dev, desc->mask_reg, + desc->mask_default); + aw_dev_info(aw_dev->dev, "done"); + return ret; +} + +static int aw_dev_mode1_pll_check(struct aw_device *aw_dev) +{ + int ret = -1; + unsigned char i; + unsigned int reg_val = 0; + struct aw_sysst_desc *desc = &aw_dev->sysst_desc; + + for (i = 0; i < AW_DEV_SYSST_CHECK_MAX; i++) { + aw_dev->ops.aw_i2c_read(aw_dev, desc->reg, ®_val); + if ((reg_val & desc->pll_check) == desc->pll_check) { + ret = 0; + break; + } + aw_dev_dbg(aw_dev->dev, "check pll lock fail, cnt=%d, reg_val=0x%04x", + i, reg_val); + usleep_range(AW_2000_US, AW_2000_US + 10); + + } + if (ret < 0) + aw_dev_err(aw_dev->dev, "pll&clk check fail"); + else + aw_dev_info(aw_dev->dev, "done"); + + return ret; +} + +static int aw_dev_mode2_pll_check(struct aw_device *aw_dev) +{ + int ret = -1; + unsigned int reg_val = 0; + struct aw_cco_mux_desc *cco_mux_desc = &aw_dev->cco_mux_desc; + + aw_dev->ops.aw_i2c_read(aw_dev, cco_mux_desc->reg, ®_val); + reg_val &= (~cco_mux_desc->mask); + aw_dev_dbg(aw_dev->dev, "REG_PLLCTRL1_bit14 = 0x%04x", reg_val); + if (reg_val == cco_mux_desc->divided_val) { + aw_dev_dbg(aw_dev->dev, "CCO_MUX is already divided"); + return ret; + } + + /* change mode2 */ + aw_dev->ops.aw_i2c_write_bits(aw_dev, cco_mux_desc->reg, + cco_mux_desc->mask, cco_mux_desc->divided_val); + ret = aw_dev_mode1_pll_check(aw_dev); + + /* change mode1 */ + aw_dev->ops.aw_i2c_write_bits(aw_dev, cco_mux_desc->reg, + cco_mux_desc->mask, cco_mux_desc->bypass_val); + if (ret == 0) { + usleep_range(AW_2000_US, AW_2000_US + 10); + ret = aw_dev_mode1_pll_check(aw_dev); + } + + return ret; +} + +static int aw_dev_syspll_check(struct aw_device *aw_dev) +{ + int ret = -1; + + ret = aw_dev_mode1_pll_check(aw_dev); + if (ret < 0) { + aw_dev_err(aw_dev->dev, + "mode1 check iis failed try switch to mode2 check"); + + ret = aw_dev_mode2_pll_check(aw_dev); + if (ret < 0) + aw_dev_err(aw_dev->dev, "mode2 check iis failed"); + } + + return ret; +} + +static int aw_dev_sysst_check(struct aw_device *aw_dev) +{ + int ret = -1; + unsigned char i; + unsigned int reg_val = 0; + unsigned int check_value = 0; + struct aw_sysst_desc *desc = &aw_dev->sysst_desc; + struct aw_noise_gate_desc *noise_gate_desc = &aw_dev->noise_gate_desc; + + check_value = desc->st_check; + + if (noise_gate_desc->reg != AW_REG_NONE) { + aw_dev->ops.aw_i2c_read(aw_dev, noise_gate_desc->reg, ®_val); + if (reg_val & (~noise_gate_desc->mask)) + check_value = desc->st_check; + else + check_value = desc->st_sws_check; + } + + for (i = 0; i < AW_DEV_SYSST_CHECK_MAX; i++) { + aw_dev->ops.aw_i2c_read(aw_dev, desc->reg, ®_val); + if (((reg_val & (~desc->mask)) & check_value) == check_value) { + ret = 0; + break; + } + aw_dev_info(aw_dev->dev, "check fail, cnt=%d, reg_val=0x%04x", + i, reg_val); + usleep_range(AW_2000_US, AW_2000_US + 10); + + } + if (ret < 0) + aw_dev_err(aw_dev->dev, "check fail"); + else + aw_dev_info(aw_dev->dev, "done"); + + return ret; +} + +int aw882xx_dev_get_fade_vol_step(struct aw_device *aw_dev) +{ + return aw_dev->vol_step; +} + +void aw882xx_dev_set_fade_vol_step(struct aw_device *aw_dev, unsigned int step) +{ + aw_dev->vol_step = step; +} + +void aw882xx_dev_get_fade_time(unsigned int *time, bool fade_in) +{ + if (fade_in) + *time = g_fade_in_time; + else + *time = g_fade_out_time; +} + +void aw882xx_dev_set_fade_time(unsigned int time, bool fade_in) +{ + if (fade_in) + g_fade_in_time = time; + else + g_fade_out_time = time; +} + +/*init aw_device*/ +void aw882xx_dev_deinit(struct aw_device *aw_dev) +{ + if (aw_dev == NULL) + return; + + if (aw_dev->prof_info.prof_desc != NULL) { + kfree(aw_dev->prof_info.prof_desc); + aw_dev->prof_info.prof_desc = NULL; + aw_dev->prof_info.count = 0; + } +} + +int aw882xx_dev_get_cali_re(struct aw_device *aw_dev, int32_t *cali_re) +{ + + return aw882xx_dsp_read_cali_re(aw_dev, cali_re); +} + +int aw882xx_dev_dc_status(struct aw_device *aw_dev) +{ + return aw882xx_dsp_get_dc_status(aw_dev); +} + +int aw882xx_dev_status(struct aw_device *aw_dev) +{ + return aw_dev->status; +} + +int aw882xx_dev_init_cali_re(struct aw_device *aw_dev) +{ + int ret = 0; + struct aw_cali_desc *cali_desc = &aw_dev->cali_desc; + + if (cali_desc->mode) { + if (cali_desc->cali_re == AW_ERRO_CALI_VALUE) { + ret = aw882xx_cali_read_re_from_nvram(&cali_desc->cali_re, aw_dev->channel); + if (ret) { + aw_dev_info(aw_dev->dev, "read nvram cali failed, use default Re"); + cali_desc->cali_re = AW_ERRO_CALI_VALUE; + cali_desc->cali_result = CALI_RESULT_NONE; + return 0; + } + + if (cali_desc->cali_re < aw_dev->re_min || + cali_desc->cali_re > aw_dev->re_max) { + aw_dev_err(aw_dev->dev, "out range re value: %d", + cali_desc->cali_re); + cali_desc->cali_re = AW_ERRO_CALI_VALUE; + /*cali_result is error when aw-cali-check enable*/ + if (aw_dev->cali_desc.cali_check_st) + cali_desc->cali_result = CALI_RESULT_ERROR; + + return -EINVAL; + } + + aw_dev_dbg(aw_dev->dev, "read re value: %d", cali_desc->cali_re); + + if (aw_dev->cali_desc.cali_check_st) + cali_desc->cali_result = CALI_RESULT_NORMAL; + + } + } else { + aw_dev_info(aw_dev->dev, "no cali, needn't init cali re"); + } + return ret; +} + +static void aw_dev_soft_reset(struct aw_device *aw_dev) +{ + struct aw_soft_rst *reset = &aw_dev->soft_rst; + + aw_dev->ops.aw_i2c_write(aw_dev, reset->reg, reset->reg_value); + aw_dev_info(aw_dev->dev, "soft reset done"); +} + +int aw882xx_device_irq_reinit(struct aw_device *aw_dev) +{ + int ret; + + /*reg re load*/ + ret = aw_dev_reg_fw_update(aw_dev); + if (ret < 0) + return ret; + + return 0; +} + +int aw882xx_device_init(struct aw_device *aw_dev, struct aw_container *aw_cfg) +{ + /*acf_hdr_t *hdr;*/ + int ret; + + if (aw_cfg == NULL) { + aw_dev_err(aw_dev->dev, "aw_cfg is NULL"); + return -ENOMEM; + } + + ret = aw882xx_dev_parse_acf(aw_dev, aw_cfg); + if (ret) { + aw882xx_dev_deinit(aw_dev); + aw_dev_err(aw_dev->dev, "aw_dev acf load failed"); + return -EINVAL; + } + + aw_dev_soft_reset(aw_dev); + + aw_dev->cur_prof = AW_INIT_PROFILE; + aw_dev->set_prof = AW_INIT_PROFILE; + ret = aw_dev_reg_fw_update(aw_dev); + if (ret < 0) + return ret; + + if (aw_dev->ops.aw_frcset_check) { + ret = aw_dev->ops.aw_frcset_check(aw_dev); + if (ret) + return ret; + } + + aw_dev->status = AW_DEV_PW_ON; + aw882xx_device_stop(aw_dev); + + aw_dev_info(aw_dev->dev, "init done"); + return 0; +} + +int aw882xx_dev_reg_update(struct aw_device *aw_dev, bool force) +{ + int ret; + + if (force) { + aw_dev_soft_reset(aw_dev); + ret = aw_dev_reg_fw_update(aw_dev); + if (ret < 0) + return ret; + } else { + if (aw_dev->cur_prof != aw_dev->set_prof) { + ret = aw_dev_reg_fw_update(aw_dev); + if (ret < 0) + return ret; + } + } + + aw_dev->cur_prof = aw_dev->set_prof; + + aw_dev_info(aw_dev->dev, "done"); + return 0; +} + +static void aw_dev_cali_re_update(struct aw_device *aw_dev) +{ + struct aw_cali_desc *desc = &aw_dev->cali_desc; + + if (desc->mode && (desc->cali_re != AW_ERRO_CALI_VALUE)) { + if ((desc->cali_re >= aw_dev->re_min) && + (desc->cali_re <= aw_dev->re_max)) + aw882xx_dsp_write_cali_re(aw_dev, desc->cali_re); + else + aw_dev_err(aw_dev->dev, "cali re is out of range"); + } +} + +static void aw_dev_boost_type_set(struct aw_device *aw_dev) +{ + struct aw_profctrl_desc *profctrl_desc = &aw_dev->profctrl_desc; + struct aw_bstctrl_desc *bstctrl_desc = &aw_dev->bstctrl_desc; + + aw_dev_dbg(aw_dev->dev, "enter"); + + if (aw_dev->bstcfg_enable) { + /*set spk mode*/ + aw_dev->ops.aw_i2c_write_bits(aw_dev, profctrl_desc->reg, + profctrl_desc->mask, profctrl_desc->spk_mode); + + /*force boost*/ + aw_dev->ops.aw_i2c_write_bits(aw_dev, bstctrl_desc->reg, + bstctrl_desc->mask, bstctrl_desc->frc_bst); + + aw_dev_dbg(aw_dev->dev, "boost type set done"); + } +} + +static void aw_dev_boost_type_recover(struct aw_device *aw_dev) +{ + + struct aw_profctrl_desc *profctrl_desc = &aw_dev->profctrl_desc; + struct aw_bstctrl_desc *bstctrl_desc = &aw_dev->bstctrl_desc; + + aw_dev_dbg(aw_dev->dev, "enter"); + + if (aw_dev->bstcfg_enable) { + /*set transprant*/ + aw_dev->ops.aw_i2c_write_bits(aw_dev, bstctrl_desc->reg, + bstctrl_desc->mask, bstctrl_desc->tsp_type); + + usleep_range(AW_5000_US, AW_5000_US + 50); + /*set cfg boost type*/ + aw_dev->ops.aw_i2c_write_bits(aw_dev, bstctrl_desc->reg, + bstctrl_desc->mask, bstctrl_desc->cfg_bst_type); + + /*set cfg prof mode*/ + aw_dev->ops.aw_i2c_write_bits(aw_dev, profctrl_desc->reg, + profctrl_desc->mask, profctrl_desc->cfg_prof_mode); + + aw_dev_dbg(aw_dev->dev, "boost type recover done"); + } +} + +static void aw_dev_i2s_enable(struct aw_device *aw_dev, bool flag) +{ + struct aw_txen_desc *txen_desc = &aw_dev->txen_desc; + struct aw_cali_desc *cali_desc = &aw_dev->cali_desc; + + aw_dev_dbg(aw_dev->dev, "enter, i2s_enable: %d", flag); + + if (txen_desc->reg == AW_REG_NONE) { + aw_dev_info(aw_dev->dev, "needn't set i2s status"); + return; + } + + if (flag) { + if (cali_desc->mode == AW_CALI_MODE_NONE) + aw_dev->ops.aw_i2c_write_bits(aw_dev, + txen_desc->reg, txen_desc->mask, txen_desc->reserve_val); + else + aw_dev->ops.aw_i2c_write_bits(aw_dev, + txen_desc->reg, txen_desc->mask, txen_desc->enable); + } else { + aw_dev->ops.aw_i2c_write_bits(aw_dev, + txen_desc->reg, txen_desc->mask, txen_desc->disable); + } +} + + +int aw882xx_device_start(struct aw_device *aw_dev) +{ + int ret; + struct aw_dither_desc *dither_desc = &aw_dev->dither_desc; + + aw_dev_dbg(aw_dev->dev, "enter"); + + if (aw_dev->status == AW_DEV_PW_ON) { + aw_dev_info(aw_dev->dev, "already power on"); + return 0; + } + + /*set froce boost*/ + aw_dev_boost_type_set(aw_dev); + + aw_dev_set_dither(aw_dev, false); + + /*power on*/ + aw_dev_pwd(aw_dev, false); + usleep_range(AW_2000_US, AW_2000_US + 10); + + ret = aw_dev_syspll_check(aw_dev); + if (ret < 0) { + aw_dev_reg_dump(aw_dev); + aw_dev_pwd(aw_dev, true); + aw_dev_dbg(aw_dev->dev, "pll check failed cannot start"); + return ret; + } + + /*amppd on*/ + aw_dev_amppd(aw_dev, false); + usleep_range(AW_1000_US, AW_1000_US + 50); + + /*check i2s status*/ + ret = aw_dev_sysst_check(aw_dev); + if (ret < 0) { + aw_dev_reg_dump(aw_dev); + /*close tx feedback*/ + aw_dev_i2s_enable(aw_dev, false); + /*clear interrupt*/ + aw882xx_dev_clear_int_status(aw_dev); + /*close amppd*/ + aw_dev_amppd(aw_dev, true); + /*power down*/ + aw_dev_pwd(aw_dev, true); + return -EINVAL; + } + + /*boost type recover*/ + aw_dev_boost_type_recover(aw_dev); + + /*enable tx feedback*/ + if (aw_dev->txen_st) + aw_dev_i2s_enable(aw_dev, true); + + if (aw_dev->amppd_st) + aw_dev_amppd(aw_dev, true); + + + if (aw_dev->ops.aw_reg_force_set) + aw_dev->ops.aw_reg_force_set(aw_dev); + + /*close uls hmute*/ + aw_dev_uls_hmute(aw_dev, false); + + if (aw_dev->dither_st == dither_desc->enable) + aw_dev_set_dither(aw_dev, true); + + + if (!aw_dev->mute_st) { + /*close mute*/ + if (aw882xx_cali_check_result(&aw_dev->cali_desc)) + aw882xx_dev_mute(aw_dev, false); + else + aw882xx_dev_mute(aw_dev, true); + } + + /*clear inturrupt*/ + aw882xx_dev_clear_int_status(aw_dev); + /*set inturrupt mask*/ + aw882xx_dev_set_intmask(aw_dev, true); + + aw882xx_monitor_start(&aw_dev->monitor_desc); + aw_dev_cali_re_update(aw_dev); +#ifdef AW_ALGO_AUTH_DSP + aw882xx_dev_algo_authentication(aw_dev); +#endif + aw_dev->status = AW_DEV_PW_ON; + aw_dev_info(aw_dev->dev, "done"); + return 0; +} + +int aw882xx_device_stop(struct aw_device *aw_dev) +{ + aw_dev_dbg(aw_dev->dev, "enter"); + + if (aw_dev->status == AW_DEV_PW_OFF) { + aw_dev_dbg(aw_dev->dev, "already power off"); + return 0; + } + + aw_dev->status = AW_DEV_PW_OFF; + + aw882xx_monitor_stop(&aw_dev->monitor_desc); + /*clear interrupt*/ + aw882xx_dev_clear_int_status(aw_dev); + + /*set defaut int mask*/ + aw882xx_dev_set_intmask(aw_dev, false); + + /*set uls hmute*/ + aw_dev_uls_hmute(aw_dev, true); + + /*set mute*/ + aw882xx_dev_mute(aw_dev, true); + + usleep_range(AW_5000_US, AW_5000_US + 10); + + /*close tx feedback*/ + aw_dev_i2s_enable(aw_dev, false); + + usleep_range(AW_1000_US, AW_1000_US + 100); + + /*enable amppd*/ + aw_dev_amppd(aw_dev, true); + + /*set power down*/ + aw_dev_pwd(aw_dev, true); + + ext_dsp_prof_write = AW_EXT_DSP_WRITE_NONE; + aw_dev_info(aw_dev->dev, "done"); + return 0; +} + +int aw882xx_dev_set_afe_module_en(int type, int enable) +{ + return aw882xx_dsp_set_afe_module_en(type, enable); +} + +int aw882xx_dev_get_afe_module_en(int type, int *status) +{ + return aw882xx_dsp_get_afe_module_en(type, status); +} + +int aw882xx_dev_set_copp_module_en(bool enable) +{ + return aw882xx_dsp_set_copp_module_en(enable); +} + +static int aw_device_parse_sound_channel_dt(struct aw_device *aw_dev) +{ + int ret = 0; + uint32_t channel_value = 0; + struct list_head *dev_list = NULL; + struct list_head *pos = NULL; + struct aw_device *local_dev = NULL; + + ret = of_property_read_u32(aw_dev->dev->of_node, "sound-channel", &channel_value); + if (ret < 0) { + channel_value = AW_DEV_CH_PRI_L; + aw_dev_info(aw_dev->dev, "read sound-channel failed,use default"); + } + + aw_dev_info(aw_dev->dev, "read sound-channel value is : %d", channel_value); + if (channel_value >= AW_DEV_CH_MAX) + channel_value = AW_DEV_CH_PRI_L; + + /* when dev_num > 0, get dev list to compare*/ + if (aw_dev->ops.aw_get_dev_num() > 0) { + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed"); + return ret; + } + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + if (local_dev->channel == channel_value) { + aw_dev_err(local_dev->dev, "sound-channel:%d already exists", + channel_value); + return -EINVAL; + } + } + } + + aw_dev->channel = channel_value; + + return 0; + +} + +static void aw_device_parse_fade_flag_dt(struct aw_device *aw_dev) +{ + int ret; + uint32_t fade_en = 0; + + ret = of_property_read_u32(aw_dev->dev->of_node, "fade-flag", &fade_en); + if (ret < 0) + aw_dev_info(aw_dev->dev, "read fade-flag failed,use default"); + + + aw_dev->fade_en = fade_en; + aw_dev_info(aw_dev->dev, "fade-flag: %d", fade_en); + +} + +static int aw_device_parse_dt(struct aw_device *aw_dev) +{ + int ret = 0; + + ret = aw_device_parse_sound_channel_dt(aw_dev); + if (ret) { + aw_dev_err(aw_dev->dev, "parse sound-channel failed!"); + return ret; + } + aw882xx_device_parse_topo_id_dt(aw_dev); + aw882xx_device_parse_port_id_dt(aw_dev); + aw_device_parse_fade_flag_dt(aw_dev); + + return ret; +} + +int aw882xx_dev_get_list_head(struct list_head **head) +{ + if (list_empty(&g_dev_list)) + return -EINVAL; + + *head = &g_dev_list; + + return 0; +} + +int aw882xx_device_probe(struct aw_device *aw_dev) +{ + int ret = 0; + + INIT_LIST_HEAD(&aw_dev->list_node); + + ret = aw_device_parse_dt(aw_dev); + if (ret) + return ret; + + if (aw_dev->channel == 0) + aw882xx_algo_auth_misc_init(aw_dev); + + ret = aw882xx_cali_init(&aw_dev->cali_desc); + if (ret) + return ret; + + aw882xx_monitor_init(&aw_dev->monitor_desc); + /*aw_afe_init();*/ + + ret = aw882xx_spin_init(&aw_dev->spin_desc); + if (ret) + return ret; + + mutex_lock(&g_dev_lock); + list_add(&aw_dev->list_node, &g_dev_list); + mutex_unlock(&g_dev_lock); + + return 0; +} + +int aw882xx_device_remove(struct aw_device *aw_dev) +{ + aw882xx_monitor_deinit(&aw_dev->monitor_desc); + aw882xx_cali_deinit(&aw_dev->cali_desc); + if (aw_dev->channel == 0) + aw882xx_algo_auth_misc_deinit(aw_dev); + /*aw_afe_deinit();*/ + return 0; +} + diff --git a/sound/soc/codecs/aw882xx/aw882xx_device.h b/sound/soc/codecs/aw882xx/aw882xx_device.h new file mode 100644 index 000000000000..78c7efb31836 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_device.h @@ -0,0 +1,463 @@ +/* SPDX-License-Identifier: GPL-2.0 + * aw882xx_device.h + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_DEVICE_FILE_H__ +#define __AW882XX_DEVICE_FILE_H__ +#include "aw882xx_data_type.h" +#include "aw882xx_calib.h" +#include "aw882xx_monitor.h" +#include "aw882xx_dsp.h" + +#define AW_VOLUME_STEP_DB (6 * 2) +#define AW_REG_NONE (0xFF) +#define AW_NAME_MAX (50) +#define ALGO_VERSION_MAX (80) + +#define AW_GET_MIN_VALUE(value1, value2) \ + ((value1) > (value2) ? (value2) : (value1)) + +#define AW_GET_MAX_VALUE(value1, value2) \ + ((value1) > (value2) ? (value1) : (value2)) + +extern int g_algo_auth_st; + +enum { + AW_1000_US = 1000, + AW_2000_US = 2000, + AW_3000_US = 3000, + AW_4000_US = 4000, + AW_5000_US = 5000, + AW_10000_US = 10000, + AW_32000_US = 32000, + AW_70000_US = 70000, + AW_100000_US = 100000, +}; + +struct aw_device; + +enum { + AW_DEV_TYPE_NONE = 0, + AW_DEV_TYPE_OK, +}; + +enum { + AW_EF_AND_CHECK = 0, + AW_EF_OR_CHECK, +}; + +enum { + AW_DEV_CH_PRI_L = 0, + AW_DEV_CH_PRI_R = 1, + AW_DEV_CH_SEC_L = 2, + AW_DEV_CH_SEC_R = 3, + AW_DEV_CH_TERT_L = 4, + AW_DEV_CH_TERT_R = 5, + AW_DEV_CH_QUAT_L = 6, + AW_DEV_CH_QUAT_R = 7, + AW_DEV_CH_MAX, +}; + +enum AW_DEV_INIT { + AW_DEV_INIT_ST = 0, + AW_DEV_INIT_OK = 1, + AW_DEV_INIT_NG = 2, +}; + +enum AW_DEV_STATUS { + AW_DEV_PW_OFF = 0, + AW_DEV_PW_ON, +}; + +enum AW_DEV_FW_STATUS { + AW_DEV_FW_FAILED = 0, + AW_DEV_FW_OK, +}; + + +enum { + AW_EXT_DSP_WRITE_NONE = 0, + AW_EXT_DSP_WRITE, +}; + +enum AW_SPIN_KCONTROL_STATUS { + AW_SPIN_KCONTROL_DISABLE = 0, + AW_SPIN_KCONTROL_ENABLE, +}; + +enum AW_ALGO_AUTH_MODE { + AW_ALGO_AUTH_DISABLE = 0, + AW_ALGO_AUTH_MODE_MAGIC_ID, + AW_ALGO_AUTH_MODE_REG_CRC, +}; + +enum AW_ALGO_AUTH_ID { + AW_ALGO_AUTH_MAGIC_ID = 0x4157, +}; + +enum AW_ALGO_AUTH_STATUS { + AW_ALGO_AUTH_WAIT = 0, + AW_ALGO_AUTH_OK = 1, +}; + +struct aw_device_ops { + int (*aw_i2c_write)(struct aw_device *aw_dev, unsigned char reg_addr, unsigned int reg_data); + int (*aw_i2c_read)(struct aw_device *aw_dev, unsigned char reg_addr, unsigned int *reg_data); + int (*aw_i2c_write_bits)(struct aw_device *aw_dev, unsigned char reg_addr, unsigned int mask, unsigned int reg_data); + int (*aw_set_hw_volume)(struct aw_device *aw_dev, unsigned int value); + int (*aw_get_hw_volume)(struct aw_device *aw_dev, unsigned int *value); + unsigned int (*aw_reg_val_to_db)(unsigned int value); + bool (*aw_check_wr_access)(int reg); + bool (*aw_check_rd_access)(int reg); + int (*aw_get_reg_num)(void); + int (*aw_get_version)(char *buf, int size); + int (*aw_get_dev_num)(void); + void (*aw_set_algo)(struct aw_device *aw_dev); + unsigned int (*aw_get_irq_type)(struct aw_device *aw_dev, unsigned int value); + void (*aw_reg_force_set)(struct aw_device *aw_dev); + int (*aw_frcset_check)(struct aw_device *aw_dev); +}; + +struct aw_int_desc { + unsigned int mask_reg; /*interrupt mask reg*/ + unsigned int st_reg; /*interrupt status reg*/ + unsigned int mask_default; /*default mask close all*/ + unsigned int int_mask; /*set mask*/ +}; + +struct aw_work_mode { + unsigned int reg; + unsigned int mask; + unsigned int spk_val; + unsigned int rcv_val; +}; + +struct aw_soft_rst { + int reg; + int reg_value; +}; + +struct aw_pwd_desc { + unsigned int reg; + unsigned int mask; + unsigned int enable; + unsigned int disable; +}; + +struct aw_amppd_desc { + unsigned int reg; + unsigned int mask; + unsigned int enable; + unsigned int disable; +}; + +struct aw_bop_desc { + unsigned int reg; + unsigned int mask; + unsigned int enable; + unsigned int disbale; +}; + +struct aw_vcalb_desc { + unsigned int icalk_reg; + unsigned int icalk_reg_mask; + unsigned int icalk_shift; + unsigned int icalkl_reg; + unsigned int icalkl_reg_mask; + unsigned int icalkl_shift; + unsigned int icalk_sign_mask; + unsigned int icalk_neg_mask; + int icalk_value_factor; + + unsigned int vcalk_reg; + unsigned int vcalk_reg_mask; + unsigned int vcalk_shift; + unsigned int vcalkl_reg; + unsigned int vcalkl_reg_mask; + unsigned int vcalkl_shift; + unsigned int vcalk_sign_mask; + unsigned int vcalk_neg_mask; + int vcalk_value_factor; + + unsigned int vcalb_reg; + int cabl_base_value; + int vcal_factor; +}; + +struct aw_mute_desc { + unsigned int reg; + unsigned int mask; + unsigned int enable; + unsigned int disable; +}; + +struct aw_uls_hmute_desc { + unsigned int reg; + unsigned int mask; + unsigned int enable; + unsigned int disable; +}; + +struct aw_txen_desc { + unsigned int reg; + unsigned int mask; + unsigned int enable; + unsigned int disable; + unsigned int reserve_val; +}; + +struct aw_sysst_desc { + unsigned int reg; + unsigned int mask; + unsigned int st_check; + unsigned int st_sws_check; + unsigned int pll_check; +}; + +struct aw_profctrl_desc { + unsigned int reg; + unsigned int mask; + unsigned int spk_mode; + unsigned int cfg_prof_mode; +}; + +struct aw_bstctrl_desc { + unsigned int reg; + unsigned int mask; + unsigned int frc_bst; + unsigned int tsp_type; + unsigned int cfg_bst_type; +}; + +struct aw_cco_mux_desc { + unsigned int reg; + unsigned int mask; + unsigned int divided_val; + unsigned int bypass_val; +}; + +struct aw_volume_desc { + unsigned int reg; + unsigned int mask; + unsigned int shift; + int init_volume; + int mute_volume; + int ctl_volume; + int monitor_volume; +}; + +struct aw_voltage_desc { + unsigned int reg; + unsigned int vbat_range; + unsigned int int_bit; +}; + +struct aw_temperature_desc { + unsigned int reg; + unsigned int sign_mask; + unsigned int neg_mask; +}; + +struct aw_ipeak_desc { + unsigned int reg; + unsigned int mask; +}; + +struct aw_spin_ch { + uint16_t rx_val; +}; + +struct aw_reg_ch { + unsigned int reg; + unsigned int mask; + unsigned int left_val; + unsigned int right_val; +}; + +struct aw_spin_desc { + int aw_spin_kcontrol_st; + struct aw_spin_ch spin_table[AW_SPIN_MAX]; + struct aw_reg_ch rx_desc; +}; + +struct aw_efcheck_desc { + unsigned int reg; + unsigned int mask; + unsigned int and_val; + unsigned int or_val; +}; + +struct aw_dither_desc { + unsigned int reg; + unsigned int mask; + unsigned int enable; + unsigned int disable; +}; + +struct aw_noise_gate_desc { + unsigned int reg; + unsigned int mask; +}; + +struct aw_psm_desc { + unsigned int reg; + unsigned int mask; + unsigned int enable; + unsigned int disable; +}; + +struct aw_mpd_desc { + unsigned int reg; + unsigned int mask; + unsigned int enable; + unsigned int disable; +}; + +struct aw_dsmzth_desc { + unsigned int reg; + unsigned int mask; + unsigned int enable; + unsigned int disable; +}; + +struct aw_auth_desc { + uint8_t reg_in; + uint8_t reg_out; + int32_t auth_mode; + int32_t reg_crc; + int32_t random; + int32_t chip_id; + int32_t check_result; +}; + +struct algo_auth_data { + int32_t auth_mode; /* 0: disable 1 : chip ID 2 : reg crc */ + int32_t reg_crc; + int32_t random; + int32_t chip_id; + int32_t check_result; +}; + +#define AW_IOCTL_MAGIC_S 'w' +#define AW_IOCTL_GET_ALGO_AUTH _IOWR(AW_IOCTL_MAGIC_S, 1, struct algo_auth_data) +#define AW_IOCTL_SET_ALGO_AUTH _IOWR(AW_IOCTL_MAGIC_S, 2, struct algo_auth_data) + + +struct aw_device { + int status; + unsigned int chip_id; + unsigned int monitor_start; + int bstcfg_enable; + int frcset_en; + int bop_en; + int efuse_check; + int fade_en; + unsigned int mute_st; + unsigned int amppd_st; + unsigned int dither_st; + unsigned int txen_st; + + unsigned char cur_prof; /*current profile index*/ + unsigned char set_prof; /*set profile index*/ + unsigned int channel; /*pa channel select*/ + unsigned int vol_step; + unsigned int re_max; + unsigned int re_min; + + struct device *dev; + struct i2c_client *i2c; + char monitor_name[AW_NAME_MAX]; + void *private_data; + + struct aw_int_desc int_desc; + struct aw_work_mode work_mode; + struct aw_pwd_desc pwd_desc; + struct aw_amppd_desc amppd_desc; + struct aw_mute_desc mute_desc; + struct aw_uls_hmute_desc uls_hmute_desc; + struct aw_txen_desc txen_desc; + struct aw_vcalb_desc vcalb_desc; + struct aw_sysst_desc sysst_desc; + struct aw_profctrl_desc profctrl_desc; + struct aw_bstctrl_desc bstctrl_desc; + struct aw_cco_mux_desc cco_mux_desc; + struct aw_voltage_desc voltage_desc; + struct aw_temperature_desc temp_desc; + struct aw_ipeak_desc ipeak_desc; + struct aw_volume_desc volume_desc; + struct aw_prof_info prof_info; + struct aw_cali_desc cali_desc; + struct aw_monitor_desc monitor_desc; + struct aw_soft_rst soft_rst; + struct aw_spin_desc spin_desc; + struct aw_bop_desc bop_desc; + struct aw_efcheck_desc efcheck_desc; + struct aw_dither_desc dither_desc; + struct aw_noise_gate_desc noise_gate_desc; + struct aw_psm_desc psm_desc; + struct aw_mpd_desc mpd_desc; + struct aw_dsmzth_desc dsmzth_desc; + struct aw_auth_desc auth_desc; + struct aw_device_ops ops; + struct list_head list_node; +}; + + +void aw882xx_dev_deinit(struct aw_device *aw_dev); +int aw882xx_device_init(struct aw_device *aw_dev, struct aw_container *aw_cfg); +int aw882xx_device_start(struct aw_device *aw_dev); +int aw882xx_device_stop(struct aw_device *aw_dev); +int aw882xx_dev_reg_update(struct aw_device *aw_dev, bool force); +int aw882xx_device_irq_reinit(struct aw_device *aw_dev); + +struct mutex *aw882xx_dev_get_ext_dsp_prof_wr_lock(void); +char *aw882xx_dev_get_ext_dsp_prof_write(void); + +/*re*/ +int aw882xx_dev_get_cali_re(struct aw_device *aw_dev, int32_t *cali_re); +int aw882xx_dev_init_cali_re(struct aw_device *aw_dev); +int aw882xx_dev_dc_status(struct aw_device *aw_dev); + +/*interrupt*/ +int aw882xx_dev_status(struct aw_device *aw_dev); +int aw882xx_dev_get_int_status(struct aw_device *aw_dev, uint16_t *int_status); +void aw882xx_dev_clear_int_status(struct aw_device *aw_dev); +int aw882xx_dev_set_intmask(struct aw_device *aw_dev, bool flag); + +/*fade int / out*/ +void aw882xx_dev_set_fade_vol_step(struct aw_device *aw_dev, unsigned int step); +int aw882xx_dev_get_fade_vol_step(struct aw_device *aw_dev); +void aw882xx_dev_get_fade_time(unsigned int *time, bool fade_in); +void aw882xx_dev_set_fade_time(unsigned int time, bool fade_in); + +/*dsp kcontrol*/ +int aw882xx_dev_set_afe_module_en(int type, int enable); +int aw882xx_dev_get_afe_module_en(int type, int *status); +int aw882xx_dev_set_copp_module_en(bool enable); + +int aw882xx_device_probe(struct aw_device *aw_dev); +int aw882xx_device_remove(struct aw_device *aw_dev); +int aw882xx_dev_get_list_head(struct list_head **head); + +int aw882xx_dev_set_volume(struct aw_device *aw_dev, unsigned int set_vol); +int aw882xx_dev_get_volume(struct aw_device *aw_dev, unsigned int *get_vol); +void aw882xx_dev_mute(struct aw_device *aw_dev, bool mute); + + +void aw882xx_dev_monitor_hal_get_time(struct aw_device *aw_dev, uint32_t *time); +void aw882xx_dev_monitor_hal_work(struct aw_device *aw_dev, uint32_t *vmax); + +int aw882xx_dev_algo_auth_mode(struct aw_device *aw_dev, struct algo_auth_data *algo_data); +void aw882xx_dev_iv_forbidden_output(struct aw_device *aw_dev, bool power_waste); + +#endif + diff --git a/sound/soc/codecs/aw882xx/aw882xx_dsp.c b/sound/soc/codecs/aw882xx/aw882xx_dsp.c new file mode 100644 index 000000000000..0083c261fc16 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_dsp.c @@ -0,0 +1,1309 @@ +// SPDX-License-Identifier: GPL-2.0 +/* aw882xx_dsp.c + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/*#define DEBUG*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aw882xx_device.h" +#include "aw882xx_dsp.h" +#include "aw882xx_log.h" +/*#include "aw882xx_afe.h"*/ + +static DEFINE_MUTEX(g_aw_dsp_msg_lock); +static DEFINE_MUTEX(g_aw_dsp_lock); + +#define AW_MSG_ID_ENABLE_CALI (0x00000001) +#define AW_MSG_ID_ENABLE_HMUTE (0x00000002) +#define AW_MSG_ID_F0_Q (0x00000003) +#define AW_MSG_ID_DIRECT_CUR_FLAG (0x00000006) +#define AW_MSG_ID_SPK_STATUS (0x00000007) +#define AW_MSG_ID_VERSION (0x00000008) +#define AW_MSG_ID_AUDIO_MIX (0x0000000B) +#define AW_MSG_ID_VERSION_NEW (0x00000012) + +/*dsp params id*/ +#define AW_MSG_ID_RX_SET_ENABLE (0x10013D11) +#define AW_MSG_ID_TX_SET_ENABLE (0x10013D13) +#define AW_MSG_ID_VMAX_L (0x10013D17) +#define AW_MSG_ID_VMAX_R (0x10013D18) +#define AW_MSG_ID_CALI_CFG_L (0x10013D19) +#define AW_MSG_ID_CALI_CFG_R (0x10013d1A) +#define AW_MSG_ID_RE_L (0x10013d1B) +#define AW_MSG_ID_RE_R (0x10013D1C) +#define AW_MSG_ID_NOISE_L (0x10013D1D) +#define AW_MSG_ID_NOISE_R (0x10013D1E) +#define AW_MSG_ID_F0_L (0x10013D1F) +#define AW_MSG_ID_F0_R (0x10013D20) +#define AW_MSG_ID_REAL_DATA_L (0x10013D21) +#define AW_MSG_ID_REAL_DATA_R (0x10013D22) +#define AW_MSG_ID_ALGO_AUTHENTICATION (0x10013D46) + +#define AFE_MSG_ID_MSG_0 (0x10013D2A) +#define AFE_MSG_ID_MSG_1 (0x10013D2B) +#define AFE_MSG_ID_MSG_2 (0x10013D36) +#define AFE_MSG_ID_MSG_3 (0x10013D33) + +#define AW_MSG_ID_PARAMS (0x10013D12) +#define AW_MSG_ID_PARAMS_1 (0x10013D2D) +#define AW_MSG_ID_PARAMS_2 (0x10013D32) +#define AW_MSG_ID_PARAMS_3 (0x10013D35) +#define AW_MSG_ID_PARAMS_DEFAULT (0x10013D37) + +#define AW_MSG_ID_SPIN (0x10013D2E) + +static int g_tx_topo_id = AW_TX_DEFAULT_TOPO_ID; +static int g_rx_topo_id = AW_RX_DEFAULT_TOPO_ID; +static int g_tx_port_id = AW_TX_DEFAULT_PORT_ID; +static int g_rx_port_id = AW_RX_DEFAULT_PORT_ID; + +enum { + MSG_PARAM_ID_0 = 0, + MSG_PARAM_ID_1, + MSG_PARAM_ID_2, + MSG_PARAM_ID_3, + MSG_PARAM_ID_MAX, +}; + +static uint32_t afe_param_msg_id[MSG_PARAM_ID_MAX] = { + AFE_MSG_ID_MSG_0, + AFE_MSG_ID_MSG_1, + AFE_MSG_ID_MSG_2, + AFE_MSG_ID_MSG_3, +}; + +/***************dsp communicate**************/ +#ifdef AW_QCOM_PLATFORM +#if (KERNEL_VERSION(4, 4, 1) <= LINUX_VERSION_CODE) +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#endif +#endif + +#define AW_COPP_MODULE_ID (0X10013D02) /*SKT module id*/ +#define AW_COPP_PARAMS_ID_AWDSP_ENABLE (0X10013D14) /*SKT enable param id*/ + +#ifdef AW_MTK_PLATFORM_WITH_DSP +extern int mtk_spk_send_ipi_buf_to_dsp(void *data_buffer, uint32_t data_size); +extern int mtk_spk_recv_ipi_buf_from_dsp(int8_t *buffer, int16_t size, uint32_t *buf_len); +#elif defined AW_QCOM_PLATFORM +extern int afe_get_topology(int port_id); +extern int aw_send_afe_cal_apr(uint32_t param_id, + void *buf, int cmd_size, bool write); +extern int aw_send_afe_rx_module_enable(void *buf, int size); +extern int aw_send_afe_tx_module_enable(void *buf, int size); +#else +static int aw_send_afe_cal_apr(uint32_t param_id, + void *buf, int cmd_size, bool write) +{ + return 0; +} +static int aw_send_afe_rx_module_enable(void *buf, int size) +{ + return 0; +} +static int aw_send_afe_tx_module_enable(void *buf, int size) +{ + return 0; +} +static int afe_get_topology(int port_id) +{ + return 0; +} + +#endif + +#ifdef AW_QCOM_PLATFORM +extern void aw_set_port_id(int tx_port_id, int rx_port_id); +#else +static void aw_set_port_id(int tx_port_id, int rx_port_id) +{ + +} +#endif + +static int aw_adm_param_enable(int port_id, int module_id, int param_id, int enable) +{ +#ifdef AW_QCOM_ADM_MSG + /*for v3*/ + int copp_idx = 0; + uint32_t enable_param; + struct param_hdr_v3 param_hdr; + int rc = 0; + + aw_pr_dbg("port_id %d, module_id 0x%x, enable %d", + port_id, module_id, enable); + + copp_idx = adm_get_default_copp_idx(port_id); + if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) { + aw_pr_err("Invalid copp_num: %d", copp_idx); + return -EINVAL; + } + + if (enable < 0 || enable > 1) { + aw_pr_err("Invalid value for enable %d", enable); + return -EINVAL; + } + + aw_pr_dbg("port_id %d, module_id 0x%x, copp_idx 0x%x, enable %d", + port_id, module_id, copp_idx, enable); + + memset(¶m_hdr, 0, sizeof(param_hdr)); + param_hdr.module_id = module_id; + param_hdr.instance_id = INSTANCE_ID_0; + param_hdr.param_id = param_id; + param_hdr.param_size = sizeof(enable_param); + enable_param = enable; + + rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr, + (uint8_t *) &enable_param); + if (rc) + aw_pr_err("Failed to set enable of module(%d) instance(%d) to %d, err %d", + module_id, INSTANCE_ID_0, enable, rc); + return rc; +#else + return 0; +#endif +} + +static int aw_dsp_get_msg_num(int dev_ch, int *msg_num) +{ + switch (dev_ch) { + case AW_DEV_CH_PRI_L: + *msg_num = MSG_PARAM_ID_0; + break; + case AW_DEV_CH_PRI_R: + *msg_num = MSG_PARAM_ID_0; + break; + case AW_DEV_CH_SEC_L: + *msg_num = MSG_PARAM_ID_1; + break; + case AW_DEV_CH_SEC_R: + *msg_num = MSG_PARAM_ID_1; + break; + case AW_DEV_CH_TERT_L: + *msg_num = MSG_PARAM_ID_2; + break; + case AW_DEV_CH_TERT_R: + *msg_num = MSG_PARAM_ID_2; + break; + case AW_DEV_CH_QUAT_L: + *msg_num = MSG_PARAM_ID_3; + break; + case AW_DEV_CH_QUAT_R: + *msg_num = MSG_PARAM_ID_3; + break; + default: + aw_pr_err("can not find msg num, channel %d ", dev_ch); + return -EINVAL; + } + + aw_pr_dbg("msg num[%d] ", *msg_num); + return 0; +} + +static void aw_dsp_get_check_sum(int pos, void *data, int size, int *check_sum) +{ + int i = 0; + int sum_data = 0; + + for (i = pos; i < size / sizeof(uint8_t); i++) + sum_data += *((uint8_t *)data + sizeof(uint8_t) * i); + + + *check_sum = sum_data; +} + +#ifdef AW_MTK_PLATFORM_WITH_DSP +/*****************mtk dsp communication function start**********************/ +static int aw_mtk_write_data_to_dsp(int param_id, void *data, int size) +{ + int ret = 0; + int32_t *dsp_data = NULL; + aw_dsp_msg_t *hdr = NULL; + + dsp_data = kzalloc(sizeof(aw_dsp_msg_t) + size, GFP_KERNEL); + if (!dsp_data) + return -ENOMEM; + + + hdr = (aw_dsp_msg_t *)dsp_data; + hdr->type = AW_DSP_MSG_TYPE_DATA; + hdr->opcode_id = param_id; + hdr->version = AW_DSP_MSG_HDR_VER; + + memcpy(((char *)dsp_data) + sizeof(aw_dsp_msg_t), + data, size); + + ret = mtk_spk_send_ipi_buf_to_dsp(dsp_data, + sizeof(aw_dsp_msg_t) + size); + if (ret < 0) { + aw_pr_err("write data failed"); + kfree(dsp_data); + dsp_data = NULL; + return ret; + } + + kfree(dsp_data); + dsp_data = NULL; + return ret; +} + +static int aw_mtk_read_data_from_dsp(int param_id, void *data, int size) +{ + int ret = 0; + aw_dsp_msg_t hdr; + + hdr.type = AW_DSP_MSG_TYPE_CMD; + hdr.opcode_id = param_id; + hdr.version = AW_DSP_MSG_HDR_VER; + + mutex_lock(&g_aw_dsp_msg_lock); + ret = mtk_spk_send_ipi_buf_to_dsp(&hdr, sizeof(aw_dsp_msg_t)); + if (ret < 0) { + aw_pr_err("send cmd failed"); + goto dsp_msg_failed; + } + + ret = mtk_spk_recv_ipi_buf_from_dsp(data, size, &size); + if (ret < 0) { + aw_pr_err("get data failed"); + goto dsp_msg_failed; + } + mutex_unlock(&g_aw_dsp_msg_lock); + return ret; + +dsp_msg_failed: + mutex_unlock(&g_aw_dsp_msg_lock); + return ret; +} + +/*****************mtk dsp communication function end**********************/ +#else +/*****************qcom dsp communication function start**********************/ +static int aw_afe_get_topology(uint32_t param_id) +{ + if (param_id == AW_MSG_ID_TX_SET_ENABLE) + return afe_get_topology(g_tx_port_id); + else + return afe_get_topology(g_rx_port_id); +} + +static void aw_check_dsp_ready(uint32_t param_id) +{ + int ret; + + ret = aw_afe_get_topology(param_id); + + if (param_id == AW_MSG_ID_TX_SET_ENABLE) { + if (ret != g_tx_topo_id) + aw_pr_err("tx topo id is 0x%x", ret); + } else { + if (ret != g_rx_topo_id) + aw_pr_err("rx topo id is 0x%x", ret); + } +} + +static int aw_qcom_write_data_to_dsp(uint32_t param_id, void *data, int size) +{ + int ret = 0; + + aw_check_dsp_ready(param_id); + mutex_lock(&g_aw_dsp_lock); + ret = aw_send_afe_cal_apr(param_id, data, size, true); + mutex_unlock(&g_aw_dsp_lock); + return ret; +} + +static int aw_qcom_read_data_from_dsp(uint32_t param_id, void *data, int size) +{ + int ret = 0; + + aw_check_dsp_ready(param_id); + mutex_lock(&g_aw_dsp_lock); + ret = aw_send_afe_cal_apr(param_id, data, size, false); + mutex_unlock(&g_aw_dsp_lock); + + return ret; +} +#endif + +/******************* afe module communication function ************************/ +static int aw_dsp_set_afe_rx_module_enable(void *buf, int size) +{ +#ifdef AW_MTK_PLATFORM_WITH_DSP + return aw_mtk_write_data_to_dsp(AW_MSG_ID_RX_SET_ENABLE, buf, size); +#else + return aw_send_afe_rx_module_enable(buf, size); +#endif +} + +static int aw_dsp_set_afe_tx_module_enable(void *buf, int size) +{ +#ifdef AW_MTK_PLATFORM_WITH_DSP + return aw_mtk_write_data_to_dsp(AW_MSG_ID_TX_SET_ENABLE, buf, size); +#else + return aw_send_afe_tx_module_enable(buf, size); +#endif +} + +static int aw_dsp_get_afe_rx_module_enable(void *buf, int size) +{ +#ifdef AW_MTK_PLATFORM_WITH_DSP + return aw_mtk_read_data_from_dsp(AW_MSG_ID_RX_SET_ENABLE, buf, size); +#else + return aw_qcom_read_data_from_dsp(AW_MSG_ID_RX_SET_ENABLE, buf, size); +#endif +} + +static int aw_dsp_get_afe_tx_module_enable(void *buf, int size) +{ +#ifdef AW_MTK_PLATFORM_WITH_DSP + return aw_mtk_read_data_from_dsp(AW_MSG_ID_TX_SET_ENABLE, buf, size); +#else + return aw_qcom_read_data_from_dsp(AW_MSG_ID_TX_SET_ENABLE, buf, size); +#endif +} + +/******************* read/write msg communication function ***********************/ +static int aw_read_msg_from_dsp(struct aw_device *aw_dev, + uint32_t msg_id, char *data_ptr, unsigned int data_size) +{ + int ret = 0; + int msg_num = -EINVAL; + aw_dsp_msg_t hdr[2]; + + ret = aw_dsp_get_msg_num(aw_dev->channel, &msg_num); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "get msg_num failed"); + return ret; + } + + hdr[0].type = AW_DSP_MSG_TYPE_DATA; + hdr[0].opcode_id = afe_param_msg_id[msg_num]; + hdr[0].version = AW_DSP_MSG_HDR_VER; + hdr[1].type = AW_DSP_MSG_TYPE_CMD; + hdr[1].opcode_id = msg_id; + hdr[1].version = AW_DSP_MSG_HDR_VER; + + mutex_lock(&g_aw_dsp_msg_lock); + +#ifdef AW_MTK_PLATFORM_WITH_DSP + ret = mtk_spk_send_ipi_buf_to_dsp(&hdr, 2 * sizeof(aw_dsp_msg_t)); +#else + ret = aw_qcom_write_data_to_dsp(afe_param_msg_id[msg_num], + &hdr[1], sizeof(aw_dsp_msg_t)); +#endif + if (ret < 0) { + aw_pr_err("msg_id:0x%x, send cmd failed", msg_id); + goto dsp_msg_failed; + } + +#ifdef AW_MTK_PLATFORM_WITH_DSP + ret = mtk_spk_recv_ipi_buf_from_dsp(data_ptr, data_size, &data_size); +#else + ret = aw_qcom_read_data_from_dsp(afe_param_msg_id[msg_num], + data_ptr, (int)data_size); +#endif + if (ret < 0) { + aw_pr_err("msg_id:0x%x, read data failed", msg_id); + goto dsp_msg_failed; + } + + + mutex_unlock(&g_aw_dsp_msg_lock); + return 0; + +dsp_msg_failed: + mutex_unlock(&g_aw_dsp_msg_lock); + return ret; +} + +static int aw_read_msg_from_dsp_v_1_0_0_0(struct aw_device *aw_dev, + uint32_t params_id, char *data_ptr, unsigned int len, int num) +{ + int ret = 0; + int sum_data = 0; + int32_t *dsp_msg = NULL; + aw_msg_hdr_t write_hdr; + aw_msg_hdr_t *read_hdr = NULL; +#ifdef AW_MTK_PLATFORM_WITH_DSP + int real_len = 0; +#endif + memset(&write_hdr, 0, sizeof(aw_msg_hdr_t)); + write_hdr.version = AW_DSP_MSG_VER; + write_hdr.type = DSP_MSG_TYPE_WRITE_CMD; + write_hdr.params_id = params_id; + write_hdr.channel = aw_dev->channel; + write_hdr.num = num; + write_hdr.data_size = len / num; + + aw_dsp_get_check_sum(sizeof(int32_t), &write_hdr, sizeof(aw_msg_hdr_t), &write_hdr.checksum); + + mutex_lock(&g_aw_dsp_msg_lock); +#ifdef AW_MTK_PLATFORM_WITH_DSP + ret = mtk_spk_send_ipi_buf_to_dsp(&write_hdr, sizeof(aw_msg_hdr_t)); +#else + ret = aw_qcom_write_data_to_dsp(AW_MSG_ID_PARAMS_DEFAULT, &write_hdr, sizeof(aw_msg_hdr_t)); +#endif + if (ret < 0) { + aw_pr_err("write data to dsp failed"); + goto write_hdr_error; + } + + dsp_msg = kzalloc(sizeof(aw_msg_hdr_t) + len, GFP_KERNEL); + if (!dsp_msg) { + ret = -ENOMEM; + goto kalloc_msg_error; + } + +#ifdef AW_MTK_PLATFORM_WITH_DSP + ret = mtk_spk_recv_ipi_buf_from_dsp((char *)dsp_msg, sizeof(aw_msg_hdr_t) + len, &real_len); +#else + ret = aw_qcom_read_data_from_dsp(AW_MSG_ID_PARAMS_DEFAULT, (char *)dsp_msg, + sizeof(aw_msg_hdr_t) + len); +#endif + + if (ret < 0) { + aw_pr_err("read data from dsp failed"); + goto read_msg_error; + } + + read_hdr = (aw_msg_hdr_t *)dsp_msg; + if (read_hdr->type != DSP_MSG_TYPE_READ_DATA) { + aw_pr_err("read_hdr type = %d not read data!", read_hdr->type); + ret = -EINVAL; + goto read_msg_error; + } + + aw_dsp_get_check_sum(sizeof(int32_t), dsp_msg, sizeof(aw_msg_hdr_t) + len, &sum_data); + + if (sum_data != read_hdr->checksum) { + aw_pr_err("aw_dsp_msg check sum error!"); + aw_pr_err("read_hdr->checksum=%d sum_data=%d", read_hdr->checksum, sum_data); + ret = -EINVAL; + goto read_msg_error; + } + + memcpy(data_ptr, ((char *)dsp_msg) + sizeof(aw_msg_hdr_t), len); + +read_msg_error: + kfree(dsp_msg); + dsp_msg = NULL; +write_hdr_error: +kalloc_msg_error: + mutex_unlock(&g_aw_dsp_msg_lock); + return ret; + +} + +int aw882xx_dsp_read_dsp_msg(struct aw_device *aw_dev, uint32_t msg_id, char *data_ptr, unsigned int size) +{ + int ret = 0; + + if (aw_dev->channel < AW_DEV_CH_TERT_L) { + ret = aw_read_msg_from_dsp(aw_dev, msg_id, data_ptr, size); + } else { + ret = aw_read_msg_from_dsp_v_1_0_0_0(aw_dev, msg_id, data_ptr, + size, AW_DSP_CHANNEL_DEFAULT_NUM); + } + + return ret; +} + +static int aw_write_msg_to_dsp(struct aw_device *aw_dev, + uint32_t msg_id, char *data_ptr, unsigned int data_size) +{ + int ret = 0; + int msg_num = -EINVAL; + int32_t *dsp_msg = NULL; + aw_dsp_msg_t *hdr = NULL; + + ret = aw_dsp_get_msg_num(aw_dev->channel, &msg_num); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "get msg_num failed"); + return ret; + } + + dsp_msg = kzalloc(sizeof(aw_dsp_msg_t) + data_size, + GFP_KERNEL); + if (!dsp_msg) + return -ENOMEM; + + hdr = (aw_dsp_msg_t *)dsp_msg; + hdr->type = AW_DSP_MSG_TYPE_DATA; + hdr->opcode_id = msg_id; + hdr->version = AW_DSP_MSG_HDR_VER; + + memcpy(((char *)dsp_msg) + sizeof(aw_dsp_msg_t), + data_ptr, data_size); + +#ifdef AW_MTK_PLATFORM_WITH_DSP + ret = aw_mtk_write_data_to_dsp(afe_param_msg_id[msg_num], (void *)dsp_msg, + sizeof(aw_dsp_msg_t) + data_size); +#else + ret = aw_qcom_write_data_to_dsp(afe_param_msg_id[msg_num], (void *)dsp_msg, + sizeof(aw_dsp_msg_t) + data_size); +#endif + if (ret < 0) { + aw_pr_err("msg_id:0x%x, write data failed", msg_id); + kfree(dsp_msg); + dsp_msg = NULL; + return ret; + } + + kfree(dsp_msg); + dsp_msg = NULL; + return ret; +} + +static int aw_write_msg_to_dsp_v_1_0_0_0(struct aw_device *aw_dev, + uint32_t params_id, void *data, unsigned int len, int num) +{ + int ret = 0; + int32_t *dsp_msg = NULL; + aw_msg_hdr_t *hdr = NULL; + + mutex_lock(&g_aw_dsp_msg_lock); + dsp_msg = kzalloc(sizeof(aw_msg_hdr_t) + len, GFP_KERNEL); + if (!dsp_msg) { + aw_pr_err("kzalloc dsp_msg error"); + ret = -ENOMEM; + goto kalloc_error; + } + hdr = (aw_msg_hdr_t *)dsp_msg; + hdr->version = AW_DSP_MSG_VER; + hdr->type = DSP_MSG_TYPE_WRITE_DATA; + hdr->params_id = params_id; + hdr->channel = aw_dev->channel; + hdr->num = num; + hdr->data_size = len / num; + + memcpy(((char *)dsp_msg) + sizeof(aw_msg_hdr_t), data, len); + + aw_dsp_get_check_sum(sizeof(int32_t), dsp_msg, sizeof(aw_msg_hdr_t) + len, &hdr->checksum); + +#ifdef AW_MTK_PLATFORM_WITH_DSP + ret = mtk_spk_send_ipi_buf_to_dsp(dsp_msg, sizeof(aw_msg_hdr_t) + len); +#else + ret = aw_qcom_write_data_to_dsp(AW_MSG_ID_PARAMS_DEFAULT, dsp_msg, sizeof(aw_msg_hdr_t) + len); +#endif + if (ret < 0) { + aw_pr_err("write data failed"); + goto write_msg_error; + } + +write_msg_error: + kfree(dsp_msg); + dsp_msg = NULL; +kalloc_error: + mutex_unlock(&g_aw_dsp_msg_lock); + return ret; + +} + +int aw882xx_dsp_write_dsp_msg(struct aw_device *aw_dev, uint32_t msg_id, char *data_ptr, unsigned int size) +{ + int ret = 0; + + if (aw_dev->channel < AW_DEV_CH_TERT_L) { + ret = aw_write_msg_to_dsp(aw_dev, msg_id, data_ptr, size); + } else { + ret = aw_write_msg_to_dsp_v_1_0_0_0(aw_dev, msg_id, data_ptr, + size, AW_DSP_CHANNEL_DEFAULT_NUM); + } + + return ret; +} + +/******************* read/write data communication function ***********************/ +static int aw_read_data_from_dsp(uint32_t param_id, void *data, int size) +{ +#ifdef AW_MTK_PLATFORM_WITH_DSP + return aw_mtk_read_data_from_dsp(param_id, data, size); +#else + return aw_qcom_read_data_from_dsp(param_id, data, size); +#endif +} + +static int aw_write_data_to_dsp(uint32_t param_id, void *data, int size) +{ +#ifdef AW_MTK_PLATFORM_WITH_DSP + return aw_mtk_write_data_to_dsp(param_id, data, size); +#else + return aw_qcom_write_data_to_dsp(param_id, data, size); +#endif +} + +/************************* dsp communication function *****************************/ +int aw882xx_dsp_set_afe_module_en(int type, int enable) +{ + int ret = 0; + + switch (type) { + case AW_RX_MODULE: + ret = aw_dsp_set_afe_rx_module_enable(&enable, sizeof(int32_t)); + break; + case AW_TX_MODULE: + ret = aw_dsp_set_afe_tx_module_enable(&enable, sizeof(int32_t)); + break; + default: + aw_pr_err("unsupported type %d", type); + return -EINVAL; + } + + return ret; +} + +int aw882xx_dsp_get_afe_module_en(int type, int *status) +{ + int ret = 0; + + switch (type) { + case AW_RX_MODULE: + ret = aw_dsp_get_afe_rx_module_enable(status, sizeof(int32_t)); + break; + case AW_TX_MODULE: + ret = aw_dsp_get_afe_tx_module_enable(status, sizeof(int32_t)); + break; + default: + aw_pr_err("unsupported type %d", type); + return -EINVAL; + } + + return ret; +} + +int aw882xx_dsp_read_te(struct aw_device *aw_dev, int32_t *te) +{ + int ret = 0; + int32_t data[8] = {0}; /*[re:r0:Te:r0_te]*/ + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, AW_MSG_ID_SPK_STATUS, + (char *)data, sizeof(int32_t) * 8); + if (ret) { + aw_dev_err(aw_dev->dev, " read Te failed "); + return ret; + } + + if ((aw_dev->channel % 2) == 0) + *te = data[2]; + else + *te = data[6]; + + aw_dev_dbg(aw_dev->dev, "read Te %d", *te); + return ret; +} + +int aw882xx_dsp_read_st(struct aw_device *aw_dev, int32_t *r0, int32_t *te) +{ + int ret = 0; + int32_t data[8] = {0}; /*[re:r0:Te:r0_te]*/ + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, AW_MSG_ID_SPK_STATUS, + (char *)data, sizeof(int32_t) * 8); + if (ret) { + aw_dev_err(aw_dev->dev, "read spk st failed"); + return ret; + } + + if ((aw_dev->channel % 2) == 0) { + *r0 = AW_DSP_RE_TO_SHOW_RE(data[0]); + *te = data[2]; + } else { + *r0 = AW_DSP_RE_TO_SHOW_RE(data[4]); + *te = data[6]; + } + aw_dev_dbg(aw_dev->dev, "read Re %d , Te %d", *r0, *te); + return ret; +} + +int aw882xx_dsp_read_spin(int *spin_mode) +{ + int ret = 0; + int32_t spin = 0; + + ret = aw_read_data_from_dsp(AW_MSG_ID_SPIN, &spin, sizeof(int32_t)); + if (ret) { + *spin_mode = 0; + aw_pr_err("read spin failed "); + return ret; + } + *spin_mode = spin; + aw_pr_dbg("read spin done"); + return ret; +} + +int aw882xx_dsp_write_spin(int spin_mode) +{ + int ret = 0; + int32_t spin = spin_mode; + + if (spin >= AW_SPIN_MAX) { + aw_pr_err("spin [%d] unsupported ", spin); + return -EINVAL; + } + + ret = aw_write_data_to_dsp(AW_MSG_ID_SPIN, &spin, sizeof(int32_t)); + if (ret) { + aw_pr_err("write spin failed "); + return ret; + } + aw_pr_dbg("write spin done"); + return ret; +} + +int aw882xx_dsp_read_r0(struct aw_device *aw_dev, int32_t *r0) +{ + uint32_t msg_id = -EINVAL; + int ret = 0; + int32_t data[6] = {0}; + + if (aw_dev->channel == AW_DEV_CH_PRI_L || + aw_dev->channel == AW_DEV_CH_SEC_L || + aw_dev->channel == AW_DEV_CH_TERT_L || + aw_dev->channel == AW_DEV_CH_QUAT_L) { + msg_id = AW_MSG_ID_REAL_DATA_L; + } else if (aw_dev->channel == AW_DEV_CH_PRI_R || + aw_dev->channel == AW_DEV_CH_SEC_R || + aw_dev->channel == AW_DEV_CH_TERT_R || + aw_dev->channel == AW_DEV_CH_QUAT_R) { + msg_id = AW_MSG_ID_REAL_DATA_R; + } else { + aw_dev_err(aw_dev->dev, "unsupport dev channel"); + return -EINVAL; + } + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, msg_id, (char *)data, sizeof(int32_t) * 6); + if (ret) { + aw_dev_err(aw_dev->dev, "read real re failed "); + return ret; + } + + *r0 = AW_DSP_RE_TO_SHOW_RE(data[0]); + aw_dev_dbg(aw_dev->dev, "read r0 %d\n", *r0); + return ret; +} + +int aw882xx_dsp_read_cali_data(struct aw_device *aw_dev, char *data, unsigned int data_len) +{ + uint32_t msg_id = -EINVAL; + int ret = 0; + + if (aw_dev->channel == AW_DEV_CH_PRI_L || + aw_dev->channel == AW_DEV_CH_SEC_L || + aw_dev->channel == AW_DEV_CH_TERT_L || + aw_dev->channel == AW_DEV_CH_QUAT_L) { + msg_id = AW_MSG_ID_REAL_DATA_L; + } else if (aw_dev->channel == AW_DEV_CH_PRI_R || + aw_dev->channel == AW_DEV_CH_SEC_R || + aw_dev->channel == AW_DEV_CH_TERT_R || + aw_dev->channel == AW_DEV_CH_QUAT_R) { + msg_id = AW_MSG_ID_REAL_DATA_R; + } else { + aw_dev_err(aw_dev->dev, "unsupport dev channel"); + return -EINVAL; + } + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, msg_id, data, data_len); + if (ret) { + aw_dev_err(aw_dev->dev, "read cali dara failed "); + return ret; + } + aw_dev_dbg(aw_dev->dev, "read cali_data"); + return ret; +} + + +int aw882xx_dsp_get_dc_status(struct aw_device *aw_dev) +{ + int ret = 0; + int32_t data[2] = {0}; + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, AW_MSG_ID_DIRECT_CUR_FLAG, (char *)data, sizeof(int32_t) * 2); + if (ret) { + aw_dev_err(aw_dev->dev, "read dc flag failed"); + return ret; + } + + if ((aw_dev->channel % 2) == 0) + ret = data[0]; + else + ret = data[1]; + + aw_dev_dbg(aw_dev->dev, "read direct current status:%d", ret); + return ret; +} + +int aw882xx_dsp_read_f0_q(struct aw_device *aw_dev, int32_t *f0, int32_t *q) +{ + int ret = 0; + int32_t data[4] = {0}; + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, AW_MSG_ID_F0_Q, (char *)data, sizeof(int32_t) * 4); + if (ret) { + aw_dev_err(aw_dev->dev, "read f0 & q failed"); + return ret; + } + + if ((aw_dev->channel % 2) == 0) { + *f0 = data[0]; + *q = data[1]; + } else { + *f0 = data[2]; + *q = data[3]; + } + aw_dev_dbg(aw_dev->dev, "read f0 is %d, q is %d", *f0, *q); + return ret; +} + +int aw882xx_dsp_read_f0(struct aw_device *aw_dev, int32_t *f0) +{ + int ret = 0; + uint32_t msg_id = -EINVAL; + + if (aw_dev->channel == AW_DEV_CH_PRI_L || + aw_dev->channel == AW_DEV_CH_SEC_L || + aw_dev->channel == AW_DEV_CH_TERT_L || + aw_dev->channel == AW_DEV_CH_QUAT_L) { + msg_id = AW_MSG_ID_F0_L; + } else if (aw_dev->channel == AW_DEV_CH_PRI_R || + aw_dev->channel == AW_DEV_CH_SEC_R || + aw_dev->channel == AW_DEV_CH_TERT_R || + aw_dev->channel == AW_DEV_CH_QUAT_R) { + msg_id = AW_MSG_ID_F0_R; + } else { + aw_dev_err(aw_dev->dev, "unsupport dev channel"); + return -EINVAL; + } + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, msg_id, (char *)f0, sizeof(int32_t)); + if (ret) { + aw_dev_err(aw_dev->dev, "read f0 failed"); + return ret; + } + aw_dev_dbg(aw_dev->dev, "read f0"); + return ret; +} + +int aw882xx_dsp_cali_en(struct aw_device *aw_dev, int32_t cali_msg_data) +{ + int ret = 0; + + ret = aw882xx_dsp_write_dsp_msg(aw_dev, AW_MSG_ID_ENABLE_CALI, (char *)&cali_msg_data, sizeof(int32_t)); + if (ret) { + aw_dev_err(aw_dev->dev, "write cali en failed"); + return ret; + } + aw_dev_dbg(aw_dev->dev, "write cali_en[%d]", cali_msg_data); + return ret; +} + +int aw882xx_dsp_hmute_en(struct aw_device *aw_dev, bool is_hmute) +{ + int ret = 0; + int32_t hmute = is_hmute; + + ret = aw882xx_dsp_write_dsp_msg(aw_dev, AW_MSG_ID_ENABLE_HMUTE, (char *)&hmute, sizeof(int32_t)); + if (ret) { + aw_dev_err(aw_dev->dev, "write hmue failed "); + return ret; + } + aw_dev_dbg(aw_dev->dev, "write hmute[%d]", is_hmute); + return ret; +} + +int aw882xx_dsp_read_cali_re(struct aw_device *aw_dev, int32_t *cali_re) +{ + int ret = 0; + uint32_t msg_id = -EINVAL; + int32_t read_re = 0; + + if (aw_dev->channel == AW_DEV_CH_PRI_L || + aw_dev->channel == AW_DEV_CH_SEC_L || + aw_dev->channel == AW_DEV_CH_TERT_L || + aw_dev->channel == AW_DEV_CH_QUAT_L) { + msg_id = AW_MSG_ID_RE_L; + } else if (aw_dev->channel == AW_DEV_CH_PRI_R || + aw_dev->channel == AW_DEV_CH_SEC_R || + aw_dev->channel == AW_DEV_CH_TERT_R || + aw_dev->channel == AW_DEV_CH_QUAT_R) { + msg_id = AW_MSG_ID_RE_R; + } else { + aw_dev_err(aw_dev->dev, "unsupport dev channel"); + return -EINVAL; + } + + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, msg_id, (char *)&read_re, sizeof(int32_t)); + if (ret) { + aw_dev_err(aw_dev->dev, "read cali re failed "); + return ret; + } + *cali_re = AW_DSP_RE_TO_SHOW_RE(read_re); + aw_dev_dbg(aw_dev->dev, "read cali re done"); + return ret; +} + +int aw882xx_dsp_write_cali_re(struct aw_device *aw_dev, int32_t cali_re) +{ + int ret = 0; + uint32_t msg_id = -EINVAL; + int32_t local_re = AW_SHOW_RE_TO_DSP_RE(cali_re); + + if (aw_dev->channel == AW_DEV_CH_PRI_L || + aw_dev->channel == AW_DEV_CH_SEC_L || + aw_dev->channel == AW_DEV_CH_TERT_L || + aw_dev->channel == AW_DEV_CH_QUAT_L) { + msg_id = AW_MSG_ID_RE_L; + } else if (aw_dev->channel == AW_DEV_CH_PRI_R || + aw_dev->channel == AW_DEV_CH_SEC_R || + aw_dev->channel == AW_DEV_CH_TERT_R || + aw_dev->channel == AW_DEV_CH_QUAT_R) { + msg_id = AW_MSG_ID_RE_R; + } else { + aw_dev_err(aw_dev->dev, "unsupport dev channel"); + return -EINVAL; + } + + ret = aw882xx_dsp_write_dsp_msg(aw_dev, msg_id, (char *)&local_re, sizeof(int32_t)); + if (ret) { + aw_dev_err(aw_dev->dev, "write cali re failed "); + return ret; + } + aw_dev_dbg(aw_dev->dev, "write cali re done"); + return ret; +} + +int aw882xx_dsp_write_params(struct aw_device *aw_dev, char *data, unsigned int data_len) +{ + int ret = 0; + uint32_t msg_id = -EINVAL; + int msg_num = -EINVAL; + + ret = aw_dsp_get_msg_num(aw_dev->channel, &msg_num); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "get msg_num failed"); + return ret; + } + + if (msg_num == MSG_PARAM_ID_0) { + msg_id = AW_MSG_ID_PARAMS; + } else if (msg_num == MSG_PARAM_ID_1) { + msg_id = AW_MSG_ID_PARAMS_1; + } else if (msg_num == MSG_PARAM_ID_2) { + msg_id = AW_MSG_ID_PARAMS_2; + } else if (msg_num == MSG_PARAM_ID_3) { + msg_id = AW_MSG_ID_PARAMS_3; + } else { + aw_dev_err(aw_dev->dev, "unsupport msg num"); + return ret; + } + + ret = aw_write_data_to_dsp(msg_id, data, data_len); + if (ret) { + aw_dev_err(aw_dev->dev, "write params failed"); + return ret; + } + aw_dev_dbg(aw_dev->dev, "write params done"); + return ret; +} + +#ifdef AW_ALGO_AUTH_DSP +int aw882xx_dsp_read_algo_auth_data(struct aw_device *aw_dev, + char *data, unsigned int data_len) +{ + int ret = 0; + + ret = aw_read_data_from_dsp(AW_MSG_ID_ALGO_AUTHENTICATION, data, data_len); + if (ret) + aw_dev_err(aw_dev->dev, "read algo auth failed"); + + aw_dev_dbg(aw_dev->dev, "read algo auth data done"); + + return ret; +} + +int aw882xx_dsp_write_algo_auth_data(struct aw_device *aw_dev, + char *data, unsigned int data_len) +{ + int ret = 0; + + ret = aw_write_data_to_dsp(AW_MSG_ID_ALGO_AUTHENTICATION, data, data_len); + if (ret) { + aw_pr_err("write algo auth failed "); + return ret; + } + aw_pr_dbg("write algo auth done"); + + return ret; +} +#endif + +int aw882xx_dsp_read_vmax(struct aw_device *aw_dev, char *data, unsigned int data_len) +{ + int ret = 0; + uint32_t msg_id = -EINVAL; + + if (aw_dev->channel == AW_DEV_CH_PRI_L || + aw_dev->channel == AW_DEV_CH_SEC_L || + aw_dev->channel == AW_DEV_CH_TERT_L || + aw_dev->channel == AW_DEV_CH_QUAT_L) { + msg_id = AW_MSG_ID_VMAX_L; + } else if (aw_dev->channel == AW_DEV_CH_PRI_R || + aw_dev->channel == AW_DEV_CH_SEC_R || + aw_dev->channel == AW_DEV_CH_TERT_R || + aw_dev->channel == AW_DEV_CH_QUAT_R) { + msg_id = AW_MSG_ID_VMAX_R; + } else { + aw_dev_err(aw_dev->dev, "unsupport dev channel"); + return -EINVAL; + } + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, msg_id, data, data_len); + if (ret) { + aw_dev_err(aw_dev->dev, "read vmax failed"); + return ret; + } + aw_dev_dbg(aw_dev->dev, "read vmax done"); + return ret; +} + +int aw882xx_dsp_write_vmax(struct aw_device *aw_dev, char *data, unsigned int data_len) +{ + int ret = 0; + uint32_t msg_id = -EINVAL; + + if (aw_dev->channel == AW_DEV_CH_PRI_L || + aw_dev->channel == AW_DEV_CH_SEC_L || + aw_dev->channel == AW_DEV_CH_TERT_L || + aw_dev->channel == AW_DEV_CH_QUAT_L) { + msg_id = AW_MSG_ID_VMAX_L; + } else if (aw_dev->channel == AW_DEV_CH_PRI_R || + aw_dev->channel == AW_DEV_CH_SEC_R || + aw_dev->channel == AW_DEV_CH_TERT_R || + aw_dev->channel == AW_DEV_CH_QUAT_R) { + msg_id = AW_MSG_ID_VMAX_R; + } else { + aw_dev_err(aw_dev->dev, "unsupport dev channel"); + return -EINVAL; + } + + ret = aw882xx_dsp_write_dsp_msg(aw_dev, msg_id, data, data_len); + if (ret) { + aw_dev_err(aw_dev->dev, "write vmax failed "); + return ret; + } + aw_dev_dbg(aw_dev->dev, "write vmax done"); + return ret; +} + +int aw882xx_dsp_noise_en(struct aw_device *aw_dev, bool is_noise) +{ + int ret = 0; + int32_t noise = is_noise; + uint32_t msg_id = -EINVAL; + + if (aw_dev->channel == AW_DEV_CH_PRI_L || + aw_dev->channel == AW_DEV_CH_SEC_L || + aw_dev->channel == AW_DEV_CH_TERT_L || + aw_dev->channel == AW_DEV_CH_QUAT_L) { + msg_id = AW_MSG_ID_NOISE_L; + } else if (aw_dev->channel == AW_DEV_CH_PRI_R || + aw_dev->channel == AW_DEV_CH_SEC_R || + aw_dev->channel == AW_DEV_CH_TERT_R || + aw_dev->channel == AW_DEV_CH_QUAT_R) { + msg_id = AW_MSG_ID_NOISE_R; + } else { + aw_dev_err(aw_dev->dev, "unsupport dev channel"); + return -EINVAL; + } + + ret = aw882xx_dsp_write_dsp_msg(aw_dev, msg_id, (char *)&noise, sizeof(int32_t)); + if (ret) { + aw_dev_err(aw_dev->dev, "write noise failed "); + return ret; + } + aw_dev_dbg(aw_dev->dev, "write noise[%d] done", noise); + return ret; +} + +int aw882xx_dsp_read_cali_cfg(struct aw_device *aw_dev, char *data, unsigned int data_len) +{ + int ret = 0; + uint32_t msg_id = -EINVAL; + + if (aw_dev->channel == AW_DEV_CH_PRI_L || + aw_dev->channel == AW_DEV_CH_SEC_L || + aw_dev->channel == AW_DEV_CH_TERT_L || + aw_dev->channel == AW_DEV_CH_QUAT_L) { + msg_id = AW_MSG_ID_CALI_CFG_L; + } else if (aw_dev->channel == AW_DEV_CH_PRI_R || + aw_dev->channel == AW_DEV_CH_SEC_R || + aw_dev->channel == AW_DEV_CH_TERT_R || + aw_dev->channel == AW_DEV_CH_QUAT_R) { + msg_id = AW_MSG_ID_CALI_CFG_R; + } else { + aw_dev_err(aw_dev->dev, "unsupport dev channel"); + return -EINVAL; + } + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, msg_id, data, data_len); + if (ret) { + aw_dev_err(aw_dev->dev, "read cali_cfg failed "); + return ret; + } + aw_dev_dbg(aw_dev->dev, "read cali_cfg done"); + return ret; +} + +int aw882xx_dsp_write_cali_cfg(struct aw_device *aw_dev, char *data, unsigned int data_len) +{ + int ret = 0; + uint32_t msg_id = -EINVAL; + + if (aw_dev->channel == AW_DEV_CH_PRI_L || + aw_dev->channel == AW_DEV_CH_SEC_L || + aw_dev->channel == AW_DEV_CH_TERT_L || + aw_dev->channel == AW_DEV_CH_QUAT_L) { + msg_id = AW_MSG_ID_CALI_CFG_L; + } else if (aw_dev->channel == AW_DEV_CH_PRI_R || + aw_dev->channel == AW_DEV_CH_SEC_R || + aw_dev->channel == AW_DEV_CH_TERT_R || + aw_dev->channel == AW_DEV_CH_QUAT_R) { + msg_id = AW_MSG_ID_CALI_CFG_R; + } else { + aw_dev_err(aw_dev->dev, "unsupport dev channel"); + return -EINVAL; + } + + ret = aw882xx_dsp_write_dsp_msg(aw_dev, msg_id, data, data_len); + if (ret) { + aw_dev_err(aw_dev->dev, "write cali_cfg failed "); + return ret; + } + + aw_dev_dbg(aw_dev->dev, "write cali_cfg done"); + return ret; +} + +int aw882xx_dsp_set_copp_module_en(bool enable) +{ + int ret = 0; + + ret = aw_adm_param_enable(g_rx_port_id, AW_COPP_MODULE_ID, + AW_COPP_PARAMS_ID_AWDSP_ENABLE, enable); + if (ret) + return -EINVAL; + + aw_pr_info("set skt %s", enable == 1 ? "enable" : "disable"); + return ret; +} + + +int aw882xx_dsp_set_mixer_en(struct aw_device *aw_dev, uint32_t mixer_en) +{ + int ret = 0; + + ret = aw882xx_dsp_write_dsp_msg(aw_dev, AW_MSG_ID_AUDIO_MIX, (char *)&mixer_en, sizeof(uint32_t)); + if (ret) { + aw_dev_err(aw_dev->dev, "write mixer_en failed"); + return ret; + } + aw_dev_dbg(aw_dev->dev, "write mixer_en[%d]", mixer_en); + return ret; + +} + +int aw882xx_get_algo_version(struct aw_device *aw_dev, char *algo_ver_buf) +{ + int ret = 0; + unsigned int algo_ver = 0; + char *algo_data = NULL; + + ret = aw882xx_dsp_read_dsp_msg(aw_dev, AW_MSG_ID_VERSION, + (char *)&algo_ver, sizeof(uint32_t)); + if ((ret < 0) || (algo_ver == 0)) { + ret = aw882xx_dsp_read_dsp_msg(aw_dev, AW_MSG_ID_VERSION_NEW, + algo_ver_buf, ALGO_VERSION_MAX); + if (ret < 0) + return ret; + } else { + algo_data = (char *)&algo_ver; + snprintf(algo_ver_buf, ALGO_VERSION_MAX, "aw_algo_v%d.%d.%d.%d", + algo_data[3], algo_data[2], algo_data[1], algo_data[0]); + } + + aw_dev_dbg(aw_dev->dev, "%s", algo_ver_buf); + return ret; +} + +void aw882xx_device_parse_topo_id_dt(struct aw_device *aw_dev) +{ + int ret = 0; + + ret = of_property_read_u32(aw_dev->dev->of_node, "aw-tx-topo-id", &g_tx_topo_id); + if (ret < 0) { + g_tx_topo_id = AW_TX_DEFAULT_TOPO_ID; + aw_dev_info(aw_dev->dev, "read aw-tx-topo-id failed,use default"); + } + + ret = of_property_read_u32(aw_dev->dev->of_node, "aw-rx-topo-id", &g_rx_topo_id); + if (ret < 0) { + g_rx_topo_id = AW_RX_DEFAULT_TOPO_ID; + aw_dev_info(aw_dev->dev, "read aw-rx-topo-id failed,use default"); + } + + aw_dev_info(aw_dev->dev, "tx-topo-id: 0x%x, rx-topo-id: 0x%x", + g_tx_topo_id, g_rx_topo_id); +} + +void aw882xx_device_parse_port_id_dt(struct aw_device *aw_dev) +{ + int ret = 0; + + ret = of_property_read_u32(aw_dev->dev->of_node, "aw-tx-port-id", &g_tx_port_id); + if (ret < 0) { + g_tx_port_id = AW_TX_DEFAULT_PORT_ID; + aw_dev_info(aw_dev->dev, "read aw-tx-port-id failed,use default"); + } + + ret = of_property_read_u32(aw_dev->dev->of_node, "aw-rx-port-id", &g_rx_port_id); + if (ret < 0) { + g_rx_port_id = AW_RX_DEFAULT_PORT_ID; + aw_dev_info(aw_dev->dev, "read aw-rx-port-id failed,use default"); + } + + aw_set_port_id(g_tx_port_id, g_rx_port_id); + aw_dev_info(aw_dev->dev, "tx-port-id: 0x%x, rx-port-id: 0x%x", + g_tx_port_id, g_rx_port_id); + +} + diff --git a/sound/soc/codecs/aw882xx/aw882xx_dsp.h b/sound/soc/codecs/aw882xx/aw882xx_dsp.h new file mode 100644 index 000000000000..f2a36d68c9c3 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_dsp.h @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: GPL-2.0 + * aw882xx_dsp.h + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_DSP_H__ +#define __AW882XX_DSP_H__ + +//#define AW_MTK_PLATFORM_WITH_DSP + +//#define AW_QCOM_ADM_MSG +/*#define AW_ALGO_AUTH_DSP*/ +/*factor form 12bit(4096) to 1000*/ +#define AW_DSP_RE_TO_SHOW_RE(re) (((re) * (1000)) >> (12)) +#define AW_SHOW_RE_TO_DSP_RE(re) (((re) << 12) / (1000)) + +#define AW_DSP_SLEEP_TIME (10) + +#define AW_TX_DEFAULT_TOPO_ID (0x1000FF00) +#define AW_RX_DEFAULT_TOPO_ID (0x1000FF01) +#define AW_TX_DEFAULT_PORT_ID (0x1007) +#define AW_RX_DEFAULT_PORT_ID (0x1006) + +#define AW_DSP_MSG_VER (0x10000000) +#define AW_DSP_CHANNEL_DEFAULT_NUM (1) + +enum aw_dsp_msg_type { + AW_DSP_MSG_TYPE_DATA = 0, + AW_DSP_MSG_TYPE_CMD = 1, +}; + +enum { + AW_SPIN_0 = 0, + AW_SPIN_90, + AW_SPIN_180, + AW_SPIN_270, + AW_SPIN_MAX, +}; + + +enum { + AW_AUDIO_MIX_DSIABLE = 0, + AW_AUDIO_MIX_ENABLE, +}; + +#define AW_DSP_MSG_HDR_VER (1) +typedef struct aw_msg_hdr aw_dsp_msg_t; + +enum { + DSP_MSG_TYPE_WRITE_CMD = 0, + DSP_MSG_TYPE_WRITE_DATA, + DSP_MSG_TYPE_READ_DATA, +}; + +typedef struct aw_msg_hdr_v_1_0_0_0 { + int32_t checksum; + int32_t version; + int32_t type; + int32_t params_id; + int32_t channel; + int32_t num; + int32_t data_size; + int32_t reseriver[3]; +} aw_msg_hdr_t; + +int aw882xx_dsp_read_dsp_msg(struct aw_device *aw_dev, uint32_t msg_id, char *data_ptr, unsigned int size); +int aw882xx_dsp_write_dsp_msg(struct aw_device *aw_dev, uint32_t msg_id, char *data_ptr, unsigned int size); +int aw882xx_dsp_write_cali_cfg(struct aw_device *aw_dev, char *data, unsigned int data_len); +int aw882xx_dsp_read_cali_cfg(struct aw_device *aw_dev, char *data, unsigned int data_len); +int aw882xx_dsp_noise_en(struct aw_device *aw_dev, bool is_noise); +int aw882xx_dsp_write_vmax(struct aw_device *aw_dev, char *data, unsigned int data_len); +int aw882xx_dsp_read_vmax(struct aw_device *aw_dev, char *data, unsigned int data_len); +int aw882xx_dsp_write_params(struct aw_device *aw_dev, char *data, unsigned int data_len); +int aw882xx_dsp_write_cali_re(struct aw_device *aw_dev, int32_t cali_re); +int aw882xx_dsp_read_cali_re(struct aw_device *aw_dev, int32_t *cali_re); +int aw882xx_dsp_read_r0(struct aw_device *aw_dev, int32_t *r0); +int aw882xx_dsp_read_st(struct aw_device *aw_dev, int32_t *r0, int32_t *te); +int aw882xx_dsp_read_te(struct aw_device *aw_dev, int32_t *te); +int aw882xx_dsp_get_dc_status(struct aw_device *aw_dev); +int aw882xx_dsp_hmute_en(struct aw_device *aw_dev, bool is_hmute); +int aw882xx_dsp_cali_en(struct aw_device *aw_dev, int32_t cali_msg_data); +int aw882xx_dsp_read_f0(struct aw_device *aw_dev, int32_t *f0); +int aw882xx_dsp_read_f0_q(struct aw_device *aw_dev, int32_t *f0, int32_t *q); +int aw882xx_dsp_read_cali_data(struct aw_device *aw_dev, char *data, unsigned int data_len); +int aw882xx_dsp_set_afe_module_en(int type, int enable); +int aw882xx_dsp_get_afe_module_en(int type, int *status); +int aw882xx_dsp_set_copp_module_en(bool enable); +int aw882xx_dsp_write_spin(int spin_mode); +int aw882xx_dsp_read_spin(int *spin_mode); +int aw882xx_get_algo_version(struct aw_device *aw_dev, char *algo_ver_buf); +void aw882xx_device_parse_topo_id_dt(struct aw_device *aw_dev); +void aw882xx_device_parse_port_id_dt(struct aw_device *aw_dev); +int aw882xx_dsp_set_mixer_en(struct aw_device *aw_dev, uint32_t mixer_en); +#ifdef AW_ALGO_AUTH_DSP +int aw882xx_dsp_read_algo_auth_data(struct aw_device *aw_dev, + char *data, unsigned int data_len); +int aw882xx_dsp_write_algo_auth_data(struct aw_device *aw_dev, + char *data, unsigned int data_len); +#endif +#endif + diff --git a/sound/soc/codecs/aw882xx/aw882xx_init.c b/sound/soc/codecs/aw882xx/aw882xx_init.c new file mode 100644 index 000000000000..a4ce5fc91c85 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_init.c @@ -0,0 +1,2277 @@ +// SPDX-License-Identifier: GPL-2.0 +/* aw_init.c aw882xx codec module + * + * + * Copyright (c) 2019 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/* #define DEBUG */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aw882xx.h" +#include "aw882xx_pid_1852_reg.h" +#include "aw882xx_pid_2013_reg.h" +#include "aw882xx_pid_2032_reg.h" +#include "aw882xx_pid_2055a_reg.h" +#include "aw882xx_pid_2055_reg.h" +#include "aw882xx_pid_2071_reg.h" +#include "aw882xx_pid_2113_reg.h" +#include "aw882xx_pid_2308_reg.h" +#include "aw882xx_log.h" + +static int aw882xx_dev_i2c_write_bits(struct aw_device *aw_dev, + unsigned char reg_addr, unsigned int mask, unsigned int reg_data) +{ + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + return aw882xx_i2c_write_bits(aw882xx, reg_addr, mask, reg_data); +} + +static int aw882xx_dev_i2c_write(struct aw_device *aw_dev, + unsigned char reg_addr, unsigned int reg_data) +{ + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + return aw882xx_i2c_write(aw882xx, reg_addr, reg_data); +} + +static int aw882xx_dev_i2c_read(struct aw_device *aw_dev, + unsigned char reg_addr, unsigned int *reg_data) +{ + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + return aw882xx_i2c_read(aw882xx, reg_addr, reg_data); +} + +static void aw882xx_dev_set_algo_en(struct aw_device *aw_dev) +{ + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + aw882xx_kcontorl_set(aw882xx); +} + +/* [7 : 4]: -6DB ; [3 : 0]: 0.5DB real_value = value * 2 : 0.5db --> 1 */ +static unsigned int aw_pid_1852_reg_val_to_db(unsigned int value) +{ + return ((value >> 4) * AW_PID_1852_VOL_STEP_DB + (value & 0x0f)); +} + +/* [7 : 4]: -6DB ; [3 : 0]: -0.5DB reg_value = value / step << 4 + value % step ; step = 6 * 2 */ +static unsigned int aw_pid_1852_db_val_to_reg(unsigned int value) +{ + return (((value / AW_PID_1852_VOL_STEP_DB) << 4) + (value % AW_PID_1852_VOL_STEP_DB)); +} + +static int aw_pid_1852_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + struct aw_volume_desc *vol_desc = &aw882xx->aw_pa->volume_desc; + + real_value = aw_pid_1852_db_val_to_reg(AW_GET_MIN_VALUE(value, vol_desc->mute_volume)); + + /* cal real value */ + aw882xx_i2c_read(aw882xx, AW_PID_1852_HAGCCFG4_REG, ®_value); + + aw_dev_dbg(aw882xx->dev, "value %d , 0x%x", value, real_value); + + /* 15 : 8] volume */ + real_value = (real_value << 8) | (reg_value & 0x00ff); + + /* write value */ + aw882xx_i2c_write(aw882xx, AW_PID_1852_HAGCCFG4_REG, real_value); + return 0; +} + +static int aw_pid_1852_get_volume(struct aw_device *aw_dev, unsigned int *value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + /* read value */ + aw882xx_i2c_read(aw882xx, AW_PID_1852_HAGCCFG4_REG, ®_value); + + /* [15 : 8] volume */ + real_value = reg_value >> 8; + + real_value = aw_pid_1852_reg_val_to_db(real_value); + *value = real_value; + + return 0; +} + +static bool aw_pid_1852_check_rd_access(int reg) +{ + if (reg >= AW_PID_1852_REG_MAX) + return false; + + + if (aw_pid_1852_reg_access[reg] & AW_PID_1852_REG_RD_ACCESS) + return true; + else + return false; +} + +static bool aw_pid_1852_check_wr_access(int reg) +{ + if (reg >= AW_PID_1852_REG_MAX) + return false; + + + if (aw_pid_1852_reg_access[reg] & AW_PID_1852_REG_WR_ACCESS) + return true; + else + return false; +} + +static int aw_pid_1852_get_reg_num(void) +{ + return AW_PID_1852_REG_MAX; +} + +static unsigned int aw_pid_1852_get_irq_type(struct aw_device *aw_dev, + unsigned int value) +{ + unsigned int ret = INT_TYPE_NONE; + /* UVL0 */ + if (value & (~AW_PID_1852_UVLI_MASK)) { + aw_dev_info(aw_dev->dev, "UVLO: occur"); + ret |= INT_TYPE_UVLO; + } + + /* BSTOCM */ + if (value & (~AW_PID_1852_BSTOCI_MASK)) { + aw_dev_info(aw_dev->dev, "BSTOCI: occur"); + ret |= INT_TYPE_BSTOC; + } + + /* OCDI */ + if (value & (~AW_PID_1852_OCDI_MASK)) { + aw_dev_info(aw_dev->dev, "OCDI: occur"); + ret |= INT_TYPE_OCDI; + } + + /* OTHI */ + if (value & (~AW_PID_1852_OTHI_MASK)) { + aw_dev_info(aw_dev->dev, "OTHI: occur"); + ret |= INT_TYPE_OTHI; + } + + return ret; +} + +static int aw_pid_1852_dev_init(struct aw882xx *aw882xx) +{ + int ret; + struct aw_device *aw_pa = aw882xx->aw_pa; + + /* call aw device init func */ + memset(aw_pa->monitor_name, 0, AW_NAME_MAX); + memcpy(aw_pa->monitor_name, AW_PID_1852_MONITOR_FILE, strlen(AW_PID_1852_MONITOR_FILE)); + + aw_pa->prof_info.prof_desc = NULL; + aw_pa->prof_info.count = 0; + aw_pa->channel = 0; + aw_pa->bstcfg_enable = AW_BSTCFG_DISABLE; + aw_pa->bop_en = AW_BOP_DISABLE; + aw_pa->vol_step = AW_PID_1852_VOL_STEP; + + aw_pa->private_data = (void *)aw882xx; + aw_pa->dev = aw882xx->dev; + aw_pa->i2c = aw882xx->i2c; + aw_pa->ops.aw_get_version = aw882xx_get_version; + aw_pa->ops.aw_get_dev_num = aw882xx_get_dev_num; + aw_pa->ops.aw_set_algo = aw882xx_dev_set_algo_en; + aw_pa->ops.aw_i2c_read = aw882xx_dev_i2c_read; + aw_pa->ops.aw_i2c_write = aw882xx_dev_i2c_write; + aw_pa->ops.aw_i2c_write_bits = aw882xx_dev_i2c_write_bits; + aw_pa->ops.aw_get_hw_volume = aw_pid_1852_get_volume; + aw_pa->ops.aw_set_hw_volume = aw_pid_1852_set_volume; + aw_pa->ops.aw_reg_val_to_db = aw_pid_1852_reg_val_to_db; + aw_pa->ops.aw_check_rd_access = aw_pid_1852_check_rd_access; + aw_pa->ops.aw_check_wr_access = aw_pid_1852_check_wr_access; + aw_pa->ops.aw_get_reg_num = aw_pid_1852_get_reg_num; + aw_pa->ops.aw_get_irq_type = aw_pid_1852_get_irq_type; + + aw_pa->int_desc.mask_reg = AW_PID_1852_SYSINTM_REG; + aw_pa->int_desc.mask_default = AW_PID_1852_SYSINTM_DEFAULT; + aw_pa->int_desc.int_mask = AW_PID_1852_SYSINTM_DEFAULT; + aw_pa->int_desc.st_reg = AW_PID_1852_SYSINT_REG; + + aw_pa->work_mode.reg = AW_PID_1852_SYSCTRL_REG; + aw_pa->work_mode.mask = AW_PID_1852_RCV_MODE_MASK; + aw_pa->work_mode.spk_val = AW_PID_1852_RCV_MODE_SPEAKER_MODE_VCOM13PVDD_VALUE; + aw_pa->work_mode.rcv_val = AW_PID_1852_RCV_MODE_RECEIVER_MODE_VCOM12PVDD_VALUE; + + aw_pa->pwd_desc.reg = AW_PID_1852_SYSCTRL_REG; + aw_pa->pwd_desc.mask = AW_PID_1852_PWDN_MASK; + aw_pa->pwd_desc.enable = AW_PID_1852_PWDN_POWER_DOWN_VALUE; + aw_pa->pwd_desc.disable = AW_PID_1852_PWDN_NORMAL_WORKING_VALUE; + + aw_pa->amppd_desc.reg = AW_PID_1852_SYSCTRL_REG; + aw_pa->amppd_desc.mask = AW_PID_1852_AMPPD_MASK; + aw_pa->amppd_desc.enable = AW_PID_1852_AMPPD_POWER_DOWN_VALUE; + aw_pa->amppd_desc.disable = AW_PID_1852_AMPPD_NORMAL_WORKING_VALUE; + + aw_pa->mute_desc.reg = AW_PID_1852_SYSCTRL2_REG; + aw_pa->mute_desc.mask = AW_PID_1852_HMUTE_MASK; + aw_pa->mute_desc.enable = AW_PID_1852_HMUTE_ENABLE_VALUE; + aw_pa->mute_desc.disable = AW_PID_1852_HMUTE_DISABLE_VALUE; + + aw_pa->uls_hmute_desc.reg = AW_REG_NONE; + + aw_pa->txen_desc.reg = AW_PID_1852_I2SCFG1_REG; + aw_pa->txen_desc.mask = AW_PID_1852_I2STXEN_MASK; + aw_pa->txen_desc.enable = AW_PID_1852_I2STXEN_ENABLE_VALUE; + aw_pa->txen_desc.disable = AW_PID_1852_I2STXEN_DISABLE_VALUE; + + aw_pa->vcalb_desc.vcalb_reg = AW_PID_1852_VTMCTRL3_REG; + aw_pa->vcalb_desc.vcal_factor = AW_PID_1852_VCAL_FACTOR; + aw_pa->vcalb_desc.cabl_base_value = AW_PID_1852_CABL_BASE_VALUE; + + aw_pa->vcalb_desc.icalk_value_factor = AW_PID_1852_ICABLK_FACTOR; + aw_pa->vcalb_desc.icalk_reg = AW_PID_1852_EFRM1_REG; + aw_pa->vcalb_desc.icalkl_reg = AW_REG_NONE; + aw_pa->vcalb_desc.icalk_reg_mask = AW_PID_1852_EF_ISN_GESLP_MASK; + aw_pa->vcalb_desc.icalk_sign_mask = AW_PID_1852_EF_ISN_GESLP_SIGN_MASK; + aw_pa->vcalb_desc.icalk_neg_mask = AW_PID_1852_EF_ISN_GESLP_NEG; + + aw_pa->vcalb_desc.vcalk_reg = AW_PID_1852_EFRH_REG; + aw_pa->vcalb_desc.vcalk_reg_mask = AW_PID_1852_EF_VSN_GESLP_MASK; + aw_pa->vcalb_desc.vcalkl_reg = AW_REG_NONE; + aw_pa->vcalb_desc.vcalk_sign_mask = AW_PID_1852_EF_VSN_GESLP_SIGN_MASK; + aw_pa->vcalb_desc.vcalk_neg_mask = AW_PID_1852_EF_VSN_GESLP_NEG; + aw_pa->vcalb_desc.vcalk_value_factor = AW_PID_1852_VCABLK_FACTOR; + + aw_pa->sysst_desc.reg = AW_PID_1852_SYSST_REG; + aw_pa->sysst_desc.mask = AW_PID_1852_SYSST_CHECK_MASK; + aw_pa->sysst_desc.st_check = AW_PID_1852_SYSST_CHECK; + aw_pa->sysst_desc.pll_check = AW_PID_1852_IIS_CHECK; + + aw_pa->spin_desc.rx_desc.reg = AW_PID_1852_I2SCTRL_REG; + aw_pa->spin_desc.rx_desc.mask = AW_PID_1852_CHSEL_MASK; + aw_pa->spin_desc.rx_desc.left_val = AW_PID_1852_CHSEL_LEFT_VALUE; + aw_pa->spin_desc.rx_desc.right_val = AW_PID_1852_CHSEL_RIGHT_VALUE; + + aw_pa->cco_mux_desc.reg = AW_PID_1852_PLLCTRL1_REG; + aw_pa->cco_mux_desc.mask = AW_PID_1852_I2S_CCO_MUX_MASK; + aw_pa->cco_mux_desc.divided_val = AW_PID_1852_I2S_CCO_MUX_8_16_32KHZ_VALUE; + aw_pa->cco_mux_desc.bypass_val = AW_PID_1852_I2S_CCO_MUX_EXC_8_16_32KHZ_VALUE; + + aw_pa->voltage_desc.reg = AW_PID_1852_VBAT_REG; + aw_pa->voltage_desc.int_bit = AW_PID_1852_MONITOR_INT_10BIT; + aw_pa->voltage_desc.vbat_range = AW_PID_1852_MONITOR_VBAT_RANGE; + + aw_pa->temp_desc.reg = AW_PID_1852_TEMP_REG; + aw_pa->temp_desc.neg_mask = AW_PID_1852_MONITOR_TEMP_NEG_MASK; + aw_pa->temp_desc.sign_mask = AW_PID_1852_MONITOR_TEMP_SIGN_MASK; + + aw_pa->ipeak_desc.reg = AW_PID_1852_SYSCTRL2_REG; + aw_pa->ipeak_desc.mask = AW_PID_1852_BST_IPEAK_MASK; + + aw_pa->volume_desc.reg = AW_PID_1852_HAGCCFG4_REG; + aw_pa->volume_desc.mask = AW_PID_1852_VOL_MASK; + aw_pa->volume_desc.shift = AW_PID_1852_VOL_START_BIT; + aw_pa->volume_desc.mute_volume = AW_PID_1852_MUTE_VOL; + aw_pa->volume_desc.ctl_volume = AW_PID_1852_VOL_DEFAULT_VALUE; + + aw_pa->bop_desc.reg = AW_REG_NONE; + aw_pa->efcheck_desc.reg = AW_REG_NONE; + + aw_pa->soft_rst.reg = AW882XX_SOFT_RESET_REG; + aw_pa->soft_rst.reg_value = AW882XX_SOFT_RESET_VALUE; + + aw_pa->dither_desc.reg = AW_PID_1852_TESTCTRL2_REG; + aw_pa->dither_desc.mask = AW_PID_1852_DITHER_MASK; + aw_pa->dither_desc.enable = AW_PID_1852_DITHER_ENABLE_VALUE; + aw_pa->dither_desc.disable = AW_PID_1852_DITHER_DISABLE_VALUE; + + aw_pa->noise_gate_desc.reg = AW_REG_NONE; + + aw_pa->auth_desc.reg_in = AW_PID_1852_CRCIN_REG; + aw_pa->auth_desc.reg_out = AW_PID_1852_CRCOUT_REG; + + aw_pa->psm_desc.reg = AW_REG_NONE; + aw_pa->mpd_desc.reg = AW_REG_NONE; + aw_pa->dsmzth_desc.reg = AW_REG_NONE; + + ret = aw882xx_device_probe(aw_pa); + + aw882xx->aw_pa = aw_pa; + return ret; +} + +/****************************************************** + * + * A2013 init + * + ******************************************************/ +/*[9 : 6]: -6DB ; [5 : 0]: 0.125DB real_value = value * 8 : 0.125db --> 1*/ +static unsigned int aw_pid_2013_reg_val_to_db(unsigned int value) +{ + return ((value >> 6) * AW_PID_2013_VOL_STEP_DB + (value & 0x003f)); +} + +/*[9 : 6]: -6DB ; [5 : 0]: -0.125DB reg_value = value / step << 6 + value % step ; step = 6 * 8*/ +static unsigned int aw_pid_2013_db_val_to_reg(unsigned int value) +{ + return (((value / AW_PID_2013_VOL_STEP_DB) << 6) + (value % AW_PID_2013_VOL_STEP_DB)); +} + +static int aw_pid_2013_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + struct aw_volume_desc *vol_desc = &aw882xx->aw_pa->volume_desc; + + real_value = aw_pid_2013_db_val_to_reg(AW_GET_MIN_VALUE(value, vol_desc->mute_volume)); + + /* cal real value */ + aw882xx_i2c_read(aw882xx, AW_PID_2013_SYSCTRL2_REG, ®_value); + + aw_dev_dbg(aw882xx->dev, "value %d , 0x%x", value, real_value); + + /*9 : 0] volume*/ + real_value = real_value | (reg_value & 0xfc00); + + /* write value */ + aw882xx_i2c_write(aw882xx, AW_PID_2013_SYSCTRL2_REG, real_value); + return 0; +} + +static int aw_pid_2013_get_volume(struct aw_device *aw_dev, unsigned int *value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + /* read value */ + aw882xx_i2c_read(aw882xx, AW_PID_2013_SYSCTRL2_REG, ®_value); + + /*[9 : 0] volume*/ + real_value = reg_value & 0x03ff; + + real_value = aw_pid_2013_reg_val_to_db(real_value); + *value = real_value; + + return 0; +} + +static bool aw_pid_2013_check_rd_access(int reg) +{ + if (reg >= AW_PID_2013_REG_MAX) + return false; + + if (aw_pid_2013_reg_access[reg] & AW_PID_2013_REG_RD_ACCESS) + return true; + else + return false; +} + +static bool aw_pid_2013_check_wr_access(int reg) +{ + if (reg >= AW_PID_2013_REG_MAX) + return false; + + if (aw_pid_2013_reg_access[reg] & AW_PID_2013_REG_WR_ACCESS) + return true; + else + return false; +} + +static int aw_pid_2013_get_reg_num(void) +{ + return AW_PID_2013_REG_MAX; +} + +static unsigned int aw_pid_2013_get_irq_type(struct aw_device *aw_dev, + unsigned int value) +{ + unsigned int ret = INT_TYPE_NONE; + + /*UVL0*/ + if (value & (~AW_PID_2013_UVLI_MASK)) { + aw_dev_info(aw_dev->dev, "UVLO: occur"); + ret |= INT_TYPE_UVLO; + } + + /*BSTOCM*/ + if (value & (~AW_PID_2013_BSTOCI_MASK)) { + aw_dev_info(aw_dev->dev, "BSTOCI: occur"); + ret |= INT_TYPE_BSTOC; + } + + /*OCDI*/ + if (value & (~AW_PID_2013_OCDI_MASK)) { + aw_dev_info(aw_dev->dev, "OCDI: occur"); + ret |= INT_TYPE_OCDI; + } + + /*OTHI*/ + if (value & (~AW_PID_2013_OTHI_MASK)) { + aw_dev_info(aw_dev->dev, "OTHI: occur"); + ret |= INT_TYPE_OTHI; + } + + return ret; +} + +static void aw_pid_2013_efver_check(struct aw_device *aw_dev) +{ + unsigned int reg_val = 0; + unsigned int efverh = 0; + unsigned int efverl = 0; + + aw_dev->ops.aw_i2c_read(aw_dev, + AW_PID_2013_EFRM1_REG, ®_val); + + efverh = (((reg_val & (~AW_PID_2013_EFVERH_MASK)) >> + AW_PID_2013_EFVERH_START_BIT) ^ + AW_PID_2013_EFVER_CHECK); + efverl = (((reg_val & (~AW_PID_2013_EFVERL_MASK)) >> + AW_PID_2013_EFVERL_START_BIT) ^ + AW_PID_2013_EFVER_CHECK); + + aw_dev_dbg(aw_dev->dev, "efverh: 0x%0x, efverl: 0x%0x", efverh, efverl); + + if (efverh && efverl) { + aw_dev->bstcfg_enable = AW_BSTCFG_ENABLE; + aw_dev_info(aw_dev->dev, "A2013 EFVER A"); + } else if (efverh && !efverl) { + aw_dev->bstcfg_enable = AW_BSTCFG_DISABLE; + aw_dev_info(aw_dev->dev, "A2013 EFVER B"); + } else { + aw_dev->bstcfg_enable = AW_BSTCFG_DISABLE; + aw_dev_info(aw_dev->dev, "unsupport A2013 EFVER"); + } + aw_dev_info(aw_dev->dev, "bstcfg enable: %d", aw_dev->bstcfg_enable); +} + +static int aw_pid_2013_dev_init(struct aw882xx *aw882xx) +{ + int ret = 0; + struct aw_device *aw_pa = aw882xx->aw_pa; + + /*call aw device init func*/ + memset(aw_pa->monitor_name, 0, AW_NAME_MAX); + memcpy(aw_pa->monitor_name, AW_PID_2013_MONITOR_FILE, strlen(AW_PID_2013_MONITOR_FILE)); + + aw_pa->prof_info.prof_desc = NULL; + aw_pa->prof_info.count = 0; + aw_pa->channel = 0; + aw_pa->bop_en = AW_BOP_DISABLE; + aw_pa->vol_step = AW_PID_2013_VOL_STEP; + + aw_pa->private_data = (void *)aw882xx; + aw_pa->dev = aw882xx->dev; + aw_pa->i2c = aw882xx->i2c; + aw_pa->ops.aw_get_version = aw882xx_get_version; + aw_pa->ops.aw_get_dev_num = aw882xx_get_dev_num; + aw_pa->ops.aw_set_algo = aw882xx_dev_set_algo_en; + aw_pa->ops.aw_i2c_read = aw882xx_dev_i2c_read; + aw_pa->ops.aw_i2c_write = aw882xx_dev_i2c_write; + aw_pa->ops.aw_i2c_write_bits = aw882xx_dev_i2c_write_bits; + aw_pa->ops.aw_get_hw_volume = aw_pid_2013_get_volume; + aw_pa->ops.aw_set_hw_volume = aw_pid_2013_set_volume; + aw_pa->ops.aw_reg_val_to_db = aw_pid_2013_reg_val_to_db; + aw_pa->ops.aw_check_rd_access = aw_pid_2013_check_rd_access; + aw_pa->ops.aw_check_wr_access = aw_pid_2013_check_wr_access; + aw_pa->ops.aw_get_reg_num = aw_pid_2013_get_reg_num; + aw_pa->ops.aw_get_irq_type = aw_pid_2013_get_irq_type; + + aw_pa->int_desc.mask_reg = AW_PID_2013_SYSINTM_REG; + aw_pa->int_desc.mask_default = AW_PID_2013_SYSINTM_DEFAULT; + aw_pa->int_desc.int_mask = AW_PID_2013_SYSINTM_DEFAULT; + aw_pa->int_desc.st_reg = AW_PID_2013_SYSINT_REG; + + aw_pa->work_mode.reg = AW_PID_2013_SYSCTRL_REG; + aw_pa->work_mode.mask = AW_PID_2013_EN_TRAN_MASK; + aw_pa->work_mode.spk_val = AW_PID_2013_EN_TRAN_SPK_VALUE; + aw_pa->work_mode.rcv_val = AW_PID_2013_EN_TRAN_RCV_VALUE; + + aw_pa->pwd_desc.reg = AW_PID_2013_SYSCTRL_REG; + aw_pa->pwd_desc.mask = AW_PID_2013_PWDN_MASK; + aw_pa->pwd_desc.enable = AW_PID_2013_PWDN_POWER_DOWN_VALUE; + aw_pa->pwd_desc.disable = AW_PID_2013_PWDN_WORKING_VALUE; + + aw_pa->amppd_desc.reg = AW_PID_2013_SYSCTRL_REG; + aw_pa->amppd_desc.mask = AW_PID_2013_AMPPD_MASK; + aw_pa->amppd_desc.enable = AW_PID_2013_AMPPD_POWER_DOWN_VALUE; + aw_pa->amppd_desc.disable = AW_PID_2013_AMPPD_WORKING_VALUE; + + aw_pa->mute_desc.reg = AW_PID_2013_SYSCTRL_REG; + aw_pa->mute_desc.mask = AW_PID_2013_HMUTE_MASK; + aw_pa->mute_desc.enable = AW_PID_2013_HMUTE_ENABLE_VALUE; + aw_pa->mute_desc.disable = AW_PID_2013_HMUTE_DISABLE_VALUE; + + aw_pa->uls_hmute_desc.reg = AW_REG_NONE; + + aw_pa->txen_desc.reg = AW_PID_2013_I2SCTRL1_REG; + aw_pa->txen_desc.mask = AW_PID_2013_I2STXEN_MASK; + aw_pa->txen_desc.enable = AW_PID_2013_I2STXEN_ENABLE_VALUE; + aw_pa->txen_desc.disable = AW_PID_2013_I2STXEN_DISABLE_VALUE; + + aw_pa->vcalb_desc.vcalb_reg = AW_PID_2013_VSNTM1_REG; + aw_pa->vcalb_desc.vcal_factor = AW_PID_2013_VCAL_FACTOR; + aw_pa->vcalb_desc.cabl_base_value = AW_PID_2013_CABL_BASE_VALUE; + + aw_pa->vcalb_desc.icalk_value_factor = AW_PID_2013_ICABLK_FACTOR; + aw_pa->vcalb_desc.icalk_reg = AW_PID_2013_EFRH_REG; + aw_pa->vcalb_desc.icalkl_reg = AW_REG_NONE; + aw_pa->vcalb_desc.icalk_reg_mask = AW_PID_2013_EF_ISN_GESLP_MASK; + aw_pa->vcalb_desc.icalk_sign_mask = AW_PID_2013_EF_ISN_GESLP_SIGN_MASK; + aw_pa->vcalb_desc.icalk_neg_mask = AW_PID_2013_EF_ISN_GESLP_NEG; + + aw_pa->vcalb_desc.vcalk_reg = AW_PID_2013_EFRM2_REG; + aw_pa->vcalb_desc.vcalk_reg_mask = AW_PID_2013_EF_VSN_GESLP_MASK; + aw_pa->vcalb_desc.vcalkl_reg = AW_REG_NONE; + aw_pa->vcalb_desc.vcalk_sign_mask = AW_PID_2013_EF_ISN_GESLP2_SIGN_MASK; + aw_pa->vcalb_desc.vcalk_neg_mask = AW_PID_2013_EF_ISN_GESLP2_NEG; + aw_pa->vcalb_desc.vcalk_value_factor = AW_PID_2013_VCABLK_FACTOR; + + aw_pa->sysst_desc.reg = AW_PID_2013_SYSST_REG; + aw_pa->sysst_desc.mask = AW_PID_2013_SYSST_CHECK_MASK; + aw_pa->sysst_desc.st_check = AW_PID_2013_SYSST_CHECK; + aw_pa->sysst_desc.pll_check = AW_PID_2013_IIS_CHECK; + + aw_pa->profctrl_desc.reg = AW_PID_2013_SYSCTRL_REG; + aw_pa->profctrl_desc.mask = AW_PID_2013_EN_TRAN_MASK; + aw_pa->profctrl_desc.spk_mode = AW_PID_2013_EN_TRAN_SPK_VALUE; + + aw_pa->bstctrl_desc.reg = AW_PID_2013_BSTCTRL2_REG; + aw_pa->bstctrl_desc.mask = AW_PID_2013_BST_MODE_MASK; + aw_pa->bstctrl_desc.frc_bst = AW_PID_2013_BST_MODE_FORCE_BOOST_VALUE; + aw_pa->bstctrl_desc.tsp_type = AW_PID_2013_BST_MODE_TRANSPARENT_VALUE; + + aw_pa->spin_desc.rx_desc.reg = AW_PID_2013_I2SCTRL1_REG; + aw_pa->spin_desc.rx_desc.mask = AW_PID_2013_CHSEL_MASK; + aw_pa->spin_desc.rx_desc.left_val = AW_PID_2013_CHSEL_LEFT_VALUE; + aw_pa->spin_desc.rx_desc.right_val = AW_PID_2013_CHSEL_RIGHT_VALUE; + + aw_pa->voltage_desc.reg = AW_PID_2013_VBAT_REG; + aw_pa->voltage_desc.int_bit = AW_PID_2013_MONITOR_INT_10BIT; + aw_pa->voltage_desc.vbat_range = AW_PID_2013_MONITOR_VBAT_RANGE; + + aw_pa->temp_desc.reg = AW_PID_2013_TEMP_REG; + aw_pa->temp_desc.neg_mask = AW_PID_2013_MONITOR_TEMP_NEG_MASK; + aw_pa->temp_desc.sign_mask = AW_PID_2013_MONITOR_TEMP_SIGN_MASK; + + aw_pa->cco_mux_desc.reg = AW_PID_2013_PLLCTRL3_REG; + aw_pa->cco_mux_desc.mask = AW_PID_2013_CCO_MUX_MASK; + aw_pa->cco_mux_desc.divided_val = AW_PID_2013_CCO_MUX_DIVIDED_VALUE; + aw_pa->cco_mux_desc.bypass_val = AW_PID_2013_CCO_MUX_BYPASS_VALUE; + + aw_pa->ipeak_desc.reg = AW_PID_2013_BSTCTRL2_REG; + aw_pa->ipeak_desc.mask = AW_PID_2013_BST_IPEAK_MASK; + + aw_pa->volume_desc.reg = AW_PID_2013_SYSCTRL2_REG; + aw_pa->volume_desc.mask = AW_PID_2013_VOL_MASK; + aw_pa->volume_desc.shift = AW_PID_2013_VOL_START_BIT; + aw_pa->volume_desc.mute_volume = AW_PID_2013_MUTE_VOL; + aw_pa->volume_desc.ctl_volume = AW_PID_2013_VOL_DEFAULT_VALUE; + + aw_pa->bop_desc.reg = AW_REG_NONE; + aw_pa->efcheck_desc.reg = AW_REG_NONE; + + aw_pa->soft_rst.reg = AW882XX_SOFT_RESET_REG; + aw_pa->soft_rst.reg_value = AW882XX_SOFT_RESET_VALUE; + + aw_pa->dither_desc.reg = AW_PID_2013_DBGCTRL_REG; + aw_pa->dither_desc.mask = AW_PID_2013_DITHER_MASK; + aw_pa->dither_desc.enable = AW_PID_2013_DITHER_ENABLE_VALUE; + aw_pa->dither_desc.disable = AW_PID_2013_DITHER_DISABLE_VALUE; + + aw_pa->noise_gate_desc.reg = AW_REG_NONE; + + aw_pa->auth_desc.reg_in = AW_PID_2013_TESTIN_REG; + aw_pa->auth_desc.reg_out = AW_PID_2013_TESTOUT_REG; + + aw_pa->psm_desc.reg = AW_REG_NONE; + aw_pa->mpd_desc.reg = AW_REG_NONE; + aw_pa->dsmzth_desc.reg = AW_REG_NONE; + + aw_pid_2013_efver_check(aw_pa); + ret = aw882xx_device_probe(aw_pa); + + aw882xx->aw_pa = aw_pa; + return ret; +} + +/****************************************************** + * + * A2032 init + * + ******************************************************/ +/*[7 : 4]: -6DB ; [3 : 0]: 0.5DB real_value = value * 2 : 0.5db --> 1*/ +static unsigned int aw_pid_2032_reg_val_to_db(unsigned int value) +{ + return ((value >> 6) * AW_PID_2032_VOL_STEP_DB + (value & 0x3f)); +} + +/* [7 : 4]: -6DB ; [3 : 0]: -0.5DB reg_value = value / step << 4 + value % step ; step = 6 * 2 */ +static unsigned int aw_pid_2032_db_val_to_reg(unsigned int value) +{ + return (((value / AW_PID_2032_VOL_STEP_DB) << 6) + (value % AW_PID_2032_VOL_STEP_DB)); +} + + +static int aw_pid_2032_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw_volume_desc *vol_desc = &aw882xx->aw_pa->volume_desc; + + real_value = aw_pid_2032_db_val_to_reg(AW_GET_MIN_VALUE(value, vol_desc->mute_volume)); + + /* cal real value */ + aw882xx_i2c_read(aw882xx, AW_PID_2032_SYSCTRL2_REG, ®_value); + + aw_dev_dbg(aw882xx->dev, "value %d , 0x%x", value, real_value); + + /* [15 : 6] volume */ + real_value = (real_value << 6) | (reg_value & 0x003f); + + /* write value */ + aw882xx_i2c_write(aw882xx, AW_PID_2032_SYSCTRL2_REG, real_value); + return 0; +} + +static int aw_pid_2032_get_volume(struct aw_device *aw_dev, unsigned int *value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + /* read value */ + aw882xx_i2c_read(aw882xx, AW_PID_2032_SYSCTRL2_REG, ®_value); + + /* [15 : 6] volume */ + real_value = reg_value >> 6; + + real_value = aw_pid_2032_reg_val_to_db(real_value); + *value = real_value; + + return 0; +} + +static bool aw_pid_2032_check_rd_access(int reg) +{ + if (reg >= AW_PID_2032_REG_MAX) + return false; + + if (aw_pid_2032_reg_access[reg] & AW_PID_2032_REG_RD_ACCESS) + return true; + else + return false; +} + +static bool aw_pid_2032_check_wr_access(int reg) +{ + if (reg >= AW_PID_2032_REG_MAX) + return false; + + if (aw_pid_2032_reg_access[reg] & + AW_PID_2032_REG_WR_ACCESS) + return true; + else + return false; +} + +static int aw_pid_2032_get_reg_num(void) +{ + return AW_PID_2032_REG_MAX; +} + +static unsigned int aw_pid_2032_get_irq_type(struct aw_device *aw_dev, + unsigned int value) +{ + unsigned int ret = INT_TYPE_NONE; + + /* UVL0 */ + if (value & (~AW_PID_2032_UVLI_MASK)) { + aw_dev_info(aw_dev->dev, "UVLO: occur"); + ret |= INT_TYPE_UVLO; + } + + /* BSTOCM */ + if (value & (~AW_PID_2032_BSTOCI_MASK)) { + aw_dev_info(aw_dev->dev, "BSTOCI: occur"); + ret |= INT_TYPE_BSTOC; + } + + /* OCDI */ + if (value & (~AW_PID_2032_OCDI_MASK)) { + aw_dev_info(aw_dev->dev, "OCDI: occur"); + ret |= INT_TYPE_OCDI; + } + + /* OTHI */ + if (value & (~AW_PID_2032_OTHI_MASK)) { + aw_dev_info(aw_dev->dev, "OTHI: occur"); + ret |= INT_TYPE_OTHI; + } + + return ret; +} + +static int aw_pid_2032_dev_init(struct aw882xx *aw882xx) +{ + int ret = 0; + struct aw_device *aw_pa = aw882xx->aw_pa; + + /* call aw device init func */ + memset(aw_pa->monitor_name, 0, AW_NAME_MAX); + memcpy(aw_pa->monitor_name, AW_PID_2032_MONITOR_FILE, strlen(AW_PID_2032_MONITOR_FILE)); + + aw_pa->prof_info.prof_desc = NULL; + aw_pa->prof_info.count = 0; + aw_pa->channel = 0; + aw_pa->bstcfg_enable = AW_BSTCFG_DISABLE; + aw_pa->bop_en = AW_BOP_DISABLE; + aw_pa->vol_step = AW_PID_2032_VOL_STEP; + + aw_pa->private_data = (void *)aw882xx; + aw_pa->dev = aw882xx->dev; + aw_pa->i2c = aw882xx->i2c; + aw_pa->ops.aw_get_version = aw882xx_get_version; + aw_pa->ops.aw_get_dev_num = aw882xx_get_dev_num; + aw_pa->ops.aw_set_algo = aw882xx_dev_set_algo_en; + aw_pa->ops.aw_i2c_read = aw882xx_dev_i2c_read; + aw_pa->ops.aw_i2c_write = aw882xx_dev_i2c_write; + aw_pa->ops.aw_i2c_write_bits = aw882xx_dev_i2c_write_bits; + aw_pa->ops.aw_get_hw_volume = aw_pid_2032_get_volume; + aw_pa->ops.aw_set_hw_volume = aw_pid_2032_set_volume; + aw_pa->ops.aw_reg_val_to_db = aw_pid_2032_reg_val_to_db; + aw_pa->ops.aw_check_rd_access = aw_pid_2032_check_rd_access; + aw_pa->ops.aw_check_wr_access = aw_pid_2032_check_wr_access; + aw_pa->ops.aw_get_reg_num = aw_pid_2032_get_reg_num; + aw_pa->ops.aw_get_irq_type = aw_pid_2032_get_irq_type; + + aw_pa->int_desc.mask_reg = AW_PID_2032_SYSINTM_REG; + aw_pa->int_desc.mask_default = AW_PID_2032_SYSINTM_DEFAULT; + aw_pa->int_desc.int_mask = AW_PID_2032_SYSINTM_DEFAULT; + aw_pa->int_desc.st_reg = AW_PID_2032_SYSINT_REG; + + aw_pa->work_mode.reg = AW_PID_2032_SYSCTRL_REG; + aw_pa->work_mode.mask = AW_PID_2032_RCV_MODE_MASK; + aw_pa->work_mode.spk_val = AW_PID_2032_RCV_MODE_SPEAKER_VALUE; + aw_pa->work_mode.rcv_val = AW_PID_2032_RCV_MODE_RECEIVER_VALUE; + + aw_pa->pwd_desc.reg = AW_PID_2032_SYSCTRL_REG; + aw_pa->pwd_desc.mask = AW_PID_2032_PWDN_MASK; + aw_pa->pwd_desc.enable = AW_PID_2032_PWDN_POWER_DOWN_VALUE; + aw_pa->pwd_desc.disable = AW_PID_2032_PWDN_WORKING_VALUE; + + aw_pa->amppd_desc.reg = AW_PID_2032_SYSCTRL_REG; + aw_pa->amppd_desc.mask = AW_PID_2032_AMPPD_MASK; + aw_pa->amppd_desc.enable = AW_PID_2032_AMPPD_POWER_DOWN_VALUE; + aw_pa->amppd_desc.disable = AW_PID_2032_AMPPD_WORKING_VALUE; + + aw_pa->mute_desc.reg = AW_PID_2032_SYSCTRL2_REG; + aw_pa->mute_desc.mask = AW_PID_2032_HMUTE_MASK; + aw_pa->mute_desc.enable = AW_PID_2032_HMUTE_ENABLE_VALUE; + aw_pa->mute_desc.disable = AW_PID_2032_HMUTE_DISABLE_VALUE; + + aw_pa->uls_hmute_desc.reg = AW_REG_NONE; + + aw_pa->txen_desc.reg = AW_PID_2032_I2SCFG1_REG; + aw_pa->txen_desc.mask = AW_PID_2032_I2STXEN_MASK; + aw_pa->txen_desc.enable = AW_PID_2032_I2STXEN_ENABLE_VALUE; + aw_pa->txen_desc.disable = AW_PID_2032_I2STXEN_DISABLE_VALUE; + + aw_pa->vcalb_desc.vcalb_reg = AW_PID_2032_VTMCTRL3_REG; + aw_pa->vcalb_desc.vcal_factor = AW_PID_2032_VCAL_FACTOR; + aw_pa->vcalb_desc.cabl_base_value = AW_PID_2032_CABL_BASE_VALUE; + + aw_pa->vcalb_desc.icalk_value_factor = AW_PID_2032_ICABLK_FACTOR; + aw_pa->vcalb_desc.icalk_reg = AW_PID_2032_EFRM1_REG; + aw_pa->vcalb_desc.icalkl_reg = AW_REG_NONE; + aw_pa->vcalb_desc.icalk_reg_mask = AW_PID_2032_EF_ISN_GESLP_MASK; + aw_pa->vcalb_desc.icalk_sign_mask = AW_PID_2032_EF_ISN_GESLP_SIGN_MASK; + aw_pa->vcalb_desc.icalk_neg_mask = AW_PID_2032_EF_ISN_GESLP_NEG; + + aw_pa->vcalb_desc.vcalk_reg = AW_PID_2032_EFRH_REG; + aw_pa->vcalb_desc.vcalk_reg_mask = AW_PID_2032_EF_VSN_GESLP_MASK; + aw_pa->vcalb_desc.vcalkl_reg = AW_REG_NONE; + aw_pa->vcalb_desc.vcalk_sign_mask = AW_PID_2032_EF_VSN_GESLP_SIGN_MASK; + aw_pa->vcalb_desc.vcalk_neg_mask = AW_PID_2032_EF_VSN_GESLP_NEG; + aw_pa->vcalb_desc.vcalk_value_factor = AW_PID_2032_VCABLK_FACTOR; + + aw_pa->spin_desc.rx_desc.reg = AW_PID_2032_I2SCTRL_REG; + aw_pa->spin_desc.rx_desc.mask = AW_PID_2032_CHSEL_MASK; + aw_pa->spin_desc.rx_desc.left_val = AW_PID_2032_CHSEL_LEFT_VALUE; + aw_pa->spin_desc.rx_desc.right_val = AW_PID_2032_CHSEL_RIGHT_VALUE; + + aw_pa->sysst_desc.reg = AW_PID_2032_SYSST_REG; + aw_pa->sysst_desc.mask = AW_PID_2032_SYSST_CHECK_MASK; + aw_pa->sysst_desc.st_check = AW_PID_2032_SYSST_CHECK; + aw_pa->sysst_desc.pll_check = AW_PID_2032_IIS_CHECK; + + aw_pa->cco_mux_desc.reg = AW_PID_2032_PLLCTRL1_REG; + aw_pa->cco_mux_desc.mask = AW_PID_2032_CCO_MUX_MASK; + aw_pa->cco_mux_desc.divided_val = AW_PID_2032_CCO_MUX_DIVIDED_VALUE; + aw_pa->cco_mux_desc.bypass_val = AW_PID_2032_CCO_MUX_BYPASS_VALUE; + + aw_pa->voltage_desc.reg = AW_PID_2032_VBAT_REG; + aw_pa->voltage_desc.int_bit = AW_PID_2032_MONITOR_INT_10BIT; + aw_pa->voltage_desc.vbat_range = AW_PID_2032_MONITOR_VBAT_RANGE; + + aw_pa->temp_desc.reg = AW_PID_2032_TEMP_REG; + aw_pa->temp_desc.neg_mask = AW_PID_2032_MONITOR_TEMP_NEG_MASK; + aw_pa->temp_desc.sign_mask = AW_PID_2032_MONITOR_TEMP_SIGN_MASK; + + aw_pa->ipeak_desc.reg = AW_PID_2032_SYSCTRL2_REG; + aw_pa->ipeak_desc.mask = AW_PID_2032_BST_IPEAK_MASK; + + aw_pa->volume_desc.reg = AW_PID_2032_SYSCTRL2_REG; + aw_pa->volume_desc.mask = AW_PID_2032_VOL_MASK; + aw_pa->volume_desc.shift = AW_PID_2032_VOL_START_BIT; + aw_pa->volume_desc.mute_volume = AW_PID_2032_MUTE_VOL; + aw_pa->volume_desc.ctl_volume = AW_PID_2032_VOL_DEFAULT_VALUE; + + aw_pa->bop_desc.reg = AW_REG_NONE; + aw_pa->efcheck_desc.reg = AW_REG_NONE; + + aw_pa->soft_rst.reg = AW882XX_SOFT_RESET_REG; + aw_pa->soft_rst.reg_value = AW882XX_SOFT_RESET_VALUE; + + aw_pa->dither_desc.reg = AW_PID_2032_DBGCTRL_REG; + aw_pa->dither_desc.mask = AW_PID_2032_DITHER_MASK; + aw_pa->dither_desc.enable = AW_PID_2032_DITHER_ENABLE_VALUE; + aw_pa->dither_desc.disable = AW_PID_2032_DITHER_DISABLE_VALUE; + + aw_pa->noise_gate_desc.reg = AW_REG_NONE; + + aw_pa->auth_desc.reg_in = AW_PID_2032_TESTIN_REG; + aw_pa->auth_desc.reg_out = AW_PID_2032_TESTOUT_REG; + + aw_pa->psm_desc.reg = AW_REG_NONE; + aw_pa->mpd_desc.reg = AW_REG_NONE; + aw_pa->dsmzth_desc.reg = AW_REG_NONE; + + ret = aw882xx_device_probe(aw_pa); + + aw882xx->aw_pa = aw_pa; + return ret; +} + +/* [9 : 6]: -6DB ; [5 : 0]: 0.125DB real_value = value * 8 : 0.125db --> 1 */ +static unsigned int aw_pid_2055a_reg_val_to_db(unsigned int value) +{ + return ((value >> 6) * AW_PID_2055A_VOL_STEP_DB + (value & 0x3f)); +} + +/* [9 : 6]: -6DB ; [5 : 0]: 0.125DB reg_value = value / step << 6 + value % step ; step = 6 * 8 */ +static unsigned int aw_pid_2055a_db_val_to_reg(unsigned int value) +{ + return (((value / AW_PID_2055A_VOL_STEP_DB) << 6) + (value % AW_PID_2055A_VOL_STEP_DB)); +} + +static int aw_pid_2055a_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw_volume_desc *vol_desc = &aw882xx->aw_pa->volume_desc; + + real_value = aw_pid_2055a_db_val_to_reg(AW_GET_MIN_VALUE(value, vol_desc->mute_volume)); + + /* cal real value */ + aw882xx_i2c_read(aw882xx, AW_PID_2055A_SYSCTRL2_REG, ®_value); + + aw_dev_dbg(aw882xx->dev, "value %d , 0x%x", value, real_value); + + /*[9 : 0] volume*/ + real_value = (real_value | (reg_value & 0xfc00)); + + /* write value */ + aw882xx_i2c_write(aw882xx, AW_PID_2055A_SYSCTRL2_REG, real_value); + return 0; +} + +static int aw_pid_2055a_get_volume(struct aw_device *aw_dev, unsigned int *value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + /* read value */ + aw882xx_i2c_read(aw882xx, AW_PID_2055A_SYSCTRL2_REG, ®_value); + + /* [9 : 0] volume */ + real_value = (reg_value & 0x03ff); + + real_value = aw_pid_2055a_reg_val_to_db(real_value); + *value = real_value; + + return 0; +} + +static bool aw_pid_2055a_check_rd_access(int reg) +{ + if (reg >= AW_PID_2055A_REG_MAX) + return false; + + + if (aw_pid_2055a_reg_access[reg] & AW_PID_2055A_REG_RD_ACCESS) + return true; + + return false; + +} + +static bool aw_pid_2055a_check_wr_access(int reg) +{ + if (reg >= AW_PID_2055A_REG_MAX) + return false; + + if (aw_pid_2055a_reg_access[reg] & + AW_PID_2055A_REG_WR_ACCESS) + return true; + + return false; +} + +static int aw_pid_2055a_get_reg_num(void) +{ + return AW_PID_2055A_REG_MAX; +} + +static unsigned int aw_pid_2055a_get_irq_type(struct aw_device *aw_dev, + unsigned int value) +{ + unsigned int ret = INT_TYPE_NONE; + + /* UVL0 */ + if (value & (~AW_PID_2055A_UVLI_MASK)) { + aw_dev_info(aw_dev->dev, "UVLO: occur"); + ret |= INT_TYPE_UVLO; + } + + /* BSTOCM */ + if (value & (~AW_PID_2055A_BSTOCI_MASK)) { + aw_dev_info(aw_dev->dev, "BSTOCI: occur"); + ret |= INT_TYPE_BSTOC; + } + + /* OCDI */ + if (value & (~AW_PID_2055A_OCDI_MASK)) { + aw_dev_info(aw_dev->dev, "OCDI: occur"); + ret |= INT_TYPE_OCDI; + } + + /* OTHI */ + if (value & (~AW_PID_2055A_OTHI_MASK)) { + aw_dev_info(aw_dev->dev, "OTHI: occur"); + ret |= INT_TYPE_OTHI; + } + + return ret; +} + +static int aw_pid_2055a_dev_init(struct aw882xx *aw882xx) +{ + int ret = 0; + struct aw_device *aw_pa = aw882xx->aw_pa; + + aw_pa->chip_id = PID_2055A_ID; + + /*call aw device init func*/ + memset(aw_pa->monitor_name, 0, AW_NAME_MAX); + memcpy(aw_pa->monitor_name, AW_PID_2055A_MONITOR_FILE, strlen(AW_PID_2055A_MONITOR_FILE)); + + aw_pa->prof_info.prof_desc = NULL; + aw_pa->prof_info.count = 0; + aw_pa->channel = 0; + aw_pa->bstcfg_enable = AW_BSTCFG_DISABLE; + aw_pa->bop_en = AW_BOP_DISABLE; + aw_pa->vol_step = AW_PID_2055A_VOL_STEP; + + aw_pa->private_data = (void *)aw882xx; + aw_pa->dev = aw882xx->dev; + aw_pa->i2c = aw882xx->i2c; + aw_pa->ops.aw_get_version = aw882xx_get_version; + aw_pa->ops.aw_get_dev_num = aw882xx_get_dev_num; + aw_pa->ops.aw_set_algo = aw882xx_dev_set_algo_en; + aw_pa->ops.aw_i2c_read = aw882xx_dev_i2c_read; + aw_pa->ops.aw_i2c_write = aw882xx_dev_i2c_write; + aw_pa->ops.aw_i2c_write_bits = aw882xx_dev_i2c_write_bits; + aw_pa->ops.aw_get_hw_volume = aw_pid_2055a_get_volume; + aw_pa->ops.aw_set_hw_volume = aw_pid_2055a_set_volume; + aw_pa->ops.aw_reg_val_to_db = aw_pid_2055a_reg_val_to_db; + aw_pa->ops.aw_check_rd_access = aw_pid_2055a_check_rd_access; + aw_pa->ops.aw_check_wr_access = aw_pid_2055a_check_wr_access; + aw_pa->ops.aw_get_reg_num = aw_pid_2055a_get_reg_num; + aw_pa->ops.aw_get_irq_type = aw_pid_2055a_get_irq_type; + + aw_pa->int_desc.mask_reg = AW_PID_2055A_SYSINTM_REG; + aw_pa->int_desc.mask_default = AW_PID_2055A_SYSINTM_DEFAULT; + aw_pa->int_desc.int_mask = AW_PID_2055A_SYSINTM_DEFAULT; + aw_pa->int_desc.st_reg = AW_PID_2055A_SYSINT_REG; + + aw_pa->pwd_desc.reg = AW_PID_2055A_SYSCTRL_REG; + aw_pa->pwd_desc.mask = AW_PID_2055A_PWDN_MASK; + aw_pa->pwd_desc.enable = AW_PID_2055A_PWDN_POWER_DOWN_VALUE; + aw_pa->pwd_desc.disable = AW_PID_2055A_PWDN_WORKING_VALUE; + + aw_pa->amppd_desc.reg = AW_PID_2055A_SYSCTRL_REG; + aw_pa->amppd_desc.mask = AW_PID_2055A_AMPPD_MASK; + aw_pa->amppd_desc.enable = AW_PID_2055A_AMPPD_POWER_DOWN_VALUE; + aw_pa->amppd_desc.disable = AW_PID_2055A_AMPPD_WORKING_VALUE; + + aw_pa->mute_desc.reg = AW_PID_2055A_SYSCTRL_REG; + aw_pa->mute_desc.mask = AW_PID_2055A_HMUTE_MASK; + aw_pa->mute_desc.enable = AW_PID_2055A_HMUTE_ENABLE_VALUE; + aw_pa->mute_desc.disable = AW_PID_2055A_HMUTE_DISABLE_VALUE; + + aw_pa->uls_hmute_desc.reg = AW_REG_NONE; + + aw_pa->txen_desc.reg = AW_PID_2055A_I2SCTRL1_REG; + aw_pa->txen_desc.mask = AW_PID_2055A_I2STXEN_MASK; + aw_pa->txen_desc.enable = AW_PID_2055A_I2STXEN_ENABLE_VALUE; + aw_pa->txen_desc.disable = AW_PID_2055A_I2STXEN_DISABLE_VALUE; + + aw_pa->vcalb_desc.vcalb_reg = AW_REG_NONE; + aw_pa->vcalb_desc.vcalk_reg = AW_REG_NONE; + aw_pa->vcalb_desc.icalk_reg = AW_REG_NONE; + + aw_pa->sysst_desc.reg = AW_PID_2055A_SYSST_REG; + aw_pa->sysst_desc.mask = AW_PID_2055A_SYSST_CHECK_MASK; + aw_pa->sysst_desc.st_check = AW_PID_2055A_SYSST_CHECK; + aw_pa->sysst_desc.pll_check = AW_PID_2055A_IIS_CHECK; + + aw_pa->spin_desc.rx_desc.reg = AW_PID_2055A_I2SCTRL1_REG; + aw_pa->spin_desc.rx_desc.mask = AW_PID_2055A_CHSEL_MASK; + aw_pa->spin_desc.rx_desc.left_val = AW_PID_2055A_CHSEL_LEFT_VALUE; + aw_pa->spin_desc.rx_desc.right_val = AW_PID_2055A_CHSEL_RIGHT_VALUE; + + aw_pa->voltage_desc.reg = AW_REG_NONE; + aw_pa->temp_desc.reg = AW_REG_NONE; + + aw_pa->txen_desc.reg = AW_PID_2055A_I2SCTRL1_REG; + aw_pa->txen_desc.mask = AW_PID_2055A_I2STXEN_MASK; + + aw_pa->ipeak_desc.reg = AW_PID_2055A_BSTCTRL2_REG; + aw_pa->ipeak_desc.mask = AW_PID_2055A_BST_IPEAK_MASK; + + aw_pa->volume_desc.reg = AW_PID_2055A_SYSCTRL2_REG; + aw_pa->volume_desc.mask = AW_PID_2055A_VOL_MASK; + aw_pa->volume_desc.shift = AW_PID_2055A_VOL_START_BIT; + aw_pa->volume_desc.mute_volume = AW_PID_2055A_MUTE_VOL; + aw_pa->volume_desc.ctl_volume = AW_PID_2055A_VOL_DEFAULT_VALUE; + + aw_pa->cco_mux_desc.reg = AW_PID_2055A_PLLCTRL3_REG; + aw_pa->cco_mux_desc.mask = AW_PID_2055A_CCO_MUX_MASK; + aw_pa->cco_mux_desc.divided_val = AW_PID_2055A_CCO_MUX_DIVIDED_VALUE; + aw_pa->cco_mux_desc.bypass_val = AW_PID_2055A_CCO_MUX_BYPASS_VALUE; + + aw_pa->bop_desc.reg = AW_REG_NONE; + aw_pa->efcheck_desc.reg = AW_REG_NONE; + + aw_pa->soft_rst.reg = AW882XX_SOFT_RESET_REG; + aw_pa->soft_rst.reg_value = AW882XX_SOFT_RESET_VALUE; + + aw_pa->dither_desc.reg = AW_PID_2055A_DBGCTRL_REG; + aw_pa->dither_desc.mask = AW_PID_2055A_DITHER_MASK; + aw_pa->dither_desc.enable = AW_PID_2055A_DITHER_ENABLE_VALUE; + aw_pa->dither_desc.disable = AW_PID_2055A_DITHER_DISABLE_VALUE; + + aw_pa->noise_gate_desc.reg = AW_REG_NONE; + + aw_pa->auth_desc.reg_in = AW_PID_2055A_TESTIN_REG; + aw_pa->auth_desc.reg_out = AW_PID_2055A_TESTOUT_REG; + + aw_pa->psm_desc.reg = AW_REG_NONE; + aw_pa->mpd_desc.reg = AW_REG_NONE; + aw_pa->dsmzth_desc.reg = AW_REG_NONE; + + usleep_range(AW_2000_US, AW_2000_US + 10); + aw_pa->ops.aw_i2c_write(aw_pa, AW_PID_2055A_INIT_CHECK_REG, + AW_PID_2055A_INIT_CHECK_VALUE); + usleep_range(AW_3000_US, AW_3000_US + 10); + + ret = aw882xx_device_probe(aw_pa); + + aw882xx->aw_pa = aw_pa; + return ret; +} + + +/* [9 : 6]: -6DB ; [5 : 0]: 0.125DB real_value = value * 8 : 0.125db --> 1 */ +static unsigned int aw_pid_2055_reg_val_to_db(unsigned int value) +{ + return ((value >> 6) * AW_PID_2055_VOL_STEP_DB + (value & 0x3f)); +} + +/* [9 : 6]: -6DB ; [5 : 0]: 0.125DB reg_value = value / step << 6 + value % step ; step = 6 * 8 */ +static unsigned int aw_pid_2055_db_val_to_reg(unsigned int value) +{ + return (((value / AW_PID_2055_VOL_STEP_DB) << 6) + (value % AW_PID_2055_VOL_STEP_DB)); +} + +static int aw_pid_2055_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw_volume_desc *vol_desc = &aw882xx->aw_pa->volume_desc; + + real_value = aw_pid_2055_db_val_to_reg(AW_GET_MIN_VALUE(value, vol_desc->mute_volume)); + + /* cal real value */ + aw882xx_i2c_read(aw882xx, AW_PID_2055_SYSCTRL2_REG, ®_value); + + aw_dev_dbg(aw882xx->dev, "value %d , 0x%x", value, real_value); + + /*[9 : 0] volume*/ + real_value = (real_value | (reg_value & 0xfc00)); + + /* write value */ + aw882xx_i2c_write(aw882xx, AW_PID_2055_SYSCTRL2_REG, real_value); + return 0; +} + +static int aw_pid_2055_get_volume(struct aw_device *aw_dev, unsigned int *value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + /* read value */ + aw882xx_i2c_read(aw882xx, AW_PID_2055_SYSCTRL2_REG, ®_value); + + /* [9 : 0] volume */ + real_value = (reg_value & 0x03ff); + + real_value = aw_pid_2055_reg_val_to_db(real_value); + *value = real_value; + + return 0; +} + +static bool aw_pid_2055_check_rd_access(int reg) +{ + if (reg >= AW_PID_2055_REG_MAX) + return false; + + + if (aw_pid_2055_reg_access[reg] & AW_PID_2055_REG_RD_ACCESS) + return true; + + return false; +} + +static bool aw_pid_2055_check_wr_access(int reg) +{ + if (reg >= AW_PID_2055_REG_MAX) + return false; + + if (aw_pid_2055_reg_access[reg] & + AW_PID_2055_REG_WR_ACCESS) + return true; + + return false; +} + +static int aw_pid_2055_get_reg_num(void) +{ + return AW_PID_2055_REG_MAX; +} + +static unsigned int aw_pid_2055_get_irq_type(struct aw_device *aw_dev, + unsigned int value) +{ + unsigned int ret = INT_TYPE_NONE; + + /* UVL0 */ + if (value & (~AW_PID_2055_UVLI_MASK)) { + aw_dev_info(aw_dev->dev, "UVLO: occur"); + ret |= INT_TYPE_UVLO; + } + + /* BSTOCM */ + if (value & (~AW_PID_2055_BSTOCI_MASK)) { + aw_dev_info(aw_dev->dev, "BSTOCI: occur"); + ret |= INT_TYPE_BSTOC; + } + + /* OCDI */ + if (value & (~AW_PID_2055_OCDI_MASK)) { + aw_dev_info(aw_dev->dev, "OCDI: occur"); + ret |= INT_TYPE_OCDI; + } + + /* OTHI */ + if (value & (~AW_PID_2055_OTHI_MASK)) { + aw_dev_info(aw_dev->dev, "OTHI: occur"); + ret |= INT_TYPE_OTHI; + } + + return ret; +} + +static int aw_pid_2055_dev_init(struct aw882xx *aw882xx) +{ + int ret = 0; + struct aw_device *aw_pa = aw882xx->aw_pa; + + /*call aw device init func*/ + memset(aw_pa->monitor_name, 0, AW_NAME_MAX); + memcpy(aw_pa->monitor_name, AW_PID_2055_MONITOR_FILE, strlen(AW_PID_2055_MONITOR_FILE)); + + aw_pa->prof_info.prof_desc = NULL; + aw_pa->prof_info.count = 0; + aw_pa->channel = 0; + aw_pa->bstcfg_enable = AW_BSTCFG_DISABLE; + aw_pa->bop_en = AW_BOP_DISABLE; + aw_pa->vol_step = AW_PID_2055_VOL_STEP; + + aw_pa->private_data = (void *)aw882xx; + aw_pa->dev = aw882xx->dev; + aw_pa->i2c = aw882xx->i2c; + aw_pa->ops.aw_get_version = aw882xx_get_version; + aw_pa->ops.aw_get_dev_num = aw882xx_get_dev_num; + aw_pa->ops.aw_set_algo = aw882xx_dev_set_algo_en; + aw_pa->ops.aw_i2c_read = aw882xx_dev_i2c_read; + aw_pa->ops.aw_i2c_write = aw882xx_dev_i2c_write; + aw_pa->ops.aw_i2c_write_bits = aw882xx_dev_i2c_write_bits; + aw_pa->ops.aw_get_hw_volume = aw_pid_2055_get_volume; + aw_pa->ops.aw_set_hw_volume = aw_pid_2055_set_volume; + aw_pa->ops.aw_reg_val_to_db = aw_pid_2055_reg_val_to_db; + aw_pa->ops.aw_check_rd_access = aw_pid_2055_check_rd_access; + aw_pa->ops.aw_check_wr_access = aw_pid_2055_check_wr_access; + aw_pa->ops.aw_get_reg_num = aw_pid_2055_get_reg_num; + aw_pa->ops.aw_get_irq_type = aw_pid_2055_get_irq_type; + + aw_pa->int_desc.mask_reg = AW_PID_2055_SYSINTM_REG; + aw_pa->int_desc.mask_default = AW_PID_2055_SYSINTM_DEFAULT; + aw_pa->int_desc.int_mask = AW_PID_2055_SYSINTM_DEFAULT; + aw_pa->int_desc.st_reg = AW_PID_2055_SYSINT_REG; + + aw_pa->pwd_desc.reg = AW_PID_2055_SYSCTRL_REG; + aw_pa->pwd_desc.mask = AW_PID_2055_PWDN_MASK; + aw_pa->pwd_desc.enable = AW_PID_2055_PWDN_POWER_DOWN_VALUE; + aw_pa->pwd_desc.disable = AW_PID_2055_PWDN_WORKING_VALUE; + + aw_pa->amppd_desc.reg = AW_PID_2055_SYSCTRL_REG; + aw_pa->amppd_desc.mask = AW_PID_2055_AMPPD_MASK; + aw_pa->amppd_desc.enable = AW_PID_2055_AMPPD_POWER_DOWN_VALUE; + aw_pa->amppd_desc.disable = AW_PID_2055_AMPPD_WORKING_VALUE; + + aw_pa->mute_desc.reg = AW_PID_2055_SYSCTRL_REG; + aw_pa->mute_desc.mask = AW_PID_2055_HMUTE_MASK; + aw_pa->mute_desc.enable = AW_PID_2055_HMUTE_ENABLE_VALUE; + aw_pa->mute_desc.disable = AW_PID_2055_HMUTE_DISABLE_VALUE; + + aw_pa->uls_hmute_desc.reg = AW_REG_NONE; + + aw_pa->work_mode.reg = AW_PID_2055_SYSCTRL_REG; + aw_pa->work_mode.mask = AW_PID_2055_RCV_MODE_MASK; + aw_pa->work_mode.spk_val = AW_PID_2055_RCV_MODE_SPEAKER_VALUE; + aw_pa->work_mode.rcv_val = AW_PID_2055_RCV_MODE_RECEIVER_VALUE; + + aw_pa->vcalb_desc.vcalb_reg = AW_REG_NONE; + aw_pa->vcalb_desc.vcalk_reg = AW_REG_NONE; + aw_pa->vcalb_desc.icalk_reg = AW_REG_NONE; + + aw_pa->txen_desc.reg = AW_PID_2055_I2SCTRL1_REG; + aw_pa->txen_desc.mask = AW_PID_2055_I2STXEN_MASK; + aw_pa->txen_desc.enable = AW_PID_2055_I2STXEN_ENABLE_VALUE; + aw_pa->txen_desc.disable = AW_PID_2055_I2STXEN_DISABLE_VALUE; + + aw_pa->sysst_desc.reg = AW_PID_2055_SYSST_REG; + aw_pa->sysst_desc.mask = AW_PID_2055_SYSST_CHECK_MASK; + aw_pa->sysst_desc.st_check = AW_PID_2055_SYSST_CHECK; + aw_pa->sysst_desc.pll_check = AW_PID_2055_IIS_CHECK; + + aw_pa->spin_desc.rx_desc.reg = AW_PID_2055_I2SCTRL1_REG; + aw_pa->spin_desc.rx_desc.mask = AW_PID_2055_CHSEL_MASK; + aw_pa->spin_desc.rx_desc.left_val = AW_PID_2055_CHSEL_LEFT_VALUE; + aw_pa->spin_desc.rx_desc.right_val = AW_PID_2055_CHSEL_RIGHT_VALUE; + + aw_pa->voltage_desc.reg = AW_PID_2055_VBAT_REG; + aw_pa->voltage_desc.int_bit = AW_PID_2055_MONITOR_INT_10BIT; + aw_pa->voltage_desc.vbat_range = AW_PID_2055_MONITOR_VBAT_RANGE; + + aw_pa->temp_desc.reg = AW_PID_2055_TEMP_REG; + aw_pa->temp_desc.neg_mask = AW_PID_2055_MONITOR_TEMP_NEG_MASK; + aw_pa->temp_desc.sign_mask = AW_PID_2055_MONITOR_TEMP_SIGN_MASK; + + aw_pa->ipeak_desc.reg = AW_PID_2055_BSTCTRL2_REG; + aw_pa->ipeak_desc.mask = AW_PID_2055_BST_IPEAK_MASK; + + aw_pa->volume_desc.reg = AW_PID_2055_SYSCTRL2_REG; + aw_pa->volume_desc.mask = AW_PID_2055_VOL_MASK; + aw_pa->volume_desc.shift = AW_PID_2055_VOL_START_BIT; + aw_pa->volume_desc.mute_volume = AW_PID_2055_MUTE_VOL; + aw_pa->volume_desc.ctl_volume = AW_PID_2055_VOL_DEFAULT_VALUE; + + aw_pa->cco_mux_desc.reg = AW_PID_2055_PLLCTRL3_REG; + aw_pa->cco_mux_desc.mask = AW_PID_2055_CCO_MUX_MASK; + aw_pa->cco_mux_desc.divided_val = AW_PID_2055_CCO_MUX_DIVIDED_VALUE; + aw_pa->cco_mux_desc.bypass_val = AW_PID_2055_CCO_MUX_BYPASS_VALUE; + + aw_pa->bop_desc.reg = AW_PID_2055_SADCCTRL3_REG; + aw_pa->bop_desc.mask = AW_PID_2055_BOP_EN_MASK; + aw_pa->bop_desc.enable = AW_PID_2055_BOP_EN_ENABLE_VALUE; + aw_pa->bop_desc.disbale = AW_PID_2055_BOP_EN_DISABLE_VALUE; + + aw_pa->soft_rst.reg = AW882XX_SOFT_RESET_REG; + aw_pa->soft_rst.reg_value = AW882XX_SOFT_RESET_VALUE; + + aw_pa->efcheck_desc.reg = AW_REG_NONE; + + aw_pa->dither_desc.reg = AW_PID_2055_DBGCTRL_REG; + aw_pa->dither_desc.mask = AW_PID_2055_DITHER_MASK; + aw_pa->dither_desc.enable = AW_PID_2055_DITHER_ENABLE_VALUE; + aw_pa->dither_desc.disable = AW_PID_2055_DITHER_DISABLE_VALUE; + + aw_pa->noise_gate_desc.reg = AW_REG_NONE; + + aw_pa->auth_desc.reg_in = AW_PID_2055_TESTIN_REG; + aw_pa->auth_desc.reg_out = AW_PID_2055_TESTOUT_REG; + + aw_pa->psm_desc.reg = AW_REG_NONE; + aw_pa->mpd_desc.reg = AW_REG_NONE; + aw_pa->dsmzth_desc.reg = AW_REG_NONE; + + usleep_range(AW_2000_US, AW_2000_US + 10); + aw_pa->ops.aw_i2c_write(aw_pa, AW_PID_2055_INIT_CHECK_REG, + AW_PID_2055_INIT_CHECK_VALUE); + usleep_range(AW_3000_US, AW_3000_US + 10); + + ret = aw882xx_device_probe(aw_pa); + + aw882xx->aw_pa = aw_pa; + return ret; +} + +static int aw_pid_2055_dev_check(struct aw882xx *aw882xx) +{ + unsigned int reg_data = 0; + + aw882xx_i2c_write(aw882xx, AW882XX_SOFT_RESET_REG, AW882XX_SOFT_RESET_VALUE); + usleep_range(AW_1000_US, AW_1000_US + 100); + + aw882xx_i2c_read(aw882xx, AW_PID_2055_VERSION_DIFF_REG, ®_data); + if (reg_data == AW_PID_2055A_VERSION_VALUE) + return aw_pid_2055a_dev_init(aw882xx); + else if (reg_data == AW_PID_2055_VERSION_VALUE) + return aw_pid_2055_dev_init(aw882xx); + + aw_dev_err(aw882xx->dev, "unsupported 2055 verison, 0x%04x", reg_data); + + return -EINVAL; +} + +/* [9 : 6]: -6DB ; [5 : 0]: 0.125DB real_value = value * 8 : 0.125db --> 1 */ +static unsigned int aw_pid_2071_reg_val_to_db(unsigned int value) +{ + return ((value >> 6) * AW_PID_2071_VOL_STEP_DB + (value & 0x3f)); +} + +/* [9 : 6]: -6DB ; [5 : 0]: 0.125DB reg_value = value / step << 6 + value % step ; step = 6 * 8 */ +static unsigned int aw_pid_2071_db_val_to_reg(unsigned int value) +{ + return (((value / AW_PID_2071_VOL_STEP_DB) << 6) + (value % AW_PID_2071_VOL_STEP_DB)); +} + +static int aw_pid_2071_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + struct aw_volume_desc *vol_desc = &aw882xx->aw_pa->volume_desc; + + real_value = aw_pid_2071_db_val_to_reg(AW_GET_MIN_VALUE(value, vol_desc->mute_volume)); + + /* cal real value */ + aw882xx_i2c_read(aw882xx, AW_PID_2071_SYSCTRL2_REG, ®_value); + + aw_dev_dbg(aw882xx->dev, "value %d , 0x%x", value, real_value); + + /* [15 : 6] volume */ + real_value = (real_value << 6) | (reg_value & 0x003f); + + /* write value */ + aw882xx_i2c_write(aw882xx, AW_PID_2071_SYSCTRL2_REG, real_value); + return 0; +} + +static int aw_pid_2071_get_volume(struct aw_device *aw_dev, unsigned int *value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + /* read value */ + aw882xx_i2c_read(aw882xx, AW_PID_2071_SYSCTRL2_REG, ®_value); + + /* [15 : 6] volume */ + real_value = reg_value >> 6; + + real_value = aw_pid_2071_reg_val_to_db(real_value); + *value = real_value; + + return 0; +} + +static bool aw_pid_2071_check_rd_access(int reg) +{ + if (reg >= AW_PID_2071_REG_MAX) + return false; + + if (aw_pid_2071_reg_access[reg] & AW_PID_2071_REG_RD_ACCESS) + return true; + else + return false; +} + +static bool aw_pid_2071_check_wr_access(int reg) +{ + if (reg >= AW_PID_2071_REG_MAX) + return false; + + if (aw_pid_2071_reg_access[reg] & + AW_PID_2071_REG_WR_ACCESS) + return true; + else + return false; +} + +static int aw_pid_2071_get_reg_num(void) +{ + return AW_PID_2071_REG_MAX; +} + +static unsigned int aw_pid_2071_get_irq_type(struct aw_device *aw_dev, + unsigned int value) +{ + unsigned int ret = INT_TYPE_NONE; + + /* UVL0 */ + if (value & (~AW_PID_2071_UVLI_MASK)) { + aw_dev_info(aw_dev->dev, "UVLO: occur"); + ret |= INT_TYPE_UVLO; + } + + /* BSTOCM */ + if (value & (~AW_PID_2071_BSTOCI_MASK)) { + aw_dev_info(aw_dev->dev, "BSTOCI: occur"); + ret |= INT_TYPE_BSTOC; + } + + /* OCDI */ + if (value & (~AW_PID_2071_OCDI_MASK)) { + aw_dev_info(aw_dev->dev, "OCDI: occur"); + ret |= INT_TYPE_OCDI; + } + + /* OTHI */ + if (value & (~AW_PID_2071_OTHI_MASK)) { + aw_dev_info(aw_dev->dev, "OTHI: occur"); + ret |= INT_TYPE_OTHI; + } + + return ret; +} + +static int aw_pid_2071_dev_init(struct aw882xx *aw882xx) +{ + int ret = 0; + struct aw_device *aw_pa = aw882xx->aw_pa; + + /*call aw device init func*/ + memset(aw_pa->monitor_name, 0, AW_NAME_MAX); + memcpy(aw_pa->monitor_name, AW_PID_2071_MONITOR_FILE, strlen(AW_PID_2071_MONITOR_FILE)); + + aw_pa->prof_info.prof_desc = NULL; + aw_pa->prof_info.count = 0; + aw_pa->channel = 0; + aw_pa->bstcfg_enable = AW_BSTCFG_DISABLE; + aw_pa->bop_en = AW_BOP_DISABLE; + aw_pa->vol_step = AW_PID_2071_VOL_STEP; + + aw_pa->private_data = (void *)aw882xx; + aw_pa->dev = aw882xx->dev; + aw_pa->i2c = aw882xx->i2c; + aw_pa->ops.aw_get_version = aw882xx_get_version; + aw_pa->ops.aw_get_dev_num = aw882xx_get_dev_num; + aw_pa->ops.aw_set_algo = aw882xx_dev_set_algo_en; + aw_pa->ops.aw_i2c_read = aw882xx_dev_i2c_read; + aw_pa->ops.aw_i2c_write = aw882xx_dev_i2c_write; + aw_pa->ops.aw_i2c_write_bits = aw882xx_dev_i2c_write_bits; + aw_pa->ops.aw_get_hw_volume = aw_pid_2071_get_volume; + aw_pa->ops.aw_set_hw_volume = aw_pid_2071_set_volume; + aw_pa->ops.aw_reg_val_to_db = aw_pid_2071_reg_val_to_db; + aw_pa->ops.aw_check_rd_access = aw_pid_2071_check_rd_access; + aw_pa->ops.aw_check_wr_access = aw_pid_2071_check_wr_access; + aw_pa->ops.aw_get_reg_num = aw_pid_2071_get_reg_num; + aw_pa->ops.aw_get_irq_type = aw_pid_2071_get_irq_type; + + aw_pa->int_desc.mask_reg = AW_PID_2071_SYSINTM_REG; + aw_pa->int_desc.mask_default = AW_PID_2071_SYSINTM_DEFAULT; + aw_pa->int_desc.int_mask = AW_PID_2071_SYSINTM_DEFAULT; + aw_pa->int_desc.st_reg = AW_PID_2071_SYSINT_REG; + + aw_pa->work_mode.reg = AW_PID_2071_SYSCTRL_REG; + aw_pa->work_mode.mask = AW_PID_2071_RCV_MODE_MASK; + aw_pa->work_mode.spk_val = AW_PID_2071_RCV_MODE_SPEAKER_VALUE; + aw_pa->work_mode.rcv_val = AW_PID_2071_RCV_MODE_RECEIVER_VALUE; + + aw_pa->pwd_desc.reg = AW_PID_2071_SYSCTRL_REG; + aw_pa->pwd_desc.mask = AW_PID_2071_PWDN_MASK; + aw_pa->pwd_desc.enable = AW_PID_2071_PWDN_POWER_DOWN_VALUE; + aw_pa->pwd_desc.disable = AW_PID_2071_PWDN_WORKING_VALUE; + + aw_pa->amppd_desc.reg = AW_PID_2071_SYSCTRL_REG; + aw_pa->amppd_desc.mask = AW_PID_2071_AMPPD_MASK; + aw_pa->amppd_desc.enable = AW_PID_2071_AMPPD_POWER_DOWN_VALUE; + aw_pa->amppd_desc.disable = AW_PID_2071_AMPPD_WORKING_VALUE; + + aw_pa->mute_desc.reg = AW_PID_2071_SYSCTRL2_REG; + aw_pa->mute_desc.mask = AW_PID_2071_HMUTE_MASK; + aw_pa->mute_desc.enable = AW_PID_2071_HMUTE_ENABLE_VALUE; + aw_pa->mute_desc.disable = AW_PID_2071_HMUTE_DISABLE_VALUE; + + aw_pa->uls_hmute_desc.reg = AW_REG_NONE; + + aw_pa->txen_desc.reg = AW_PID_2071_I2SCFG1_REG; + aw_pa->txen_desc.mask = AW_PID_2071_I2STXEN_MASK; + aw_pa->txen_desc.enable = AW_PID_2071_I2STXEN_ENABLE_VALUE; + aw_pa->txen_desc.disable = AW_PID_2071_I2STXEN_DISABLE_VALUE; + + aw_pa->vcalb_desc.vcalb_reg = AW_PID_2071_VTMCTRL3_REG; + aw_pa->vcalb_desc.vcal_factor = AW_PID_2071_VCAL_FACTOR; + aw_pa->vcalb_desc.cabl_base_value = AW_PID_2071_CABL_BASE_VALUE; + + aw_pa->vcalb_desc.icalk_value_factor = AW_PID_2071_ICABLK_FACTOR; + aw_pa->vcalb_desc.icalk_reg = AW_PID_2071_EFRH_REG; + aw_pa->vcalb_desc.icalk_reg_mask = AW_PID_2071_EF_VSN_OFFSET_MASK; + aw_pa->vcalb_desc.icalk_shift = AW_PID_2071_ICALK_SHIFT; + aw_pa->vcalb_desc.icalkl_reg = AW_PID_2071_EFRM1_REG; + aw_pa->vcalb_desc.icalkl_reg_mask = AW_PID_2071_EF_ISN_OFFSET_MASK; + aw_pa->vcalb_desc.icalkl_shift = AW_PID_2071_ICALKL_SHIFT; + aw_pa->vcalb_desc.icalk_sign_mask = AW_PID_2071_EF_ISN_GESLP_SIGN_MASK; + aw_pa->vcalb_desc.icalk_neg_mask = AW_PID_2071_EF_ISN_GESLP_NEG; + + aw_pa->vcalb_desc.vcalk_reg = AW_PID_2071_EFRH_REG; + aw_pa->vcalb_desc.vcalk_reg_mask = AW_PID_2071_EF_VSN_GESLP_MASK; + aw_pa->vcalb_desc.vcalkl_reg = AW_REG_NONE; + aw_pa->vcalb_desc.vcalk_sign_mask = AW_PID_2071_EF_VSN_GESLP_SIGN_MASK; + aw_pa->vcalb_desc.vcalk_neg_mask = AW_PID_2071_EF_VSN_GESLP_NEG; + aw_pa->vcalb_desc.vcalk_value_factor = AW_PID_2071_VCABLK_FACTOR; + + aw_pa->spin_desc.rx_desc.reg = AW_PID_2071_I2SCTRL_REG; + aw_pa->spin_desc.rx_desc.mask = AW_PID_2071_CHSEL_MASK; + aw_pa->spin_desc.rx_desc.left_val = AW_PID_2071_CHSEL_LEFT_VALUE; + aw_pa->spin_desc.rx_desc.right_val = AW_PID_2071_CHSEL_RIGHT_VALUE; + + aw_pa->sysst_desc.reg = AW_PID_2071_SYSST_REG; + aw_pa->sysst_desc.mask = AW_PID_2071_SYSST_CHECK_MASK; + aw_pa->sysst_desc.st_check = AW_PID_2071_SYSST_CHECK; + aw_pa->sysst_desc.pll_check = AW_PID_2071_IIS_CHECK; + + aw_pa->cco_mux_desc.reg = AW_PID_2071_PLLCTRL1_REG; + aw_pa->cco_mux_desc.mask = AW_PID_2071_CCO_MUX_MASK; + aw_pa->cco_mux_desc.divided_val = AW_PID_2071_CCO_MUX_DIVIDED_VALUE; + aw_pa->cco_mux_desc.bypass_val = AW_PID_2071_CCO_MUX_BYPASS_VALUE; + + aw_pa->voltage_desc.reg = AW_PID_2071_VBAT_REG; + aw_pa->voltage_desc.int_bit = AW_PID_2071_MONITOR_INT_10BIT; + aw_pa->voltage_desc.vbat_range = AW_PID_2071_MONITOR_VBAT_RANGE; + + aw_pa->temp_desc.reg = AW_PID_2071_TEMP_REG; + aw_pa->temp_desc.neg_mask = AW_PID_2071_MONITOR_TEMP_NEG_MASK; + aw_pa->temp_desc.sign_mask = AW_PID_2071_MONITOR_TEMP_SIGN_MASK; + + aw_pa->ipeak_desc.reg = AW_PID_2071_SYSCTRL2_REG; + aw_pa->ipeak_desc.mask = AW_PID_2071_BST_IPEAK_MASK; + + aw_pa->volume_desc.reg = AW_PID_2071_SYSCTRL2_REG; + aw_pa->volume_desc.mask = AW_PID_2071_VOL_MASK; + aw_pa->volume_desc.shift = AW_PID_2071_VOL_START_BIT; + aw_pa->volume_desc.mute_volume = AW_PID_2071_MUTE_VOL; + aw_pa->volume_desc.ctl_volume = AW_PID_2071_VOL_DEFAULT_VALUE; + + aw_pa->efcheck_desc.reg = AW_REG_NONE; + aw_pa->efuse_check = AW_EF_OR_CHECK; + + aw_pa->bop_desc.reg = AW_REG_NONE; + + aw_pa->dither_desc.reg = AW_PID_2071_DBGCTRL_REG; + aw_pa->dither_desc.mask = AW_PID_2071_DITHER_MASK; + aw_pa->dither_desc.enable = AW_PID_2071_DITHER_ENABLE_VALUE; + aw_pa->dither_desc.disable = AW_PID_2071_DITHER_DISABLE_VALUE; + + aw_pa->soft_rst.reg = AW882XX_SOFT_RESET_REG; + aw_pa->soft_rst.reg_value = AW882XX_SOFT_RESET_VALUE; + + aw_pa->noise_gate_desc.reg = AW_REG_NONE; + + aw_pa->auth_desc.reg_in = AW_PID_2071_TESTIN_REG; + aw_pa->auth_desc.reg_out = AW_PID_2071_TESTOUT_REG; + + aw_pa->psm_desc.reg = AW_REG_NONE; + aw_pa->mpd_desc.reg = AW_REG_NONE; + aw_pa->dsmzth_desc.reg = AW_REG_NONE; + + ret = aw882xx_device_probe(aw_pa); + + aw882xx->aw_pa = aw_pa; + return ret; +} + +/* [9 : 6]: -6DB ; [5 : 0]: 0.125DB real_value = value * 8 : 0.125db --> 1 */ +static unsigned int aw_pid_2113_reg_val_to_db(unsigned int value) +{ + return ((value >> 6) * AW_PID_2113_VOL_STEP_DB + (value & 0x3f)); +} + +/* [9 : 6]: -6DB ; [5 : 0]: 0.125DB reg_value = value / step << 6 + value % step ; step = 6 * 8 */ +static unsigned int aw_pid_2113_db_val_to_reg(unsigned int value) +{ + return (((value / AW_PID_2113_VOL_STEP_DB) << 6) + (value % AW_PID_2113_VOL_STEP_DB)); +} + +static int aw_pid_2113_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + struct aw_volume_desc *vol_desc = &aw882xx->aw_pa->volume_desc; + + real_value = aw_pid_2113_db_val_to_reg(AW_GET_MIN_VALUE(value, vol_desc->mute_volume)); + + aw_dev_dbg(aw882xx->dev, "value:%d, min_val: %d, real_value: 0x%x", + value, AW_GET_MIN_VALUE(value, vol_desc->mute_volume), real_value); + + /* cal real value */ + aw882xx_i2c_read(aw882xx, AW_PID_2113_SYSCTRL2_REG, ®_value); + + /*[9 : 0] volume*/ + real_value = (real_value | (reg_value & 0xfc00)); + + /* write value */ + aw882xx_i2c_write(aw882xx, AW_PID_2113_SYSCTRL2_REG, real_value); + + return 0; +} + +static int aw_pid_2113_get_volume(struct aw_device *aw_dev, unsigned int *value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + /* read value */ + aw882xx_i2c_read(aw882xx, AW_PID_2113_SYSCTRL2_REG, ®_value); + + /* [9 : 0] volume */ + real_value = (reg_value & 0x03ff); + + real_value = aw_pid_2113_reg_val_to_db(real_value); + *value = real_value; + + return 0; +} + +static bool aw_pid_2113_check_rd_access(int reg) +{ + if (reg >= AW_PID_2113_REG_MAX) + return false; + + if (aw_pid_2113_reg_access[reg] & AW_PID_2113_REG_RD_ACCESS) + return true; + else + return false; +} + +static bool aw_pid_2113_check_wr_access(int reg) +{ + if (reg >= AW_PID_2113_REG_MAX) + return false; + + if (aw_pid_2113_reg_access[reg] & + AW_PID_2113_REG_WR_ACCESS) + return true; + else + return false; +} + +static int aw_pid_2113_get_reg_num(void) +{ + return AW_PID_2113_REG_MAX; +} + +static unsigned int aw_pid_2113_get_irq_type(struct aw_device *aw_dev, + unsigned int value) +{ + unsigned int ret = INT_TYPE_NONE; + + /* UVL0 */ + if (value & (~AW_PID_2113_UVLI_MASK)) { + aw_dev_info(aw_dev->dev, "UVLO: occur"); + ret |= INT_TYPE_UVLO; + } + + /* BSTOCM */ + if (value & (~AW_PID_2113_BSTOCI_MASK)) { + aw_dev_info(aw_dev->dev, "BSTOCI: occur"); + ret |= INT_TYPE_BSTOC; + } + + /* OCDI */ + if (value & (~AW_PID_2113_OCDI_MASK)) { + aw_dev_info(aw_dev->dev, "OCDI: occur"); + ret |= INT_TYPE_OCDI; + } + + /* OTHI */ + if (value & (~AW_PID_2113_OTHI_MASK)) { + aw_dev_info(aw_dev->dev, "OTHI: occur"); + ret |= INT_TYPE_OTHI; + } + + return ret; +} + +static int aw_pid_2113_frcset_check(struct aw_device *aw_dev) +{ + unsigned int reg_val = 0; + uint16_t temh = 0; + uint16_t teml = 0; + uint16_t tem = 0; + + aw_dev->ops.aw_i2c_read(aw_dev, + AW_PID_2113_EFRH3_REG, ®_val); + temh = ((uint16_t)reg_val & (~AW_PID_2113_TEMH_MASK)); + + aw_dev->ops.aw_i2c_read(aw_dev, + AW_PID_2113_EFRL3_REG, ®_val); + teml = ((uint16_t)reg_val & (~AW_PID_2113_TEML_MASK)); + + if (aw_dev->efuse_check == AW_EF_OR_CHECK) + tem = (temh | teml); + else + tem = (temh & teml); + + if (tem == AW_PID_2113_DEFAULT_CFG) + aw_dev->frcset_en = AW_FRCSET_ENABLE; + else + aw_dev->frcset_en = AW_FRCSET_DISABLE; + + aw_dev_info(aw_dev->dev, "tem is 0x%04x, frcset_en is %d", + tem, aw_dev->frcset_en); + return 0; +} + +static void aw_pid_2113_reg_force_set(struct aw_device *aw_dev) +{ + aw_dev_dbg(aw_dev->dev, "enter"); + + if (aw_dev->frcset_en == AW_FRCSET_ENABLE) { + /*set FORCE_PWM*/ + aw_dev->ops.aw_i2c_write_bits(aw_dev, AW_PID_2113_BSTCTRL3_REG, + AW_PID_2113_FORCE_PWM_MASK, AW_PID_2113_FORCE_PWM_FORCEMINUS_PWM_VALUE); + /*set BOOST_OS_WIDTH*/ + aw_dev->ops.aw_i2c_write_bits(aw_dev, AW_PID_2113_BSTCTRL5_REG, + AW_PID_2113_BST_OS_WIDTH_MASK, AW_PID_2113_BST_OS_WIDTH_50NS_VALUE); + /*set BURST_LOOPR*/ + aw_dev->ops.aw_i2c_write_bits(aw_dev, AW_PID_2113_BSTCTRL6_REG, + AW_PID_2113_BST_LOOPR_MASK, AW_PID_2113_BST_LOOPR_340K_VALUE); + /*set RSQN_DLY*/ + aw_dev->ops.aw_i2c_write_bits(aw_dev, AW_PID_2113_BSTCTRL7_REG, + AW_PID_2113_RSQN_DLY_MASK, AW_PID_2113_RSQN_DLY_35NS_VALUE); + /*set BURST_SSMODE*/ + aw_dev->ops.aw_i2c_write_bits(aw_dev, AW_PID_2113_BSTCTRL8_REG, + AW_PID_2113_BURST_SSMODE_MASK, AW_PID_2113_BURST_SSMODE_FAST_VALUE); + /*set BST_BURST*/ + aw_dev->ops.aw_i2c_write_bits(aw_dev, AW_PID_2113_BSTCTRL9_REG, + AW_PID_2113_BST_BURST_MASK, AW_PID_2113_BST_BURST_30MA_VALUE); + aw_dev_dbg(aw_dev->dev, "force set reg done!"); + } else { + aw_dev_info(aw_dev->dev, "needn't set reg value"); + } +} + +static int aw_pid_2113_dev_init(struct aw882xx *aw882xx) +{ + int ret = 0; + struct aw_device *aw_pa = aw882xx->aw_pa; + + /*call aw device init func*/ + memset(aw_pa->monitor_name, 0, AW_NAME_MAX); + memcpy(aw_pa->monitor_name, AW_PID_2113_MONITOR_FILE, strlen(AW_PID_2113_MONITOR_FILE)); + + aw_pa->prof_info.prof_desc = NULL; + aw_pa->prof_info.count = 0; + aw_pa->channel = 0; + aw_pa->bstcfg_enable = AW_BSTCFG_DISABLE; + aw_pa->bop_en = AW_BOP_DISABLE; + aw_pa->vol_step = AW_PID_2113_VOL_STEP; + + aw_pa->private_data = (void *)aw882xx; + aw_pa->dev = aw882xx->dev; + aw_pa->i2c = aw882xx->i2c; + aw_pa->ops.aw_get_version = aw882xx_get_version; + aw_pa->ops.aw_get_dev_num = aw882xx_get_dev_num; + aw_pa->ops.aw_set_algo = aw882xx_dev_set_algo_en; + aw_pa->ops.aw_i2c_read = aw882xx_dev_i2c_read; + aw_pa->ops.aw_i2c_write = aw882xx_dev_i2c_write; + aw_pa->ops.aw_i2c_write_bits = aw882xx_dev_i2c_write_bits; + aw_pa->ops.aw_get_hw_volume = aw_pid_2113_get_volume; + aw_pa->ops.aw_set_hw_volume = aw_pid_2113_set_volume; + aw_pa->ops.aw_reg_val_to_db = aw_pid_2113_reg_val_to_db; + aw_pa->ops.aw_check_rd_access = aw_pid_2113_check_rd_access; + aw_pa->ops.aw_check_wr_access = aw_pid_2113_check_wr_access; + aw_pa->ops.aw_get_reg_num = aw_pid_2113_get_reg_num; + aw_pa->ops.aw_get_irq_type = aw_pid_2113_get_irq_type; + aw_pa->ops.aw_reg_force_set = aw_pid_2113_reg_force_set; + aw_pa->ops.aw_frcset_check = aw_pid_2113_frcset_check; + + aw_pa->int_desc.mask_reg = AW_PID_2113_SYSINTM_REG; + aw_pa->int_desc.mask_default = AW_PID_2113_SYSINTM_DEFAULT; + aw_pa->int_desc.int_mask = AW_PID_2113_SYSINTM_DEFAULT; + aw_pa->int_desc.st_reg = AW_PID_2113_SYSINT_REG; + + aw_pa->work_mode.reg = AW_PID_2113_SYSCTRL_REG; + aw_pa->work_mode.mask = AW_PID_2113_EN_TRAN_MASK; + aw_pa->work_mode.spk_val = AW_PID_2113_EN_TRAN_SPK_VALUE; + aw_pa->work_mode.rcv_val = AW_PID_2113_EN_TRAN_RCV_VALUE; + + aw_pa->pwd_desc.reg = AW_PID_2113_SYSCTRL_REG; + aw_pa->pwd_desc.mask = AW_PID_2113_PWDN_MASK; + aw_pa->pwd_desc.enable = AW_PID_2113_PWDN_POWER_DOWN_VALUE; + aw_pa->pwd_desc.disable = AW_PID_2113_PWDN_WORKING_VALUE; + + aw_pa->work_mode.reg = AW_PID_2113_SYSCTRL_REG; + aw_pa->work_mode.mask = AW_PID_2113_EN_TRAN_MASK; + aw_pa->work_mode.spk_val = AW_PID_2113_EN_TRAN_SPK_VALUE; + aw_pa->work_mode.rcv_val = AW_PID_2113_EN_TRAN_RCV_VALUE; + + aw_pa->amppd_desc.reg = AW_PID_2113_SYSCTRL_REG; + aw_pa->amppd_desc.mask = AW_PID_2113_AMPPD_MASK; + aw_pa->amppd_desc.enable = AW_PID_2113_AMPPD_POWER_DOWN_VALUE; + aw_pa->amppd_desc.disable = AW_PID_2113_AMPPD_WORKING_VALUE; + + aw_pa->mute_desc.reg = AW_PID_2113_SYSCTRL_REG; + aw_pa->mute_desc.mask = AW_PID_2113_HMUTE_MASK; + aw_pa->mute_desc.enable = AW_PID_2113_HMUTE_ENABLE_VALUE; + aw_pa->mute_desc.disable = AW_PID_2113_HMUTE_DISABLE_VALUE; + + aw_pa->uls_hmute_desc.reg = AW_PID_2113_SYSCTRL_REG; + aw_pa->uls_hmute_desc.mask = AW_PID_2113_ULS_HMUTE_MASK; + aw_pa->uls_hmute_desc.enable = AW_PID_2113_ULS_HMUTE_ENABLE_VALUE; + aw_pa->uls_hmute_desc.disable = AW_PID_2113_ULS_HMUTE_DISABLE_VALUE; + + aw_pa->vcalb_desc.vcalb_reg = AW_PID_2113_VSNTM1_REG; + aw_pa->vcalb_desc.vcal_factor = AW_PID_2113_VCAL_FACTOR; + aw_pa->vcalb_desc.cabl_base_value = AW_PID_2113_CABL_BASE_VALUE; + + aw_pa->txen_desc.reg = AW_PID_2113_I2SCTRL3_REG; + aw_pa->txen_desc.mask = AW_PID_2113_I2STXEN_MASK; + aw_pa->txen_desc.enable = AW_PID_2113_I2STXEN_ENABLE_VALUE; + aw_pa->txen_desc.disable = AW_PID_2113_I2STXEN_DISABLE_VALUE; + + aw_pa->vcalb_desc.icalk_reg = AW_PID_2113_EFRH4_REG; + aw_pa->vcalb_desc.icalk_reg_mask = AW_PID_2113_EF_ISN_GESLP_H_MASK; + aw_pa->vcalb_desc.icalk_shift = AW_PID_2113_ICALK_SHIFT; + aw_pa->vcalb_desc.icalkl_reg = AW_PID_2113_EFRL4_REG; + aw_pa->vcalb_desc.icalkl_reg_mask = AW_PID_2113_EF_ISN_GESLP_L_MASK; + aw_pa->vcalb_desc.icalkl_shift = AW_PID_2113_ICALKL_SHIFT; + aw_pa->vcalb_desc.icalk_sign_mask = AW_PID_2113_EF_ISN_GESLP_SIGN_MASK; + aw_pa->vcalb_desc.icalk_neg_mask = AW_PID_2113_EF_ISN_GESLP_NEG; + aw_pa->vcalb_desc.icalk_value_factor = AW_PID_2113_ICABLK_FACTOR; + + aw_pa->vcalb_desc.vcalk_reg = AW_PID_2113_EFRH3_REG; + aw_pa->vcalb_desc.vcalk_reg_mask = AW_PID_2113_EF_VSN_GESLP_H_MASK; + aw_pa->vcalb_desc.vcalk_shift = AW_PID_2113_VCALK_SHIFT; + aw_pa->vcalb_desc.vcalkl_reg = AW_PID_2113_EFRL3_REG; + aw_pa->vcalb_desc.vcalkl_reg_mask = AW_PID_2113_EF_VSN_GESLP_L_MASK; + aw_pa->vcalb_desc.vcalkl_shift = AW_PID_2113_VCALKL_SHIFT; + aw_pa->vcalb_desc.vcalk_sign_mask = AW_PID_2113_EF_VSN_GESLP_SIGN_MASK; + aw_pa->vcalb_desc.vcalk_neg_mask = AW_PID_2113_EF_VSN_GESLP_NEG; + aw_pa->vcalb_desc.vcalk_value_factor = AW_PID_2113_VCABLK_FACTOR; + + aw_pa->spin_desc.rx_desc.reg = AW_PID_2113_I2SCTRL1_REG; + aw_pa->spin_desc.rx_desc.mask = AW_PID_2113_CHSEL_MASK; + aw_pa->spin_desc.rx_desc.left_val = AW_PID_2113_CHSEL_LEFT_VALUE; + aw_pa->spin_desc.rx_desc.right_val = AW_PID_2113_CHSEL_RIGHT_VALUE; + + aw_pa->sysst_desc.reg = AW_PID_2113_SYSST_REG; + aw_pa->sysst_desc.mask = AW_PID_2113_SYSST_CHECK_MASK; + aw_pa->sysst_desc.st_check = AW_PID_2113_SYSST_CHECK; + aw_pa->sysst_desc.pll_check = AW_PID_2113_IIS_CHECK; + + aw_pa->cco_mux_desc.reg = AW_PID_2113_PLLCTRL1_REG; + aw_pa->cco_mux_desc.mask = AW_PID_2113_CCO_MUX_MASK; + aw_pa->cco_mux_desc.divided_val = AW_PID_2113_CCO_MUX_DIVIDED_VALUE; + aw_pa->cco_mux_desc.bypass_val = AW_PID_2113_CCO_MUX_BYPASS_VALUE; + + aw_pa->voltage_desc.reg = AW_PID_2113_VBAT_REG; + aw_pa->voltage_desc.int_bit = AW_PID_2113_MONITOR_INT_10BIT; + aw_pa->voltage_desc.vbat_range = AW_PID_2113_MONITOR_VBAT_RANGE; + + aw_pa->temp_desc.reg = AW_PID_2113_TEMP_REG; + aw_pa->temp_desc.neg_mask = AW_PID_2113_MONITOR_TEMP_NEG_MASK; + aw_pa->temp_desc.sign_mask = AW_PID_2113_MONITOR_TEMP_SIGN_MASK; + + aw_pa->ipeak_desc.reg = AW_PID_2113_BSTCTRL2_REG; + aw_pa->ipeak_desc.mask = AW_PID_2113_BST_IPEAK_MASK; + + aw_pa->volume_desc.reg = AW_PID_2113_SYSCTRL2_REG; + aw_pa->volume_desc.mask = AW_PID_2113_VOL_MASK; + aw_pa->volume_desc.shift = AW_PID_2113_VOL_START_BIT; + aw_pa->volume_desc.mute_volume = AW_PID_2113_MUTE_VOL; + aw_pa->volume_desc.ctl_volume = AW_PID_2113_VOL_DEFAULT_VALUE; + + aw_pa->bop_desc.reg = AW_PID_2113_SADCCTRL3_REG; + aw_pa->bop_desc.mask = AW_PID_2113_BOP_EN_MASK; + aw_pa->bop_desc.enable = AW_PID_2113_BOP_EN_ENABLE_VALUE; + aw_pa->bop_desc.disbale = AW_PID_2113_BOP_EN_DISABLE_VALUE; + + aw_pa->soft_rst.reg = AW882XX_SOFT_RESET_REG; + aw_pa->soft_rst.reg_value = AW882XX_SOFT_RESET_VALUE; + + usleep_range(AW_2000_US, AW_2000_US + 10); + aw_pa->ops.aw_i2c_write(aw_pa, AW_PID_2113_INIT_CHECK_REG, + AW_PID_2113_INIT_CHECK_VALUE); + usleep_range(AW_3000_US, AW_3000_US + 10); + + aw_pa->efcheck_desc.reg = AW_PID_2113_DBGCTRL_REG; + aw_pa->efcheck_desc.mask = AW_PID_2113_EF_DBMD_MASK; + aw_pa->efcheck_desc.and_val = AW_PID_2113_AND_VALUE; + aw_pa->efcheck_desc.or_val = AW_PID_2113_OR_VALUE; + + aw_pa->dither_desc.reg = AW_PID_2113_DBGCTRL_REG; + aw_pa->dither_desc.mask = AW_PID_2113_DITHER_MASK; + aw_pa->dither_desc.enable = AW_PID_2113_DITHER_ENABLE_VALUE; + aw_pa->dither_desc.disable = AW_PID_2113_DITHER_DISABLE_VALUE; + + aw_pa->noise_gate_desc.reg = AW_REG_NONE; + + aw_pa->auth_desc.reg_in = AW_PID_2113_TESTIN_REG; + aw_pa->auth_desc.reg_out = AW_PID_2113_TESTOUT_REG; + + aw_pa->psm_desc.reg = AW_REG_NONE; + aw_pa->mpd_desc.reg = AW_REG_NONE; + aw_pa->dsmzth_desc.reg = AW_REG_NONE; + + ret = aw882xx_device_probe(aw_pa); + + aw882xx->aw_pa = aw_pa; + return ret; +} + +/* [9 : 0]: -0.0940625DB*/ +static unsigned int aw_pid_2308_reg_val_to_db(unsigned int value) +{ + return value; +} + +/* [9 : 0]: -0.0940625DB*/ +static unsigned int aw_pid_2308_db_val_to_reg(unsigned int value) +{ + return value; +} + +static int aw_pid_2308_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + struct aw_volume_desc *vol_desc = &aw882xx->aw_pa->volume_desc; + + real_value = aw_pid_2308_db_val_to_reg(AW_GET_MIN_VALUE(value, vol_desc->mute_volume)); + + aw_dev_dbg(aw882xx->dev, "value:%d, min_val: %d, real_value: 0x%x", + value, AW_GET_MIN_VALUE(value, vol_desc->mute_volume), real_value); + + /* cal real value */ + aw882xx_i2c_read(aw882xx, AW_PID_2308_SYSCTRL2_REG, ®_value); + + /*[9 : 0] volume*/ + real_value = (real_value | (reg_value & 0xfc00)); + + /* write value */ + aw882xx_i2c_write(aw882xx, AW_PID_2308_SYSCTRL2_REG, real_value); + + return 0; +} + +static int aw_pid_2308_get_volume(struct aw_device *aw_dev, unsigned int *value) +{ + unsigned int reg_value = 0; + unsigned int real_value = 0; + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + /* read value */ + aw882xx_i2c_read(aw882xx, AW_PID_2308_SYSCTRL2_REG, ®_value); + + /* [9 : 0] volume */ + real_value = (reg_value & 0x03ff); + + real_value = aw_pid_2308_reg_val_to_db(real_value); + *value = real_value; + + return 0; +} + +static bool aw_pid_2308_check_rd_access(int reg) +{ + if (reg >= AW_PID_2308_REG_MAX) + return false; + + if (aw_pid_2308_reg_access[reg] & REG_RD_ACCESS) + return true; + else + return false; +} + +static bool aw_pid_2308_check_wr_access(int reg) +{ + if (reg >= AW_PID_2308_REG_MAX) + return false; + + if (aw_pid_2113_reg_access[reg] & REG_WR_ACCESS) + return true; + else + return false; +} + +static int aw_pid_2308_get_reg_num(void) +{ + return AW_PID_2308_REG_MAX; +} + +static unsigned int aw_pid_2308_get_irq_type(struct aw_device *aw_dev, + unsigned int value) +{ + unsigned int ret = INT_TYPE_NONE; + + /* UVL0 */ + if (value & (~AW_PID_2308_UVLI_MASK)) { + aw_dev_info(aw_dev->dev, "UVLO: occur"); + ret |= INT_TYPE_UVLO; + } + + /* BSTOCM */ + if (value & (~AW_PID_2308_BSTOCI_MASK)) { + aw_dev_info(aw_dev->dev, "BSTOCI: occur"); + ret |= INT_TYPE_BSTOC; + } + + /* OCDI */ + if (value & (~AW_PID_2308_OCDI_MASK)) { + aw_dev_info(aw_dev->dev, "OCDI: occur"); + ret |= INT_TYPE_OCDI; + } + + /* OTHI */ + if (value & (~AW_PID_2308_OTHI_MASK)) { + aw_dev_info(aw_dev->dev, "OTHI: occur"); + ret |= INT_TYPE_OTHI; + } + + return ret; + +} + +static int aw_pid_2308_dev_init(struct aw882xx *aw882xx) +{ + int ret = 0; + struct aw_device *aw_pa = aw882xx->aw_pa; + + /*call aw device init func*/ + memset(aw_pa->monitor_name, 0, AW_NAME_MAX); + memcpy(aw_pa->monitor_name, AW_PID_2308_MONITOR_FILE, strlen(AW_PID_2308_MONITOR_FILE)); + + aw_pa->prof_info.prof_desc = NULL; + aw_pa->prof_info.count = 0; + aw_pa->channel = 0; + aw_pa->bstcfg_enable = AW_BSTCFG_DISABLE; + aw_pa->bop_en = AW_BOP_DISABLE; + aw_pa->vol_step = AW_PID_2308_VOL_STEP; + + aw_pa->private_data = (void *)aw882xx; + aw_pa->dev = aw882xx->dev; + aw_pa->i2c = aw882xx->i2c; + + aw_pa->ops.aw_get_version = aw882xx_get_version; + aw_pa->ops.aw_get_dev_num = aw882xx_get_dev_num; + aw_pa->ops.aw_set_algo = aw882xx_dev_set_algo_en; + aw_pa->ops.aw_i2c_read = aw882xx_dev_i2c_read; + aw_pa->ops.aw_i2c_write = aw882xx_dev_i2c_write; + aw_pa->ops.aw_i2c_write_bits = aw882xx_dev_i2c_write_bits; + aw_pa->ops.aw_get_hw_volume = aw_pid_2308_get_volume; + aw_pa->ops.aw_set_hw_volume = aw_pid_2308_set_volume; + aw_pa->ops.aw_reg_val_to_db = aw_pid_2308_reg_val_to_db; + aw_pa->ops.aw_check_rd_access = aw_pid_2308_check_rd_access; + aw_pa->ops.aw_check_wr_access = aw_pid_2308_check_wr_access; + aw_pa->ops.aw_get_reg_num = aw_pid_2308_get_reg_num; + aw_pa->ops.aw_get_irq_type = aw_pid_2308_get_irq_type; + + aw_pa->int_desc.mask_reg = AW_PID_2308_SYSINTM_REG; + aw_pa->int_desc.mask_default = AW_PID_2308_SYSINTM_DEFAULT; + aw_pa->int_desc.int_mask = AW_PID_2308_SYSINTM_DEFAULT; + aw_pa->int_desc.st_reg = AW_PID_2308_SYSINT_REG; + + aw_pa->work_mode.reg = AW_PID_2308_SYSCTRL_REG; + aw_pa->work_mode.mask = AW_PID_2308_RCV_MODE_MASK; + aw_pa->work_mode.spk_val = AW_PID_2308_RCV_MODE_SPEAKER_VALUE; + aw_pa->work_mode.rcv_val = AW_PID_2308_RCV_MODE_RECEIVER_VALUE; + + aw_pa->pwd_desc.reg = AW_PID_2308_SYSCTRL_REG; + aw_pa->pwd_desc.mask = AW_PID_2308_PWDN_MASK; + aw_pa->pwd_desc.enable = AW_PID_2308_PWDN_POWER_DOWN_VALUE; + aw_pa->pwd_desc.disable = AW_PID_2308_PWDN_WORKING_VALUE; + + aw_pa->amppd_desc.reg = AW_PID_2308_SYSCTRL_REG; + aw_pa->amppd_desc.mask = AW_PID_2308_AMPPD_MASK; + aw_pa->amppd_desc.enable = AW_PID_2308_AMPPD_POWER_DOWN_VALUE; + aw_pa->amppd_desc.disable = AW_PID_2308_AMPPD_WORKING_VALUE; + + aw_pa->mute_desc.reg = AW_PID_2308_SYSCTRL_REG; + aw_pa->mute_desc.mask = AW_PID_2308_HMUTE_MASK; + aw_pa->mute_desc.enable = AW_PID_2308_HMUTE_ENABLE_VALUE; + aw_pa->mute_desc.disable = AW_PID_2308_HMUTE_DISABLE_VALUE; + + aw_pa->uls_hmute_desc.reg = AW_PID_2308_SYSCTRL_REG; + aw_pa->uls_hmute_desc.mask = AW_PID_2308_ULS_HMUTE_MASK; + aw_pa->uls_hmute_desc.enable = AW_PID_2308_ULS_HMUTE_MUTE_VALUE; + aw_pa->uls_hmute_desc.disable = AW_PID_2308_ULS_HMUTE_NORMAL_VALUE; + + aw_pa->txen_desc.reg = AW_PID_2308_SYSCTRL_REG; + aw_pa->txen_desc.mask = AW_PID_2308_I2STXEN_MASK; + aw_pa->txen_desc.enable = AW_PID_2308_I2STXEN_ENABLE_VALUE; + aw_pa->txen_desc.disable = AW_PID_2308_I2STXEN_DISABLE_VALUE; + + aw_pa->vcalb_desc.vcalb_reg = AW_REG_NONE; + aw_pa->vcalb_desc.icalk_reg = AW_REG_NONE; + aw_pa->vcalb_desc.vcalk_reg = AW_REG_NONE; + + aw_pa->spin_desc.rx_desc.reg = AW_PID_2308_I2SCTRL1_REG; + aw_pa->spin_desc.rx_desc.mask = AW_PID_2308_CHSEL_MASK; + aw_pa->spin_desc.rx_desc.left_val = AW_PID_2308_CHSEL_LEFT_VALUE; + aw_pa->spin_desc.rx_desc.right_val = AW_PID_2308_CHSEL_RIGHT_VALUE; + + aw_pa->sysst_desc.reg = AW_PID_2308_SYSST_REG; + aw_pa->sysst_desc.mask = AW_PID_2308_SYSST_CHECK_MASK; + aw_pa->sysst_desc.st_check = AW_PID_2308_NO_SWS_SYSST_CHECK; + aw_pa->sysst_desc.st_sws_check = AW_PID_2308_SWS_SYSST_CHECK; + aw_pa->sysst_desc.pll_check = AW_PID_2308_IIS_CHECK; + + aw_pa->cco_mux_desc.reg = AW_PID_2308_DBGCTRL_REG; + aw_pa->cco_mux_desc.mask = AW_PID_2308_CCO_MUX_MASK; + aw_pa->cco_mux_desc.divided_val = AW_PID_2308_CCO_MUX_DIVIDED_VALUE; + aw_pa->cco_mux_desc.bypass_val = AW_PID_2308_CCO_MUX_BYPASS_VALUE; + + aw_pa->voltage_desc.reg = AW_PID_2308_VBAT_REG; + aw_pa->voltage_desc.int_bit = AW_PID_2308_MONITOR_INT_10BIT; + aw_pa->voltage_desc.vbat_range = AW_PID_2308_MONITOR_VBAT_RANGE; + + aw_pa->temp_desc.reg = AW_PID_2308_TEMP_REG; + aw_pa->temp_desc.neg_mask = AW_PID_2308_MONITOR_TEMP_NEG_MASK; + aw_pa->temp_desc.sign_mask = AW_PID_2308_MONITOR_TEMP_SIGN_MASK; + + aw_pa->ipeak_desc.reg = AW_PID_2308_BSTCTRL2_REG; + aw_pa->ipeak_desc.mask = AW_PID_2308_BST_IPEAK_MASK; + + aw_pa->volume_desc.reg = AW_PID_2308_SYSCTRL2_REG; + aw_pa->volume_desc.mask = AW_PID_2308_VOL_MASK; + aw_pa->volume_desc.shift = AW_PID_2308_VOL_START_BIT; + aw_pa->volume_desc.mute_volume = AW_PID_2308_MUTE_VOL; + aw_pa->volume_desc.ctl_volume = AW_PID_2308_VOL_DEFAULT_VALUE; + + aw_pa->bop_desc.reg = AW_PID_2308_SYSCTRL_REG; + aw_pa->bop_desc.mask = AW_PID_2308_BOP_EN_MASK; + aw_pa->bop_desc.enable = AW_PID_2308_BOP_EN_ENABLE_VALUE; + aw_pa->bop_desc.disbale = AW_PID_2308_BOP_EN_DISABLE_VALUE; + + aw_pa->soft_rst.reg = AW882XX_SOFT_RESET_REG; + aw_pa->soft_rst.reg_value = AW882XX_SOFT_RESET_VALUE; + + aw_pa->efcheck_desc.reg = AW_REG_NONE; + + aw_pa->dither_desc.reg = AW_REG_NONE; + + aw_pa->auth_desc.reg_in = AW_PID_2308_TESTIN_REG; + aw_pa->auth_desc.reg_out = AW_PID_2308_TESTOUT_REG; + + aw_pa->noise_gate_desc.reg = AW_PID_2308_NGCTRL3_REG; + aw_pa->noise_gate_desc.mask = AW_PID_2308_NOISE_GATE_EN_MASK; + + aw_pa->psm_desc.reg = AW_PID_2308_SYSCTRL2_REG; + aw_pa->psm_desc.mask = AW_PID_2308_PSM_EN_MASK; + aw_pa->psm_desc.enable = AW_PID_2308_PSM_EN_ENABLE_VALUE; + aw_pa->psm_desc.disable = AW_PID_2308_PSM_EN_DISABLE_VALUE; + + aw_pa->mpd_desc.reg = AW_PID_2308_SYSCTRL2_REG; + aw_pa->mpd_desc.mask = AW_PID_2308_EN_MPD_MASK; + aw_pa->mpd_desc.enable = AW_PID_2308_EN_MPD_ENABLE_VALUE; + aw_pa->mpd_desc.disable = AW_PID_2308_EN_MPD_DISABLE_VALUE; + + aw_pa->dsmzth_desc.reg = AW_PID_2308_NGCTRL3_REG; + aw_pa->dsmzth_desc.mask = AW_PID_2308_DSMZTH_MASK; + aw_pa->dsmzth_desc.enable = AW_PID_2308_DSMZTH_21P33MS_VALUE; + aw_pa->dsmzth_desc.disable = AW_PID_2308_DSMZTH_NO_RESET_VALUE; + + ret = aw882xx_device_probe(aw_pa); + + aw882xx->aw_pa = aw_pa; + return ret; +} + +int aw882xx_init(struct aw882xx *aw882xx) +{ + switch (aw882xx->aw_pa->chip_id) { + case PID_1852_ID: + return aw_pid_1852_dev_init(aw882xx); + case PID_2013_ID: + return aw_pid_2013_dev_init(aw882xx); + case PID_2032_ID: + return aw_pid_2032_dev_init(aw882xx); + case PID_2055_ID: + return aw_pid_2055_dev_check(aw882xx); + case PID_2071_ID: + return aw_pid_2071_dev_init(aw882xx); + case PID_2113_ID: + return aw_pid_2113_dev_init(aw882xx); + case PID_2308_ID: + return aw_pid_2308_dev_init(aw882xx); + default: + aw_dev_err(aw882xx->dev, "unsupported chip id 0x%04x", aw882xx->aw_pa->chip_id); + break; + } + + return -EINVAL; +} + diff --git a/sound/soc/codecs/aw882xx/aw882xx_log.h b/sound/soc/codecs/aw882xx/aw882xx_log.h new file mode 100644 index 000000000000..cae62bf01683 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_log.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 + * aw882xx_log.h + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_LOG_H__ +#define __AW882XX_LOG_H__ + +/******************************************** + * print information control + *******************************************/ +#define aw_dev_err(dev, format, ...) \ + pr_err("[Awinic][%s]%s: " format "\n", dev_name(dev), __func__, ##__VA_ARGS__) +#define aw_dev_info(dev, format, ...) \ + pr_info("[Awinic][%s]%s: " format "\n", dev_name(dev), __func__, ##__VA_ARGS__) +#define aw_dev_dbg(dev, format, ...) \ + pr_debug("[Awinic][%s]%s: " format "\n", dev_name(dev), __func__, ##__VA_ARGS__) + +#define aw_pr_err(format, ...) \ + pr_err("[Awinic]%s: " format "\n", __func__, ##__VA_ARGS__) +#define aw_pr_info(format, ...) \ + pr_info("[Awinic]%s: " format "\n", __func__, ##__VA_ARGS__) +#define aw_pr_dbg(format, ...) \ + pr_debug("[Awinic]%s: " format "\n", __func__, ##__VA_ARGS__) + +#endif + diff --git a/sound/soc/codecs/aw882xx/aw882xx_monitor.c b/sound/soc/codecs/aw882xx/aw882xx_monitor.c new file mode 100644 index 000000000000..486c87214870 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_monitor.c @@ -0,0 +1,1431 @@ +// SPDX-License-Identifier: GPL-2.0 +/* aw882xx_monitor.c monitor_module + * + * Copyright (c) 2019 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "aw882xx.h" +#include "aw882xx_dsp.h" +#include "aw882xx_monitor.h" +#include "aw882xx_log.h" + + +/***************************************************** + * device monitor + *****************************************************/ +static int aw_get_hmute(struct aw_device *aw_dev) +{ + int ret; + unsigned int reg_val = 0; + struct aw_mute_desc *desc = &aw_dev->mute_desc; + + aw_dev_dbg(aw_dev->dev, "enter"); + + ret = aw_dev->ops.aw_i2c_read(aw_dev, desc->reg, ®_val); + if (ret < 0) + return ret; + + if (reg_val & (~desc->mask)) + ret = 1; + else + ret = 0; + + return ret; +} + +static int aw_monitor_get_data_form_system(struct aw_device *aw_dev, + int *data, int data_type) +{ + int ret; + char name[] = "battery"; + union power_supply_propval prop = { 0 }; + struct power_supply *psy = NULL; + + psy = power_supply_get_by_name(name); + if (psy) { + ret = power_supply_get_property(psy, data_type, &prop); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "get data failed"); + return -EINVAL; + } + *data = prop.intval; + aw_dev_dbg(aw_dev->dev, "data: %d", *data); + } else { + aw_dev_err(aw_dev->dev, "no struct power supply name : %s", name); + return -EINVAL; + } + return 0; + +} + +static int aw_monitor_get_voltage(struct aw_device *aw_dev, unsigned int *vol) +{ + int ret = -1; + uint16_t local_vol = 0; + struct aw_voltage_desc *desc = &aw_dev->voltage_desc; + + if (desc->reg == AW_REG_NONE) { + ret = aw_monitor_get_data_form_system(aw_dev, (int *)vol, POWER_SUPPLY_PROP_VOLTAGE_NOW); + if (ret) { + aw_dev_err(aw_dev->dev, "get voltage from system failed!"); + return ret; + } + *vol = (*vol) / 1000; + } else { + ret = aw_dev->ops.aw_i2c_read(aw_dev, desc->reg, vol); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "read voltage failed!"); + return ret; + } + local_vol = ((*vol) * desc->vbat_range) / desc->int_bit; + *vol = local_vol; + } + + aw_dev_info(aw_dev->dev, "chip voltage is %d", *vol); + + return 0; +} + +static int aw_monitor_get_temperature(struct aw_device *aw_dev, int *temp) +{ + int ret = -1; + unsigned int reg_val = 0; + uint16_t local_temp; + struct aw_temperature_desc *desc = &aw_dev->temp_desc; + + if (desc->reg == AW_REG_NONE) { + ret = aw_monitor_get_data_form_system(aw_dev, temp, POWER_SUPPLY_PROP_TEMP); + if (ret) { + aw_dev_err(aw_dev->dev, "get temperature from system failed!"); + return ret; + } + *temp = (*temp) / 10; + } else { + ret = aw_dev->ops.aw_i2c_read(aw_dev, desc->reg, ®_val); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "get temperature failed!"); + return ret; + } + aw_dev_info(aw_dev->dev, "reg val is 0x%04x", reg_val); + local_temp = reg_val; + if (local_temp & (~desc->sign_mask)) + local_temp = local_temp | desc->neg_mask; + + *temp = (int16_t)local_temp; + } + + aw_dev_info(aw_dev->dev, "chip temperature = %d", *temp); + return 0; +} + +static int aw_monitor_get_temp_and_vol(struct aw_device *aw_dev) +{ + int ret = -1; + struct aw_monitor_desc *monitor = &aw_dev->monitor_desc; + unsigned int voltage = 0; + int current_temp = 0; + +#ifdef AW_DEBUG + if (monitor->test_vol == 0) { + ret = aw_monitor_get_voltage(aw_dev, &voltage); + if (ret < 0) + return ret; + } else { + voltage = monitor->test_vol; + } + + if (monitor->test_temp == 0) { + ret = aw_monitor_get_temperature(aw_dev, ¤t_temp); + if (ret) + return ret; + } else { + current_temp = monitor->test_temp; + } +#else + ret = aw_monitor_get_voltage(aw_dev, &voltage); + if (ret < 0) + return ret; + + ret = aw_monitor_get_temperature(aw_dev, ¤t_temp); + if (ret < 0) + return ret; +#endif + + monitor->vol_trace.sum_val += voltage; + monitor->temp_trace.sum_val += current_temp; + monitor->samp_count++; + + return 0; +} + +static int aw_monitor_first_get_data_form_table(struct aw_device *aw_dev, + struct aw_table_info table_info, + struct aw_monitor_trace *data_trace) +{ + int i; + + if (table_info.aw_table == NULL) { + aw_dev_err(aw_dev->dev, "table_info.aw_table is null"); + return -EINVAL; + } + + for (i = 0; i < table_info.table_num; i++) { + if (data_trace->sum_val >= table_info.aw_table[i].min_val) { + memcpy(&data_trace->aw_table, &table_info.aw_table[i], + sizeof(struct aw_table)); + break; + } + } + return 0; +} + +static int aw_monitor_trace_data_from_table(struct aw_device *aw_dev, + struct aw_table_info table_info, + struct aw_monitor_trace *data_trace) +{ + int i; + + if (table_info.aw_table == NULL) { + aw_dev_err(aw_dev->dev, "table_info.aw_table is null"); + return -EINVAL; + } + + for (i = 0; i < table_info.table_num; i++) { + if (data_trace->sum_val >= table_info.aw_table[i].min_val && + data_trace->sum_val <= table_info.aw_table[i].max_val) { + memcpy(&data_trace->aw_table, &table_info.aw_table[i], + sizeof(struct aw_table)); + break; + } + } + + return 0; +} + +static int aw_monitor_get_data_from_table(struct aw_device *aw_dev, + struct aw_table_info table_info, + struct aw_monitor_trace *data_trace, + uint32_t aplha) +{ + struct aw_monitor_desc *monitor = &aw_dev->monitor_desc; + + if (monitor->first_entry == AW_FIRST_ENTRY) { + return aw_monitor_first_get_data_form_table(aw_dev, + table_info, data_trace); + } else { + data_trace->sum_val = data_trace->sum_val / monitor->samp_count; + data_trace->sum_val = ((int32_t)aplha * data_trace->sum_val + + (1000 - (int32_t)aplha) * data_trace->pre_val) / 1000; + return aw_monitor_trace_data_from_table(aw_dev, + table_info, data_trace); + } + + return 0; +} + +static int aw_monitor_get_data(struct aw_device *aw_dev) +{ + int ret; + struct aw_monitor_desc *monitor = &aw_dev->monitor_desc; + struct aw_monitor_cfg *monitor_cfg = &monitor->monitor_cfg; + struct aw_monitor_trace *vol_trace = &monitor->vol_trace; + struct aw_monitor_trace *temp_trace = &monitor->temp_trace; + + if (monitor_cfg->vol_switch) { + ret = aw_monitor_get_data_from_table(aw_dev, + monitor_cfg->vol_info, vol_trace, + monitor_cfg->vol_aplha); + if (ret < 0) + return ret; + } else { + vol_trace->aw_table.ipeak = IPEAK_NONE; + vol_trace->aw_table.gain = GAIN_NONE; + vol_trace->aw_table.vmax = VMAX_NONE; + } + + if (monitor_cfg->temp_switch) { + ret = aw_monitor_get_data_from_table(aw_dev, + monitor_cfg->temp_info, temp_trace, + monitor_cfg->temp_aplha); + if (ret < 0) + return ret; + } else { + temp_trace->aw_table.ipeak = IPEAK_NONE; + temp_trace->aw_table.gain = GAIN_NONE; + temp_trace->aw_table.vmax = VMAX_NONE; + } + + aw_dev_dbg(aw_dev->dev, "filter_vol:%d, vol: ipeak = 0x%x, gain = 0x%x, vmax = 0x%x", + monitor->vol_trace.sum_val, vol_trace->aw_table.ipeak, + vol_trace->aw_table.gain, vol_trace->aw_table.vmax); + + aw_dev_dbg(aw_dev->dev, "filter_temp:%d, temp: ipeak = 0x%x, gain = 0x%x, vmax = 0x%x", + monitor->temp_trace.sum_val, temp_trace->aw_table.ipeak, + temp_trace->aw_table.gain, temp_trace->aw_table.vmax); + return 0; +} + +static void aw_monitor_get_cfg(struct aw_device *aw_dev, + struct aw_table *set_table) +{ + struct aw_monitor_desc *monitor = &aw_dev->monitor_desc; + struct aw_table *temp_data = &monitor->temp_trace.aw_table; + struct aw_table *vol_data = &monitor->vol_trace.aw_table; + + if (temp_data->ipeak == IPEAK_NONE && vol_data->ipeak == IPEAK_NONE) { + memcpy(set_table, temp_data, sizeof(struct aw_table)); + } else if (temp_data->ipeak == IPEAK_NONE) { + memcpy(set_table, vol_data, sizeof(struct aw_table)); + } else if (vol_data->ipeak == IPEAK_NONE) { + memcpy(set_table, temp_data, sizeof(struct aw_table)); + } else { + if (monitor->monitor_cfg.logic_switch == AW_MON_LOGIC_OR) { + set_table->ipeak = (temp_data->ipeak < vol_data->ipeak ? + temp_data->ipeak : vol_data->ipeak); + set_table->gain = (temp_data->gain < vol_data->gain ? + vol_data->gain : temp_data->gain); + set_table->vmax = (temp_data->vmax < vol_data->vmax ? + vol_data->vmax : temp_data->vmax); + } else { + set_table->ipeak = (temp_data->ipeak < vol_data->ipeak ? + vol_data->ipeak : temp_data->ipeak); + set_table->gain = (temp_data->gain < vol_data->gain ? + temp_data->gain : vol_data->gain); + set_table->vmax = (temp_data->vmax < vol_data->vmax ? + temp_data->vmax : vol_data->vmax); + } + } +} + +static void aw_monitor_set_ipeak(struct aw_device *aw_dev, + uint16_t ipeak) +{ + int ret; + struct aw_monitor_cfg *monitor_cfg = &aw_dev->monitor_desc.monitor_cfg; + unsigned int reg_val = 0; + unsigned int read_reg_val; + struct aw_ipeak_desc *desc = &aw_dev->ipeak_desc; + + if (ipeak == IPEAK_NONE || (!monitor_cfg->ipeak_switch)) + return; + + ret = aw_dev->ops.aw_i2c_read(aw_dev, desc->reg, ®_val); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "read ipeak failed"); + return; + } + + read_reg_val = reg_val; + + read_reg_val &= (~desc->mask); + + if (read_reg_val == ipeak) { + aw_dev_dbg(aw_dev->dev, "ipeak = 0x%x, no change", + read_reg_val); + return; + } + + reg_val &= desc->mask; + read_reg_val = ipeak; + reg_val |= read_reg_val; + + ret = aw_dev->ops.aw_i2c_write(aw_dev, desc->reg, reg_val); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "write ipeak failed"); + return; + } + aw_dev_info(aw_dev->dev, "set reg val = 0x%x, ipeak = 0x%x", + reg_val, ipeak); + +} + +static void aw_monitor_set_gain(struct aw_device *aw_dev, uint16_t gain) +{ + int compared_vol = 0; + struct aw_monitor_cfg *monitor_cfg = &aw_dev->monitor_desc.monitor_cfg; + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + + if (gain == GAIN_NONE || (!monitor_cfg->gain_switch)) + return; + + vol_desc->monitor_volume = aw_dev->ops.aw_reg_val_to_db(gain); + + compared_vol = AW_GET_MAX_VALUE(vol_desc->ctl_volume, + vol_desc->monitor_volume); + + aw882xx_dev_set_volume(aw_dev, compared_vol); +} + +static void aw_monitor_set_vmax(struct aw_device *aw_dev, + uint32_t vmax) +{ + int ret; + struct aw_monitor_cfg *monitor_cfg = &aw_dev->monitor_desc.monitor_cfg; + + if (vmax == VMAX_NONE || (!monitor_cfg->vmax_switch)) + return; + + if ((vmax == aw_dev->monitor_desc.pre_vmax) && + (aw_dev->monitor_desc.first_entry != AW_FIRST_ENTRY)) { + aw_dev_dbg(aw_dev->dev, "vmax = 0x%x, no change", vmax); + return; + } + + aw_dev->monitor_desc.pre_vmax = vmax; + + if (aw_dev->monitor_desc.monitor_mode == AW_MON_KERNEL_MODE) { + ret = aw882xx_dsp_write_vmax(aw_dev, (char *)&vmax, sizeof(uint32_t)); + if (ret) + return; + + aw_dev_dbg(aw_dev->dev, "set vmax = 0x%x", vmax); + } +} + +static int aw_monitor_work(struct aw_device *aw_dev) +{ + int ret = -1; + struct aw_monitor_desc *monitor = &aw_dev->monitor_desc; + struct aw_monitor_cfg *monitor_cfg = &monitor->monitor_cfg; + struct aw_table set_table; + + if (aw882xx_cali_svc_get_cali_status()) { + aw_dev_info(aw_dev->dev, "done nothing during calibration"); + return 0; + } + + ret = aw_monitor_get_temp_and_vol(aw_dev); + if (ret < 0) + return ret; + + if (monitor->samp_count < monitor_cfg->monitor_count && + (monitor->first_entry == AW_NOT_FIRST_ENTRY)) + return 0; + + ret = aw_monitor_get_data(aw_dev); + if (ret < 0) + return ret; + + aw_monitor_get_cfg(aw_dev, &set_table); + + aw_dev_dbg(aw_dev->dev, "set_ipeak = 0x%x, set_gain = 0x%x, set_vmax = 0x%x", + set_table.ipeak, set_table.gain, set_table.vmax); + + aw_monitor_set_ipeak(aw_dev, set_table.ipeak); + + aw_monitor_set_gain(aw_dev, set_table.gain); + + aw_monitor_set_vmax(aw_dev, set_table.vmax); + + monitor->samp_count = 0; + monitor->temp_trace.pre_val = monitor->temp_trace.sum_val; + monitor->temp_trace.sum_val = 0; + + monitor->vol_trace.pre_val = monitor->vol_trace.sum_val; + monitor->vol_trace.sum_val = 0; + + if (monitor->first_entry == AW_FIRST_ENTRY) + monitor->first_entry = AW_NOT_FIRST_ENTRY; + + return 0; +} + +static void aw_monitor_work_func(struct work_struct *work) +{ + struct aw_device *aw_dev = container_of(work, + struct aw_device, monitor_desc.delay_work.work); + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + struct aw_monitor_cfg *monitor_cfg = &aw_dev->monitor_desc.monitor_cfg; + struct aw_monitor_desc *monitor = &aw_dev->monitor_desc; + + aw_dev_dbg(aw_dev->dev, "monitor_start:%d, monitor_status:%d, monitor_switch:%d", + aw_dev->monitor_start, monitor_cfg->monitor_status, + monitor_cfg->monitor_switch); + + if ((monitor_cfg->monitor_status == AW_MON_CFG_OK) && (aw_dev->monitor_start) && + monitor_cfg->monitor_switch) { + if (!aw_get_hmute(aw_dev)) { + aw_monitor_work(aw_dev); + if (monitor->monitor_mode == AW_MON_KERNEL_MODE) { + queue_delayed_work(aw882xx->work_queue, + &monitor->delay_work, + msecs_to_jiffies(monitor_cfg->monitor_time)); + } + } + } +} + +static void aw_monitor_check_bop_status(struct aw_device *aw_dev) +{ + struct aw_bop_desc *bop_desc = &aw_dev->bop_desc; + unsigned int reg_val = 0; + + aw_dev_dbg(aw_dev->dev, "enter"); + + if (aw_dev->bop_desc.reg == AW_REG_NONE) + return; + + aw_dev->ops.aw_i2c_read(aw_dev, bop_desc->reg, ®_val); + reg_val = (uint16_t)reg_val & (~bop_desc->mask); + if (reg_val == bop_desc->enable) + aw_dev->bop_en = AW_BOP_ENABLE; + else + aw_dev->bop_en = AW_BOP_DISABLE; + + aw_dev_dbg(aw_dev->dev, "check done! bop status is %d", aw_dev->bop_en); +} + +void aw882xx_monitor_start(struct aw_monitor_desc *monitor_desc) +{ + struct aw_device *aw_dev = container_of(monitor_desc, + struct aw_device, monitor_desc); + struct aw882xx *aw882xx = (struct aw882xx *)aw_dev->private_data; + + aw_dev_info(aw_dev->dev, "enter"); + + monitor_desc->first_entry = AW_FIRST_ENTRY; + monitor_desc->samp_count = 0; + monitor_desc->vol_trace.sum_val = 0; + monitor_desc->temp_trace.sum_val = 0; + + aw_monitor_check_bop_status(aw_dev); + + if (aw_dev->bop_en == AW_BOP_ENABLE) { + aw_dev_info(aw_dev->dev, "bop status is enable, monitor can't start"); + return; + } + + monitor_desc->mon_start_flag = true; + if (monitor_desc->monitor_mode == AW_MON_KERNEL_MODE) { + queue_delayed_work(aw882xx->work_queue, + &monitor_desc->delay_work, 0); + } +} + +int aw882xx_monitor_stop(struct aw_monitor_desc *monitor_desc) +{ + struct aw_device *aw_dev = container_of(monitor_desc, + struct aw_device, monitor_desc); + + aw_dev_info(aw_dev->dev, "enter"); + aw_dev->volume_desc.monitor_volume = 0; + monitor_desc->mon_start_flag = false; + + if (monitor_desc->monitor_mode == AW_MON_KERNEL_MODE) + cancel_delayed_work_sync(&monitor_desc->delay_work); + + + return 0; +} + +void aw882xx_monitor_hal_work(struct aw_monitor_desc *monitor_desc, uint32_t *vmax) +{ + struct aw_device *aw_dev = container_of(monitor_desc, + struct aw_device, monitor_desc); + + if (monitor_desc->mon_start_flag) { + aw_monitor_work_func(&monitor_desc->delay_work.work); + *vmax = aw_dev->monitor_desc.pre_vmax; + } else { + *vmax = VMAX_NONE; + } +} + +void aw882xx_monitor_hal_get_time(struct aw_monitor_desc *monitor_desc, uint32_t *time) +{ + struct aw_device *aw_dev = container_of(monitor_desc, + struct aw_device, monitor_desc); + struct aw_monitor_cfg *monitor_cfg = &aw_dev->monitor_desc.monitor_cfg; + + *time = monitor_cfg->monitor_time; +} + + +/***************************************************** + * load monitor config + *****************************************************/ +static int aw_monitor_param_check_sum(struct aw_device *aw_dev, + uint8_t *data, uint32_t data_len) +{ + int i, check_sum = 0; + struct aw_monitor_hdr *monitor_hdr = + (struct aw_monitor_hdr *)data; + + if (data_len < sizeof(struct aw_monitor_hdr)) { + aw_dev_err(aw_dev->dev, "data size smaller than hdr , please check monitor bin"); + return -ENOMEM; + } + + for (i = 4; i < data_len; i++) + check_sum += (uint8_t)data[i]; + + if (monitor_hdr->check_sum != check_sum) { + aw_dev_err(aw_dev->dev, "check_sum[%d] is not equal to actual check_sum[%d]", + monitor_hdr->check_sum, check_sum); + return -ENOMEM; + } + + return 0; +} + +static int aw_monitor_check_fw(struct aw_device *aw_dev, + uint8_t *data, uint32_t data_len) +{ + struct aw_monitor_hdr *monitor_hdr = + (struct aw_monitor_hdr *)data; + int temp_size, vol_size; + + if (data_len < sizeof(struct aw_monitor_hdr)) { + aw_dev_err(aw_dev->dev, "params size[%d] < struct aw_monitor_hdr size[%d]!", + data_len, (int)sizeof(struct aw_monitor_hdr)); + return -ENOMEM; + } + + if (monitor_hdr->temp_offset > data_len) { + aw_dev_err(aw_dev->dev, "temp_offset[%d] overflow file size[%d]!", + monitor_hdr->temp_offset, data_len); + return -ENOMEM; + } + + if (monitor_hdr->vol_offset > data_len) { + aw_dev_err(aw_dev->dev, "vol_offset[%d] overflow file size[%d]!", + monitor_hdr->vol_offset, data_len); + return -ENOMEM; + } + + temp_size = monitor_hdr->temp_num * monitor_hdr->single_temp_size; + if (temp_size > data_len) { + aw_dev_err(aw_dev->dev, "temp_size:[%d] overflow file size[%d]!", + temp_size, data_len); + return -ENOMEM; + } + + vol_size = monitor_hdr->vol_num * monitor_hdr->single_vol_size; + if (vol_size > data_len) { + aw_dev_err(aw_dev->dev, "vol_size:[%d] overflow file size[%d]!", + vol_size, data_len); + return -ENOMEM; + } + + return 0; +} + +static int aw_monitor_check_fw_v_0_1_1(struct aw_device *aw_dev, + uint8_t *data, uint32_t data_len) +{ + struct aw_monitor_hdr_v_0_1_1 *monitor_hdr = + (struct aw_monitor_hdr_v_0_1_1 *)data; + int temp_size, vol_size; + + if (data_len < sizeof(struct aw_monitor_hdr_v_0_1_1)) { + aw_dev_err(aw_dev->dev, "params size[%d] < struct aw_monitor_hdr size[%d]!", + data_len, (int)sizeof(struct aw_monitor_hdr_v_0_1_1)); + return -ENOMEM; + } + + if (monitor_hdr->temp_offset > data_len) { + aw_dev_err(aw_dev->dev, "temp_offset[%d] overflow file size[%d]!", + monitor_hdr->temp_offset, data_len); + return -ENOMEM; + } + + if (monitor_hdr->vol_offset > data_len) { + aw_dev_err(aw_dev->dev, "vol_offset[%d] overflow file size[%d]!", + monitor_hdr->vol_offset, data_len); + return -ENOMEM; + } + + temp_size = monitor_hdr->temp_num * monitor_hdr->single_temp_size; + if (temp_size > data_len) { + aw_dev_err(aw_dev->dev, "temp_size:[%d] overflow file size[%d]!", + temp_size, data_len); + return -ENOMEM; + } + + vol_size = monitor_hdr->vol_num * monitor_hdr->single_vol_size; + if (vol_size > data_len) { + aw_dev_err(aw_dev->dev, "vol_size:[%d] overflow file size[%d]!", + vol_size, data_len); + return -ENOMEM; + } + + return 0; +} + +static int aw_monitor_check_fw_v_0_1_2(struct aw_device *aw_dev, + uint8_t *data, uint32_t data_len) +{ + struct aw_monitor_hdr_v_0_1_2 *monitor_hdr = + (struct aw_monitor_hdr_v_0_1_2 *)data; + int temp_size, vol_size; + + if (data_len < sizeof(struct aw_monitor_hdr_v_0_1_2)) { + aw_dev_err(aw_dev->dev, "params size[%d] < struct aw_monitor_hdr size[%d]!", + data_len, (int)sizeof(struct aw_monitor_hdr_v_0_1_2)); + return -ENOMEM; + } + + if (monitor_hdr->temp_offset > data_len) { + aw_dev_err(aw_dev->dev, "temp_offset[%d] overflow file size[%d]!", + monitor_hdr->temp_offset, data_len); + return -ENOMEM; + } + + if (monitor_hdr->vol_offset > data_len) { + aw_dev_err(aw_dev->dev, "vol_offset[%d] overflow file size[%d]!", + monitor_hdr->vol_offset, data_len); + return -ENOMEM; + } + + temp_size = monitor_hdr->temp_num * monitor_hdr->single_temp_size; + if (temp_size > data_len) { + aw_dev_err(aw_dev->dev, "temp_size:[%d] overflow file size[%d]!", + temp_size, data_len); + return -ENOMEM; + } + + vol_size = monitor_hdr->vol_num * monitor_hdr->single_vol_size; + if (vol_size > data_len) { + aw_dev_err(aw_dev->dev, "vol_size:[%d] overflow file size[%d]!", + vol_size, data_len); + return -ENOMEM; + } + + return 0; +} + +static void aw_monitor_parse_hdr(struct aw_device *aw_dev, uint8_t *data) +{ + struct aw_monitor_hdr *monitor_hdr = + (struct aw_monitor_hdr *)data; + struct aw_monitor_cfg *monitor_cfg = &aw_dev->monitor_desc.monitor_cfg; + + monitor_cfg->monitor_switch = monitor_hdr->monitor_switch; + monitor_cfg->monitor_time = monitor_hdr->monitor_time; + monitor_cfg->monitor_count = monitor_hdr->monitor_count; + monitor_cfg->ipeak_switch = monitor_hdr->ipeak_switch; + monitor_cfg->gain_switch = monitor_hdr->gain_switch; + monitor_cfg->vmax_switch = monitor_hdr->vmax_switch; + monitor_cfg->temp_switch = monitor_hdr->temp_switch; + monitor_cfg->temp_aplha = monitor_hdr->temp_aplha; + monitor_cfg->vol_switch = monitor_hdr->vol_switch; + monitor_cfg->vol_aplha = monitor_hdr->vol_aplha; + + aw_dev_info(aw_dev->dev, "chip name:%s", + monitor_hdr->chip_type); + aw_dev_info(aw_dev->dev, "ui ver:0x%x", + monitor_hdr->ui_ver); + + aw_dev_info(aw_dev->dev, "monitor_switch:%d, monitor_time:%d (ms), monitor_count:%d", + monitor_cfg->monitor_switch, monitor_cfg->monitor_time, + monitor_cfg->monitor_count); + + aw_dev_info(aw_dev->dev, "ipeak_switch:%d, gain_switch:%d, vmax_switch:%d", + monitor_cfg->ipeak_switch, monitor_cfg->gain_switch, + monitor_cfg->vmax_switch); + + aw_dev_info(aw_dev->dev, "temp_switch:%d, temp_aplha:%d, vol_switch:%d, vol_aplha:%d", + monitor_cfg->temp_switch, monitor_cfg->temp_aplha, + monitor_cfg->vol_switch, monitor_cfg->vol_aplha); +} + +static void aw_monitor_parse_hdr_v_0_1_1(struct aw_device *aw_dev, uint8_t *data) +{ + struct aw_monitor_hdr_v_0_1_1 *monitor_hdr = + (struct aw_monitor_hdr_v_0_1_1 *)data; + struct aw_monitor_cfg *monitor_cfg = &aw_dev->monitor_desc.monitor_cfg; + + monitor_cfg->monitor_switch = (monitor_hdr->enable_flag >> MONITOR_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->monitor_time = monitor_hdr->monitor_time; + monitor_cfg->monitor_count = monitor_hdr->monitor_count; + monitor_cfg->ipeak_switch = (monitor_hdr->enable_flag >> MONITOR_IPEAK_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->logic_switch = (monitor_hdr->enable_flag >> MONITOR_LOGIC_BIT) & MONITOR_EN_MASK; + monitor_cfg->gain_switch = (monitor_hdr->enable_flag >> MONITOR_GAIN_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->vmax_switch = (monitor_hdr->enable_flag >> MONITOR_VMAX_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->temp_switch = (monitor_hdr->enable_flag >> MONITOR_TEMP_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->temp_aplha = monitor_hdr->temp_aplha; + monitor_cfg->vol_switch = (monitor_hdr->enable_flag >> MONITOR_VOL_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->vol_aplha = monitor_hdr->vol_aplha; + + aw_dev_info(aw_dev->dev, "chip name:%s", + monitor_hdr->chip_type); + aw_dev_info(aw_dev->dev, "ui ver:0x%x", + monitor_hdr->ui_ver); + + aw_dev_info(aw_dev->dev, "monitor_switch:%d, monitor_time:%d (ms), monitor_count:%d", + monitor_cfg->monitor_switch, monitor_cfg->monitor_time, + monitor_cfg->monitor_count); + + aw_dev_info(aw_dev->dev, "logic_switch:%d, ipeak_switch:%d, gain_switch:%d, vmax_switch:%d", + monitor_cfg->logic_switch, monitor_cfg->ipeak_switch, + monitor_cfg->gain_switch, monitor_cfg->vmax_switch); + + aw_dev_info(aw_dev->dev, "temp_switch:%d, temp_aplha:%d, vol_switch:%d, vol_aplha:%d", + monitor_cfg->temp_switch, monitor_cfg->temp_aplha, + monitor_cfg->vol_switch, monitor_cfg->vol_aplha); +} + +static void aw_monitor_parse_hdr_v_0_1_2(struct aw_device *aw_dev, uint8_t *data) +{ + struct aw_monitor_hdr_v_0_1_2 *monitor_hdr = + (struct aw_monitor_hdr_v_0_1_2 *)data; + struct aw_monitor_cfg *monitor_cfg = &aw_dev->monitor_desc.monitor_cfg; + + monitor_cfg->monitor_switch = (monitor_hdr->enable_flag >> MONITOR_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->monitor_time = monitor_hdr->monitor_time; + monitor_cfg->monitor_count = monitor_hdr->monitor_count; + monitor_cfg->ipeak_switch = (monitor_hdr->enable_flag >> MONITOR_IPEAK_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->logic_switch = (monitor_hdr->enable_flag >> MONITOR_LOGIC_BIT) & MONITOR_EN_MASK; + monitor_cfg->gain_switch = (monitor_hdr->enable_flag >> MONITOR_GAIN_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->vmax_switch = (monitor_hdr->enable_flag >> MONITOR_VMAX_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->temp_switch = (monitor_hdr->enable_flag >> MONITOR_TEMP_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->temp_aplha = monitor_hdr->temp_aplha; + monitor_cfg->vol_switch = (monitor_hdr->enable_flag >> MONITOR_VOL_EN_BIT) & MONITOR_EN_MASK; + monitor_cfg->vol_aplha = monitor_hdr->vol_aplha; + monitor_cfg->temp_source = + (monitor_hdr->enable_flag >> MONITOR_TEMPERATURE_SOURCE_BIT) & MONITOR_EN_MASK; + monitor_cfg->vol_source = + (monitor_hdr->enable_flag >> MONITOR_VOLTAGE_SOURCE_BIT) & MONITOR_EN_MASK; + monitor_cfg->vol_mode = + (monitor_hdr->enable_flag >> MONITOR_VOLTAGE_MODE_BIT) & MONITOR_EN_MASK; + + aw_dev_info(aw_dev->dev, "chip name:%s", + monitor_hdr->chip_type); + aw_dev_info(aw_dev->dev, "ui ver:0x%x", + monitor_hdr->ui_ver); + + aw_dev_info(aw_dev->dev, "voltage mode:%d, voltage source:%d , temperature source:%d", + monitor_cfg->vol_mode, monitor_cfg->vol_source, + monitor_cfg->temp_source); + + aw_dev_info(aw_dev->dev, "monitor_switch:%d, monitor_time:%d (ms), monitor_count:%d", + monitor_cfg->monitor_switch, monitor_cfg->monitor_time, + monitor_cfg->monitor_count); + + aw_dev_info(aw_dev->dev, "logic_switch:%d, ipeak_switch:%d, gain_switch:%d, vmax_switch:%d", + monitor_cfg->logic_switch, monitor_cfg->ipeak_switch, + monitor_cfg->gain_switch, monitor_cfg->vmax_switch); + + aw_dev_info(aw_dev->dev, "temp_switch:%d, temp_aplha:%d, vol_switch:%d, vol_aplha:%d", + monitor_cfg->temp_switch, monitor_cfg->temp_aplha, + monitor_cfg->vol_switch, monitor_cfg->vol_aplha); +} + +static void aw_monitor_write_data_to_table(struct aw_device *aw_dev, + struct aw_table_info *table_info, const char *offset_ptr) +{ + int i; + + for (i = 0; i < table_info->table_num * AW_TABLE_SIZE; i += AW_TABLE_SIZE) { + table_info->aw_table[i / AW_TABLE_SIZE].min_val = + AW_GET_16_DATA(offset_ptr[1 + i], offset_ptr[i]); + table_info->aw_table[i / AW_TABLE_SIZE].max_val = + AW_GET_16_DATA(offset_ptr[3 + i], offset_ptr[2 + i]); + table_info->aw_table[i / AW_TABLE_SIZE].ipeak = + AW_GET_16_DATA(offset_ptr[5 + i], offset_ptr[4 + i]); + table_info->aw_table[i / AW_TABLE_SIZE].gain = + AW_GET_16_DATA(offset_ptr[7 + i], offset_ptr[6 + i]); + table_info->aw_table[i / AW_TABLE_SIZE].vmax = + AW_GET_32_DATA(offset_ptr[11 + i], offset_ptr[10 + i], + offset_ptr[9 + i], offset_ptr[8 + i]); + } + + for (i = 0; i < table_info->table_num; i++) + aw_dev_info(aw_dev->dev, + "min_val:%d, max_val:%d, ipeak:0x%x, gain:0x%x, vmax:0x%x", + table_info->aw_table[i].min_val, + table_info->aw_table[i].max_val, + table_info->aw_table[i].ipeak, + table_info->aw_table[i].gain, + table_info->aw_table[i].vmax); + +} + + +static int aw_monitor_parse_temp_data(struct aw_device *aw_dev, uint8_t *data) +{ + struct aw_monitor_hdr *monitor_hdr = + (struct aw_monitor_hdr *)data; + struct aw_table_info *temp_info = + &aw_dev->monitor_desc.monitor_cfg.temp_info; + + aw_dev_info(aw_dev->dev, "===parse temp start ==="); + + if (temp_info->aw_table != NULL) { + devm_kfree(aw_dev->dev, temp_info->aw_table); + temp_info->aw_table = NULL; + } + + temp_info->aw_table = devm_kzalloc(aw_dev->dev, + (monitor_hdr->temp_num * AW_TABLE_SIZE), + GFP_KERNEL); + if (temp_info->aw_table == NULL) + return -ENOMEM; + + temp_info->table_num = monitor_hdr->temp_num; + aw_monitor_write_data_to_table(aw_dev, temp_info, + &data[monitor_hdr->temp_offset]); + aw_dev_info(aw_dev->dev, "===parse temp end ==="); + return 0; +} + +static int aw_monitor_parse_temp_data_v_0_1_1(struct aw_device *aw_dev, uint8_t *data) +{ + struct aw_monitor_hdr_v_0_1_1 *monitor_hdr = + (struct aw_monitor_hdr_v_0_1_1 *)data; + struct aw_table_info *temp_info = + &aw_dev->monitor_desc.monitor_cfg.temp_info; + + aw_dev_info(aw_dev->dev, "===parse temp start ==="); + + if (temp_info->aw_table != NULL) { + devm_kfree(aw_dev->dev, temp_info->aw_table); + temp_info->aw_table = NULL; + } + + temp_info->aw_table = devm_kzalloc(aw_dev->dev, + (monitor_hdr->temp_num * AW_TABLE_SIZE), + GFP_KERNEL); + if (temp_info->aw_table == NULL) + return -ENOMEM; + + temp_info->table_num = monitor_hdr->temp_num; + aw_monitor_write_data_to_table(aw_dev, temp_info, + &data[monitor_hdr->temp_offset]); + aw_dev_info(aw_dev->dev, "===parse temp end ==="); + return 0; +} + +static int aw_monitor_parse_temp_data_v_0_1_2(struct aw_device *aw_dev, uint8_t *data) +{ + struct aw_monitor_hdr_v_0_1_2 *monitor_hdr = + (struct aw_monitor_hdr_v_0_1_2 *)data; + struct aw_table_info *temp_info = + &aw_dev->monitor_desc.monitor_cfg.temp_info; + + aw_dev_info(aw_dev->dev, "===parse temp start ==="); + + if (temp_info->aw_table != NULL) { + devm_kfree(aw_dev->dev, temp_info->aw_table); + temp_info->aw_table = NULL; + } + + temp_info->aw_table = devm_kzalloc(aw_dev->dev, + (monitor_hdr->temp_num * AW_TABLE_SIZE), + GFP_KERNEL); + if (temp_info->aw_table == NULL) + return -ENOMEM; + + temp_info->table_num = monitor_hdr->temp_num; + aw_monitor_write_data_to_table(aw_dev, temp_info, + &data[monitor_hdr->temp_offset]); + aw_dev_info(aw_dev->dev, "===parse temp end ==="); + return 0; +} + +static int aw_monitor_parse_vol_data(struct aw_device *aw_dev, uint8_t *data) +{ + struct aw_monitor_hdr *monitor_hdr = + (struct aw_monitor_hdr *)data; + struct aw_table_info *vol_info = + &aw_dev->monitor_desc.monitor_cfg.vol_info; + + aw_dev_info(aw_dev->dev, "===parse vol start ==="); + if (vol_info->aw_table != NULL) { + devm_kfree(aw_dev->dev, vol_info->aw_table); + vol_info->aw_table = NULL; + } + + vol_info->aw_table = devm_kzalloc(aw_dev->dev, + (monitor_hdr->vol_num * AW_TABLE_SIZE), + GFP_KERNEL); + if (vol_info->aw_table == NULL) + return -ENOMEM; + + vol_info->table_num = monitor_hdr->vol_num; + aw_monitor_write_data_to_table(aw_dev, vol_info, + &data[monitor_hdr->vol_offset]); + aw_dev_info(aw_dev->dev, "===parse vol end ==="); + return 0; +} + +static int aw_monitor_parse_vol_data_v_0_1_1(struct aw_device *aw_dev, uint8_t *data) +{ + struct aw_monitor_hdr_v_0_1_1 *monitor_hdr = + (struct aw_monitor_hdr_v_0_1_1 *)data; + struct aw_table_info *vol_info = + &aw_dev->monitor_desc.monitor_cfg.vol_info; + + aw_dev_info(aw_dev->dev, "===parse vol start ==="); + if (vol_info->aw_table != NULL) { + devm_kfree(aw_dev->dev, vol_info->aw_table); + vol_info->aw_table = NULL; + } + + vol_info->aw_table = devm_kzalloc(aw_dev->dev, + (monitor_hdr->vol_num * AW_TABLE_SIZE), + GFP_KERNEL); + if (vol_info->aw_table == NULL) + return -ENOMEM; + + vol_info->table_num = monitor_hdr->vol_num; + aw_monitor_write_data_to_table(aw_dev, vol_info, + &data[monitor_hdr->vol_offset]); + aw_dev_info(aw_dev->dev, "===parse vol end ==="); + return 0; +} + +static int aw_monitor_parse_vol_data_v_0_1_2(struct aw_device *aw_dev, uint8_t *data) +{ + struct aw_monitor_hdr_v_0_1_2 *monitor_hdr = + (struct aw_monitor_hdr_v_0_1_2 *)data; + struct aw_table_info *vol_info = + &aw_dev->monitor_desc.monitor_cfg.vol_info; + + aw_dev_info(aw_dev->dev, "===parse vol start ==="); + if (vol_info->aw_table != NULL) { + devm_kfree(aw_dev->dev, vol_info->aw_table); + vol_info->aw_table = NULL; + } + + vol_info->aw_table = devm_kzalloc(aw_dev->dev, + (monitor_hdr->vol_num * AW_TABLE_SIZE), + GFP_KERNEL); + if (vol_info->aw_table == NULL) + return -ENOMEM; + + vol_info->table_num = monitor_hdr->vol_num; + aw_monitor_write_data_to_table(aw_dev, vol_info, + &data[monitor_hdr->vol_offset]); + aw_dev_info(aw_dev->dev, "===parse vol end ==="); + return 0; +} + +static int aw_monitor_parse_data(struct aw_device *aw_dev, + uint8_t *data, uint32_t data_len) +{ + int ret; + struct aw_monitor_cfg *monitor_cfg = &aw_dev->monitor_desc.monitor_cfg; + + ret = aw_monitor_check_fw(aw_dev, data, data_len); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "check monitor failed"); + return ret; + } + + aw_monitor_parse_hdr(aw_dev, data); + + ret = aw_monitor_parse_temp_data(aw_dev, data); + if (ret < 0) + return ret; + + ret = aw_monitor_parse_vol_data(aw_dev, data); + if (ret < 0) { + if (monitor_cfg->temp_info.aw_table != NULL) { + devm_kfree(aw_dev->dev, monitor_cfg->temp_info.aw_table); + monitor_cfg->temp_info.aw_table = NULL; + monitor_cfg->temp_info.table_num = 0; + } + return ret; + } + + monitor_cfg->monitor_status = AW_MON_CFG_OK; + return 0; +} + + +static int aw_monitor_parse_data_v_0_1_1(struct aw_device *aw_dev, + uint8_t *data, uint32_t data_len) +{ + int ret; + struct aw_monitor_cfg *monitor_cfg = &aw_dev->monitor_desc.monitor_cfg; + + ret = aw_monitor_check_fw_v_0_1_1(aw_dev, data, data_len); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "check monitor failed"); + return ret; + } + + aw_monitor_parse_hdr_v_0_1_1(aw_dev, data); + + ret = aw_monitor_parse_temp_data_v_0_1_1(aw_dev, data); + if (ret < 0) + return ret; + + ret = aw_monitor_parse_vol_data_v_0_1_1(aw_dev, data); + if (ret < 0) { + if (monitor_cfg->temp_info.aw_table != NULL) { + devm_kfree(aw_dev->dev, monitor_cfg->temp_info.aw_table); + monitor_cfg->temp_info.aw_table = NULL; + monitor_cfg->temp_info.table_num = 0; + } + return ret; + } + + monitor_cfg->monitor_status = AW_MON_CFG_OK; + return 0; +} + +static int aw_monitor_parse_data_v_0_1_2(struct aw_device *aw_dev, + uint8_t *data, uint32_t data_len) +{ + int ret; + struct aw_monitor_cfg *monitor_cfg = &aw_dev->monitor_desc.monitor_cfg; + + ret = aw_monitor_check_fw_v_0_1_2(aw_dev, data, data_len); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "check monitor failed"); + return ret; + } + + aw_monitor_parse_hdr_v_0_1_2(aw_dev, data); + + ret = aw_monitor_parse_temp_data_v_0_1_2(aw_dev, data); + if (ret < 0) + return ret; + + ret = aw_monitor_parse_vol_data_v_0_1_2(aw_dev, data); + if (ret < 0) { + if (monitor_cfg->temp_info.aw_table != NULL) { + devm_kfree(aw_dev->dev, monitor_cfg->temp_info.aw_table); + monitor_cfg->temp_info.aw_table = NULL; + monitor_cfg->temp_info.table_num = 0; + } + return ret; + } + + monitor_cfg->monitor_status = AW_MON_CFG_OK; + return 0; +} + +int aw882xx_monitor_parse_fw(struct aw_monitor_desc *monitor_desc, + uint8_t *data, uint32_t data_len) +{ + int ret; + struct aw_monitor_hdr *monitor_hdr = NULL; + struct aw_device *aw_dev = NULL; + + if (monitor_desc == NULL || data == NULL) { + pr_err("monitor_desc or data is NULL"); + return -EINVAL; + } + + monitor_hdr = (struct aw_monitor_hdr *)data; + aw_dev = container_of(monitor_desc, + struct aw_device, monitor_desc); + + ret = aw_monitor_param_check_sum(aw_dev, data, data_len); + if (ret < 0) + return ret; + + switch (monitor_hdr->monitor_ver) { + case AW_MONITOR_HDR_VER_0_1_0: + return aw_monitor_parse_data(aw_dev, data, data_len); + case AW_MONITOR_HDR_VER_0_1_1: + return aw_monitor_parse_data_v_0_1_1(aw_dev, data, data_len); + case AW_MONITOR_HDR_VER_0_1_2: + return aw_monitor_parse_data_v_0_1_2(aw_dev, data, data_len); + default: + aw_dev_err(aw_dev->dev, "cfg version:0x%x unsupported", + monitor_hdr->monitor_ver); + return -EINVAL; + } +} + +static void aw_monitor_free_firmware(struct aw_device *aw_dev) +{ + struct aw_monitor_cfg *monitor_cfg = + &aw_dev->monitor_desc.monitor_cfg; + + monitor_cfg->monitor_status = AW_MON_CFG_ST; + + if (monitor_cfg->temp_info.aw_table != NULL) { + devm_kfree(aw_dev->dev, monitor_cfg->temp_info.aw_table); + monitor_cfg->temp_info.aw_table = NULL; + } + + if (monitor_cfg->vol_info.aw_table != NULL) { + devm_kfree(aw_dev->dev, monitor_cfg->vol_info.aw_table); + monitor_cfg->vol_info.aw_table = NULL; + } + + memset(monitor_cfg, 0, sizeof(struct aw_monitor_cfg)); +} + +static int aw_monitor_real_time_update_monitor(struct aw_device *aw_dev) +{ + int ret; + const struct firmware *cont = NULL; + struct aw_container *aw_monitor_cnt = NULL; + + ret = request_firmware(&cont, aw_dev->monitor_name, aw_dev->dev); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "failed to read %s", aw_dev->monitor_name); + release_firmware(cont); + return ret; + } + + aw_monitor_cnt = devm_kzalloc(aw_dev->dev, + cont->size + sizeof(uint32_t), GFP_KERNEL); + if (aw_monitor_cnt == NULL) { + release_firmware(cont); + return -ENOMEM; + } + + aw_monitor_cnt->len = cont->size; + memcpy(aw_monitor_cnt->data, cont->data, cont->size); + release_firmware(cont); + + ret = aw882xx_monitor_parse_fw(&aw_dev->monitor_desc, + aw_monitor_cnt->data, aw_monitor_cnt->len); + if (ret < 0) + aw_dev_err(aw_dev->dev, "parse monitor firmware failed!"); + + devm_kfree(aw_dev->dev, aw_monitor_cnt); + aw_monitor_cnt = NULL; + + return ret; +} + +/***************************************************** + * monitor init + *****************************************************/ +#ifdef AW_DEBUG +static ssize_t vol_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret = -1; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + uint32_t vol = 0; + + if (count == 0) + return 0; + + ret = kstrtouint(buf, 0, &vol); + if (ret < 0) + return ret; + + aw_dev_info(aw_dev->dev, "vol set =%d", vol); + aw_dev->monitor_desc.test_vol = vol; + + return count; +} + +static ssize_t vol_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, + "vol: %d\n", + aw_dev->monitor_desc.test_vol); + return len; +} + +static ssize_t temp_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret = -1; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + int32_t temp = 0; + + if (count == 0) + return 0; + + ret = kstrtoint(buf, 0, &temp); + if (ret < 0) + return ret; + + aw_dev_info(aw_dev->dev, "temp set =%d", temp); + + aw_dev->monitor_desc.test_temp = temp; + + return count; +} + +static ssize_t temp_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, + "aw882xx temp: %d\n", + aw_dev->monitor_desc.test_temp); + + return len; +} + +static DEVICE_ATTR_RW(vol); +static DEVICE_ATTR_RW(temp); +#endif + +static ssize_t monitor_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret = -1; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + uint32_t enable = 0; + + if (count == 0) + return 0; + + ret = kstrtouint(buf, 0, &enable); + if (ret < 0) + return ret; + + aw_dev_info(aw_dev->dev, "monitor enable set =%d", enable); + + if (aw_dev->monitor_desc.monitor_cfg.monitor_switch == enable) + return count; + + aw_dev->monitor_desc.monitor_cfg.monitor_switch = enable; + if (enable) + aw882xx_monitor_start(&aw_dev->monitor_desc); + + return count; +} + +static ssize_t monitor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, + "monitor enable: %d\n", + aw_dev->monitor_desc.monitor_cfg.monitor_switch); + return len; +} + +static ssize_t monitor_update_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret = -1; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct aw_device *aw_dev = aw882xx->aw_pa; + uint32_t update = 0; + + if (count == 0) + return 0; + + ret = kstrtouint(buf, 0, &update); + if (ret < 0) + return ret; + + aw_dev_info(aw_dev->dev, "monitor update = %d", update); + + if (update) { + aw882xx_monitor_stop(&aw_dev->monitor_desc); + aw_monitor_free_firmware(aw_dev); + ret = aw_monitor_real_time_update_monitor(aw_dev); + if (ret < 0) + return ret; + aw882xx_monitor_start(&aw_dev->monitor_desc); + } + + return count; +} + +static DEVICE_ATTR_RW(monitor); +static DEVICE_ATTR_WO(monitor_update); + +static struct attribute *aw_monitor_attr[] = { + &dev_attr_monitor.attr, + &dev_attr_monitor_update.attr, +#ifdef AW_DEBUG + &dev_attr_vol.attr, + &dev_attr_temp.attr, +#endif + NULL +}; + +static struct attribute_group aw_monitor_attr_group = { + .attrs = aw_monitor_attr, +}; + +static void aw_monitor_parse_mode(struct aw_device *aw_dev) +{ + int ret = 0; + const char *mon_mode_str = NULL; + struct aw_monitor_desc *monitor = &aw_dev->monitor_desc; + + ret = of_property_read_string(aw_dev->dev->of_node, "monitor-mode", &mon_mode_str); + if (ret < 0) { + aw_dev_info(aw_dev->dev, "use default monitor mode"); + return; + } + + if (!strcmp(mon_mode_str, "kernel_monitor")) + monitor->monitor_mode = AW_MON_KERNEL_MODE; + else if (!strcmp(mon_mode_str, "hal_monitor")) + monitor->monitor_mode = AW_MON_HAL_MODE; + else + monitor->monitor_mode = AW_MON_KERNEL_MODE; + + aw_dev_info(aw_dev->dev, "read monitor-mode value is : %d", monitor->monitor_mode); +} + +void aw882xx_monitor_init(struct aw_monitor_desc *monitor_desc) +{ + int ret; + struct aw_device *aw_dev = container_of(monitor_desc, + struct aw_device, monitor_desc); + + aw_dev_info(aw_dev->dev, "enter"); +#ifdef AW_DEBUG + monitor_desc->test_vol = 0; + monitor_desc->test_temp = 0; +#endif + + + aw_monitor_parse_mode(aw_dev); + INIT_DELAYED_WORK(&monitor_desc->delay_work, aw_monitor_work_func); + + ret = sysfs_create_group(&aw_dev->dev->kobj, + &aw_monitor_attr_group); + if (ret < 0) + aw_dev_err(aw_dev->dev, "error creating sysfs attr files"); +} + +void aw882xx_monitor_deinit(struct aw_monitor_desc *monitor_desc) +{ + struct aw_device *aw_dev = + container_of(monitor_desc, struct aw_device, monitor_desc); + + aw882xx_monitor_stop(monitor_desc); + + sysfs_remove_group(&aw_dev->dev->kobj, &aw_monitor_attr_group); +} + diff --git a/sound/soc/codecs/aw882xx/aw882xx_monitor.h b/sound/soc/codecs/aw882xx/aw882xx_monitor.h new file mode 100644 index 000000000000..832eeaa98c2a --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_monitor.h @@ -0,0 +1,234 @@ +/* SPDX-License-Identifier: GPL-2.0 + * aw882xx_monitor.h + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_MONITOR_H__ +#define __AW882XX_MONITOR_H__ + +/*#define AW_DEBUG*/ + +struct aw_table; + +#define AW_TABLE_SIZE sizeof(struct aw_table) +#define AW_MONITOR_DEFAULT_FLAG (0) + +#define IPEAK_NONE (0xFF) +#define GAIN_NONE (0xFF) +#define VMAX_NONE (0xFFFFFFFF) + + +#define AW_GET_32_DATA(w, x, y, z) \ + ((uint32_t)((((uint8_t)w) << 24) | (((uint8_t)x) << 16) | (((uint8_t)y) << 8) | ((uint8_t)z))) +#define AW_GET_16_DATA(x, y) \ + ((uint16_t)((((uint8_t)x) << 8) | (uint8_t)y)) + +enum { + AW_MON_LOGIC_OR = 0, + AW_MON_LOGIC_AND = 1, +}; + +enum { + AW_FIRST_ENTRY = 0, + AW_NOT_FIRST_ENTRY = 1, +}; + +enum aw_monitor_hdr_ver { + AW_MONITOR_HDR_VER_0_1_0 = 0x00010000, + AW_MONITOR_HDR_VER_0_1_1 = 0x00010100, + AW_MONITOR_HDR_VER_0_1_2 = 0x00010200, +}; + +enum aw_monitor_init { + AW_MON_CFG_ST = 0, + AW_MON_CFG_OK = 1, +}; + +struct aw_monitor_hdr { + uint32_t check_sum; + uint32_t monitor_ver; + char chip_type[8]; + uint32_t ui_ver; + uint32_t monitor_switch; + uint32_t monitor_time; + uint32_t monitor_count; + uint32_t ipeak_switch; + uint32_t gain_switch; + uint32_t vmax_switch; + uint32_t temp_switch; + uint32_t temp_aplha; + uint32_t temp_num; + uint32_t single_temp_size; + uint32_t temp_offset; + uint32_t vol_switch; + uint32_t vol_aplha; + uint32_t vol_num; + uint32_t single_vol_size; + uint32_t vol_offset; +}; + +#define MONITOR_EN_MASK (0x01) + +enum { + MONITOR_EN_BIT = 0, + MONITOR_LOGIC_BIT = 1, + MONITOR_IPEAK_EN_BIT = 2, + MONITOR_GAIN_EN_BIT = 3, + MONITOR_VMAX_EN_BIT = 4, + MONITOR_TEMP_EN_BIT = 5, + MONITOR_VOL_EN_BIT = 6, + MONITOR_TEMPERATURE_SOURCE_BIT = 7, + MONITOR_VOLTAGE_SOURCE_BIT = 8, + MONITOR_VOLTAGE_MODE_BIT = 9, +}; + +struct aw_monitor_hdr_v_0_1_1 { + uint32_t check_sum; + uint32_t monitor_ver; + char chip_type[16]; + uint32_t ui_ver; + uint32_t monitor_time; + uint32_t monitor_count; + uint32_t enable_flag; + /* [bit 31:7] */ + /* [bit 6: vol en] */ + /* [bit 5: temp en] */ + /* [bit 4: vmax en] */ + /* [bit 3: gain en] */ + /* [bit 2: ipeak en] */ + /* [bit 1: & or | flag] */ + /* [bit 0: monitor en] */ + uint32_t temp_aplha; + uint32_t temp_num; + uint32_t single_temp_size; + uint32_t temp_offset; + uint32_t vol_aplha; + uint32_t vol_num; + uint32_t single_vol_size; + uint32_t vol_offset; + uint32_t reserver[3]; +}; + +/* v0.1.2 */ +struct aw_monitor_hdr_v_0_1_2 { + uint32_t check_sum; + uint32_t monitor_ver; + char chip_type[16]; + uint32_t ui_ver; + uint32_t monitor_time; + uint32_t monitor_count; + uint32_t enable_flag; + /* [bit 31:7]*/ + /* [bit 9: voltage mode]*/ + /* [bit 8: voltage source]*/ + /* [bit 7: temperature source]*/ + /* [bit 6: vol en]*/ + /* [bit 5: temp en]*/ + /* [bit 4: vmax en]*/ + /* [bit 3: gain en]*/ + /* [bit 2: ipeak en]*/ + /* [bit 1: & or | flag]*/ + /* [bit 0: monitor en]*/ + uint32_t temp_aplha; + uint32_t temp_num; + uint32_t single_temp_size; + uint32_t temp_offset; + uint32_t vol_aplha; + uint32_t vol_num; + uint32_t single_vol_size; + uint32_t vol_offset; + uint32_t reserver[3]; +}; + +struct aw_table { + int16_t min_val; + int16_t max_val; + uint16_t ipeak; + uint16_t gain; + uint32_t vmax; +}; + +struct aw_table_info { + uint8_t table_num; + struct aw_table *aw_table; +}; + +struct aw_monitor_cfg { + uint8_t monitor_status; + uint32_t monitor_switch; + uint32_t monitor_time; + uint32_t monitor_count; + uint32_t logic_switch; + uint32_t temp_switch; + uint32_t temp_aplha; + uint32_t vol_switch; + uint32_t vol_aplha; + uint32_t ipeak_switch; + uint32_t gain_switch; + uint32_t vmax_switch; + uint32_t temp_source; + uint32_t vol_source; + uint32_t vol_mode; + struct aw_table_info temp_info; + struct aw_table_info vol_info; +}; + +struct aw_monitor_trace { + int32_t pre_val; + int32_t sum_val; + struct aw_table aw_table; +}; + +enum aw_monitor_mode { + AW_MON_KERNEL_MODE = 0, + AW_MON_HAL_MODE, +}; + +/****************************************************************** + * struct aw882xx monitor + *******************************************************************/ +struct aw_monitor_desc { + struct delayed_work delay_work; + struct aw_monitor_cfg monitor_cfg; + + bool mon_start_flag; + uint8_t first_entry; + uint8_t samp_count; + uint8_t db_offset; + uint8_t monitor_mode; + + uint32_t pre_vmax; + struct aw_monitor_trace temp_trace; + struct aw_monitor_trace vol_trace; + + +#ifdef AW_DEBUG + uint16_t test_vol; + int16_t test_temp; +#endif +}; + +/****************************************************************** + * aw882xx monitor functions + *******************************************************************/ +void aw882xx_monitor_start(struct aw_monitor_desc *monitor_desc); +int aw882xx_monitor_stop(struct aw_monitor_desc *monitor_desc); +void aw882xx_monitor_init(struct aw_monitor_desc *monitor_desc); +void aw882xx_monitor_deinit(struct aw_monitor_desc *monitor_desc); +int aw882xx_monitor_parse_fw(struct aw_monitor_desc *monitor_desc, + uint8_t *data, uint32_t data_len); + +void aw882xx_monitor_hal_work(struct aw_monitor_desc *monitor_desc, uint32_t *vmax); +void aw882xx_monitor_hal_get_time(struct aw_monitor_desc *monitor_desc, uint32_t *time); + + +#endif + diff --git a/sound/soc/codecs/aw882xx/aw882xx_pid_1852_reg.h b/sound/soc/codecs/aw882xx/aw882xx_pid_1852_reg.h new file mode 100644 index 000000000000..94af10893b62 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_pid_1852_reg.h @@ -0,0 +1,1927 @@ +/* SPDX-License-Identifier: GPL-2.0 + * aw882xx_pid_1852_reg.h + * + * Copyright (c) 2020 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_PID_1852_REG_H__ +#define __AW882XX_PID_1852_REG_H__ + +#define AW_PID_1852_MONITOR_FILE "aw882xx_pid_1852_monitor.bin" + +/* registers list */ +#define AW_PID_1852_ID_REG (0x00) +#define AW_PID_1852_SYSST_REG (0x01) +#define AW_PID_1852_SYSINT_REG (0x02) +#define AW_PID_1852_SYSINTM_REG (0x03) +#define AW_PID_1852_SYSCTRL_REG (0x04) +#define AW_PID_1852_SYSCTRL2_REG (0x05) +#define AW_PID_1852_I2SCTRL_REG (0x06) +#define AW_PID_1852_I2SCFG1_REG (0x07) +#define AW_PID_1852_I2SCFG2_REG (0x08) +#define AW_PID_1852_HAGCCFG1_REG (0x09) +#define AW_PID_1852_HAGCCFG2_REG (0x0A) +#define AW_PID_1852_HAGCCFG3_REG (0x0B) +#define AW_PID_1852_HAGCCFG4_REG (0x0C) +#define AW_PID_1852_HAGCCFG5_REG (0x0D) +#define AW_PID_1852_HAGCCFG6_REG (0x0E) +#define AW_PID_1852_HAGCCFG7_REG (0x0F) +#define AW_PID_1852_HAGCST_REG (0x10) +#define AW_PID_1852_PRODID_REG (0x11) +#define AW_PID_1852_VBAT_REG (0x12) +#define AW_PID_1852_TEMP_REG (0x13) +#define AW_PID_1852_PVDD_REG (0x14) +#define AW_PID_1852_DBGCTRL_REG (0x20) +#define AW_PID_1852_I2SINT_REG (0x21) +#define AW_PID_1852_I2SCAPCNT_REG (0x22) +#define AW_PID_1852_CRCIN_REG (0x38) +#define AW_PID_1852_CRCOUT_REG (0x39) +#define AW_PID_1852_VSNCTRL1_REG (0x50) +#define AW_PID_1852_ISNCTRL1_REG (0x52) +#define AW_PID_1852_ISNCTRL2_REG (0x53) +#define AW_PID_1852_VTMCTRL1_REG (0x54) +#define AW_PID_1852_VTMCTRL2_REG (0x55) +#define AW_PID_1852_VTMCTRL3_REG (0x56) +#define AW_PID_1852_ISNDAT_REG (0x57) +#define AW_PID_1852_VSNDAT_REG (0x58) +#define AW_PID_1852_PWMCTRL_REG (0x59) +#define AW_PID_1852_PWMCTRL2_REG (0x5A) +#define AW_PID_1852_BSTCTRL1_REG (0x60) +#define AW_PID_1852_BSTCTRL2_REG (0x61) +#define AW_PID_1852_BSTCTRL3_REG (0x62) +#define AW_PID_1852_BSTDBG1_REG (0x63) +#define AW_PID_1852_BSTDBG2_REG (0x64) +#define AW_PID_1852_BSTDBG3_REG (0x65) +#define AW_PID_1852_PLLCTRL1_REG (0x66) +#define AW_PID_1852_PLLCTRL2_REG (0x67) +#define AW_PID_1852_PLLCTRL3_REG (0x68) +#define AW_PID_1852_CDACTRL1_REG (0x69) +#define AW_PID_1852_CDACTRL2_REG (0x6A) +#define AW_PID_1852_SADCCTRL_REG (0x6B) +#define AW_PID_1852_TESTCTRL1_REG (0x70) +#define AW_PID_1852_TESTCTRL2_REG (0x71) +#define AW_PID_1852_EFCTRL1_REG (0x72) +#define AW_PID_1852_EFCTRL2_REG (0x73) +#define AW_PID_1852_EFWH_REG (0x74) +#define AW_PID_1852_EFWM2_REG (0x75) +#define AW_PID_1852_EFWM1_REG (0x76) +#define AW_PID_1852_EFWL_REG (0x77) +#define AW_PID_1852_EFRH_REG (0x78) +#define AW_PID_1852_EFRM2_REG (0x79) +#define AW_PID_1852_EFRM1_REG (0x7A) +#define AW_PID_1852_EFRL_REG (0x7B) +#define AW_PID_1852_TESTDET_REG (0x7C) + +/******************************************** + * Register Access + *******************************************/ +#define AW_PID_1852_REG_MAX (0x7D) + + +#define AW_PID_1852_REG_NONE_ACCESS (0) +#define AW_PID_1852_REG_RD_ACCESS (1 << 0) +#define AW_PID_1852_REG_WR_ACCESS (1 << 1) + + +static const unsigned char aw_pid_1852_reg_access[AW_PID_1852_REG_MAX] = { + [AW_PID_1852_ID_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_SYSST_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_SYSINT_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_SYSINTM_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_SYSCTRL_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_SYSCTRL2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_I2SCTRL_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_I2SCFG1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_I2SCFG2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_HAGCCFG1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_HAGCCFG2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_HAGCCFG3_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_HAGCCFG4_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_HAGCCFG5_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_HAGCCFG6_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_HAGCCFG7_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_HAGCST_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_PRODID_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_VBAT_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_TEMP_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_PVDD_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_DBGCTRL_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_I2SINT_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_I2SCAPCNT_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_CRCIN_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_CRCOUT_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_VSNCTRL1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_ISNCTRL1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_ISNCTRL2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_VTMCTRL1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_VTMCTRL2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_VTMCTRL3_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_ISNDAT_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_VSNDAT_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_PWMCTRL_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_PWMCTRL2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_BSTCTRL1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_BSTCTRL2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_BSTCTRL3_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_BSTDBG1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_BSTDBG2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_BSTDBG3_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_PLLCTRL1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_PLLCTRL2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_PLLCTRL3_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_CDACTRL1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_CDACTRL2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_SADCCTRL_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_TESTCTRL1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_TESTCTRL2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_EFCTRL1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_EFCTRL2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_EFWH_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_EFWM2_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_EFWM1_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_EFWL_REG] = (AW_PID_1852_REG_RD_ACCESS | AW_PID_1852_REG_WR_ACCESS), + [AW_PID_1852_EFRH_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_EFRM2_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_EFRM1_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_EFRL_REG] = (AW_PID_1852_REG_RD_ACCESS), + [AW_PID_1852_TESTDET_REG] = (AW_PID_1852_REG_RD_ACCESS), +}; + +/* detail information of registers begin */ +/* ID (0x00) detail */ +/* IDCODE bit 15:0 (ID 0x00) */ +#define AW_PID_1852_IDCODE_START_BIT (0) +#define AW_PID_1852_IDCODE_BITS_LEN (16) +#define AW_PID_1852_IDCODE_MASK \ + (~(((1< + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_PID_2013_REG_H__ +#define __AW882XX_PID_2013_REG_H__ + +#define AW_PID_2013_MONITOR_FILE "aw882xx_pid_2013_monitor.bin" + +/* registers list */ +#define AW_PID_2013_ID_REG (0x00) +#define AW_PID_2013_SYSST_REG (0x01) +#define AW_PID_2013_SYSINT_REG (0x02) +#define AW_PID_2013_SYSINTM_REG (0x03) +#define AW_PID_2013_SYSCTRL_REG (0x04) +#define AW_PID_2013_SYSCTRL2_REG (0x05) +#define AW_PID_2013_I2SCTRL1_REG (0x06) +#define AW_PID_2013_I2SCTRL2_REG (0x07) +#define AW_PID_2013_DACCFG1_REG (0x08) +#define AW_PID_2013_DACCFG2_REG (0x09) +#define AW_PID_2013_DACCFG3_REG (0x0A) +#define AW_PID_2013_DACCFG4_REG (0x0B) +#define AW_PID_2013_DACCFG5_REG (0x0C) +#define AW_PID_2013_DACCFG6_REG (0x0D) +#define AW_PID_2013_DACCFG7_REG (0x0E) +#define AW_PID_2013_PWMCTRL_REG (0x10) +#define AW_PID_2013_I2SCFG1_REG (0x11) +#define AW_PID_2013_DBGCTRL_REG (0x12) +#define AW_PID_2013_DACST_REG (0x20) +#define AW_PID_2013_VBAT_REG (0x21) +#define AW_PID_2013_TEMP_REG (0x22) +#define AW_PID_2013_PVDD_REG (0x23) +#define AW_PID_2013_ISNDAT_REG (0x24) +#define AW_PID_2013_VSNDAT_REG (0x25) +#define AW_PID_2013_I2SINT_REG (0x26) +#define AW_PID_2013_I2SCAPCNT_REG (0x27) +#define AW_PID_2013_ANASTA1_REG (0x28) +#define AW_PID_2013_ANASTA2_REG (0x29) +#define AW_PID_2013_ANASTA3_REG (0x2A) +#define AW_PID_2013_TESTDET_REG (0x2B) +#define AW_PID_2013_TESTIN_REG (0x38) +#define AW_PID_2013_TESTOUT_REG (0x39) +#define AW_PID_2013_VSNTM1_REG (0x50) +#define AW_PID_2013_VSNTM2_REG (0x51) +#define AW_PID_2013_ISNCTRL1_REG (0x52) +#define AW_PID_2013_PLLCTRL1_REG (0x53) +#define AW_PID_2013_PLLCTRL2_REG (0x54) +#define AW_PID_2013_PLLCTRL3_REG (0x55) +#define AW_PID_2013_CDACTRL1_REG (0x56) +#define AW_PID_2013_CDACTRL2_REG (0x57) +#define AW_PID_2013_SADCCTRL1_REG (0x58) +#define AW_PID_2013_BSTCTRL1_REG (0x60) +#define AW_PID_2013_BSTCTRL2_REG (0x61) +#define AW_PID_2013_BSTCTRL3_REG (0x62) +#define AW_PID_2013_BSTCTRL4_REG (0x63) +#define AW_PID_2013_BSTCTRL5_REG (0x64) +#define AW_PID_2013_BSTCTRL6_REG (0x65) +#define AW_PID_2013_DSMCFG1_REG (0x66) +#define AW_PID_2013_DSMCFG2_REG (0x67) +#define AW_PID_2013_DSMCFG3_REG (0x68) +#define AW_PID_2013_DSMCFG4_REG (0x69) +#define AW_PID_2013_DSMCFG5_REG (0x6A) +#define AW_PID_2013_DSMCFG6_REG (0x6B) +#define AW_PID_2013_DSMCFG7_REG (0x6C) +#define AW_PID_2013_DSMCFG8_REG (0x6D) +#define AW_PID_2013_TESTCTRL1_REG (0x70) +#define AW_PID_2013_TESTCTRL2_REG (0x71) +#define AW_PID_2013_EFCTRL1_REG (0x72) +#define AW_PID_2013_EFCTRL2_REG (0x73) +#define AW_PID_2013_EFWH_REG (0x74) +#define AW_PID_2013_EFWM2_REG (0x75) +#define AW_PID_2013_EFWM1_REG (0x76) +#define AW_PID_2013_EFWL_REG (0x77) +#define AW_PID_2013_EFRH_REG (0x78) +#define AW_PID_2013_EFRM2_REG (0x79) +#define AW_PID_2013_EFRM1_REG (0x7A) +#define AW_PID_2013_EFRL_REG (0x7B) +#define AW_PID_2013_TM_REG (0x7C) + +/******************************************** + * Register Access + *******************************************/ +#define AW_PID_2013_REG_MAX (0x7D) + +#define AW_PID_2013_REG_NONE_ACCESS (0) +#define AW_PID_2013_REG_RD_ACCESS (1 << 0) +#define AW_PID_2013_REG_WR_ACCESS (1 << 1) + +const unsigned char aw_pid_2013_reg_access[AW_PID_2013_REG_MAX] = { + [AW_PID_2013_ID_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_SYSST_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_SYSINT_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_SYSINTM_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_SYSCTRL_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_SYSCTRL2_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_I2SCTRL1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_I2SCTRL2_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DACCFG1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DACCFG2_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DACCFG3_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DACCFG4_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DACCFG5_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DACCFG6_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DACCFG7_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_PWMCTRL_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_I2SCFG1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DBGCTRL_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DACST_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_VBAT_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_TEMP_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_PVDD_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_ISNDAT_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_VSNDAT_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_I2SINT_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_I2SCAPCNT_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_ANASTA1_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_ANASTA2_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_ANASTA3_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_TESTDET_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_TESTIN_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_TESTOUT_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_VSNTM1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_VSNTM2_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_ISNCTRL1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_PLLCTRL1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_PLLCTRL2_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_PLLCTRL3_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_CDACTRL1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_CDACTRL2_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_SADCCTRL1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_BSTCTRL1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_BSTCTRL2_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_BSTCTRL3_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_BSTCTRL4_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_BSTCTRL5_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_BSTCTRL6_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DSMCFG1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DSMCFG2_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DSMCFG3_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DSMCFG4_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DSMCFG5_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DSMCFG6_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DSMCFG7_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_DSMCFG8_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_TESTCTRL1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_TESTCTRL2_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_EFCTRL1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_EFCTRL2_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_EFWH_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_EFWM2_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_EFWM1_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_EFWL_REG] = (AW_PID_2013_REG_RD_ACCESS | AW_PID_2013_REG_WR_ACCESS), + [AW_PID_2013_EFRH_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_EFRM2_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_EFRM1_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_EFRL_REG] = (AW_PID_2013_REG_RD_ACCESS), + [AW_PID_2013_TM_REG] = (AW_PID_2013_REG_NONE_ACCESS), +}; + +/* detail information of registers begin */ +/* ID (0x00) detail */ +/* IDCODE bit 15:0 (ID 0x00) */ +#define AW_PID_2013_IDCODE_START_BIT (0) +#define AW_PID_2013_IDCODE_BITS_LEN (16) +#define AW_PID_2013_IDCODE_MASK \ + (~(((1< + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_PID_2032_REG_H__ +#define __AW882XX_PID_2032_REG_H__ + +#define AW_PID_2032_MONITOR_FILE "aw882xx_pid_2032_monitor.bin" + +/* registers list */ +#define AW_PID_2032_ID_REG (0x00) +#define AW_PID_2032_SYSST_REG (0x01) +#define AW_PID_2032_SYSINT_REG (0x02) +#define AW_PID_2032_SYSINTM_REG (0x03) +#define AW_PID_2032_SYSCTRL_REG (0x04) +#define AW_PID_2032_SYSCTRL2_REG (0x05) +#define AW_PID_2032_I2SCTRL_REG (0x06) +#define AW_PID_2032_I2SCFG1_REG (0x07) +#define AW_PID_2032_I2SCFG2_REG (0x08) +#define AW_PID_2032_HAGCCFG1_REG (0x09) +#define AW_PID_2032_HAGCCFG2_REG (0x0A) +#define AW_PID_2032_HAGCCFG3_REG (0x0B) +#define AW_PID_2032_HAGCCFG4_REG (0x0C) +#define AW_PID_2032_HAGCCFG5_REG (0x0D) +#define AW_PID_2032_HAGCCFG6_REG (0x0E) +#define AW_PID_2032_HAGCCFG7_REG (0x0F) +#define AW_PID_2032_HAGCST_REG (0x10) +#define AW_PID_2032_PRODID_REG (0x11) +#define AW_PID_2032_VBAT_REG (0x12) +#define AW_PID_2032_TEMP_REG (0x13) +#define AW_PID_2032_PVDD_REG (0x14) +#define AW_PID_2032_HAGCCFG8_REG (0x15) +#define AW_PID_2032_DBGCTRL_REG (0x20) +#define AW_PID_2032_I2SINT_REG (0x21) +#define AW_PID_2032_I2SCAPCNT_REG (0x22) +#define AW_PID_2032_ANASTA1_REG (0x23) +#define AW_PID_2032_ANASTA2_REG (0x24) +#define AW_PID_2032_ANASTA3_REG (0x25) +#define AW_PID_2032_ANASTA4_REG (0x26) +#define AW_PID_2032_DSMCFG1_REG (0x30) +#define AW_PID_2032_DSMCFG2_REG (0x31) +#define AW_PID_2032_DSMCFG3_REG (0x32) +#define AW_PID_2032_DSMCFG4_REG (0x33) +#define AW_PID_2032_DSMCFG5_REG (0x34) +#define AW_PID_2032_DSMCFG6_REG (0x35) +#define AW_PID_2032_DSMCFG7_REG (0x36) +#define AW_PID_2032_DSMCFG8_REG (0x37) +#define AW_PID_2032_TESTIN_REG (0x38) +#define AW_PID_2032_TESTOUT_REG (0x39) +#define AW_PID_2032_VSNCTRL1_REG (0x50) +#define AW_PID_2032_ISNCTRL1_REG (0x52) +#define AW_PID_2032_ISNCTRL2_REG (0x53) +#define AW_PID_2032_VTMCTRL1_REG (0x54) +#define AW_PID_2032_VTMCTRL2_REG (0x55) +#define AW_PID_2032_VTMCTRL3_REG (0x56) +#define AW_PID_2032_ISNDAT_REG (0x57) +#define AW_PID_2032_VSNDAT_REG (0x58) +#define AW_PID_2032_PWMCTRL_REG (0x59) +#define AW_PID_2032_PWMCTRL2_REG (0x5A) +#define AW_PID_2032_BSTCTRL1_REG (0x60) +#define AW_PID_2032_BSTCTRL2_REG (0x61) +#define AW_PID_2032_BSTCTRL3_REG (0x62) +#define AW_PID_2032_BSTDBG1_REG (0x63) +#define AW_PID_2032_BSTDBG2_REG (0x64) +#define AW_PID_2032_BSTDBG3_REG (0x65) +#define AW_PID_2032_PLLCTRL1_REG (0x66) +#define AW_PID_2032_PLLCTRL2_REG (0x67) +#define AW_PID_2032_PLLCTRL3_REG (0x68) +#define AW_PID_2032_CDACTRL1_REG (0x69) +#define AW_PID_2032_CDACTRL2_REG (0x6A) +#define AW_PID_2032_SADCCTRL_REG (0x6B) +#define AW_PID_2032_BSTCTRL8_REG (0x6C) +#define AW_PID_2032_TESTCTRL1_REG (0x70) +#define AW_PID_2032_TESTCTRL2_REG (0x71) +#define AW_PID_2032_EFCTRL1_REG (0x72) +#define AW_PID_2032_EFCTRL2_REG (0x73) +#define AW_PID_2032_EFWH_REG (0x74) +#define AW_PID_2032_EFWM2_REG (0x75) +#define AW_PID_2032_EFWM1_REG (0x76) +#define AW_PID_2032_EFWL_REG (0x77) +#define AW_PID_2032_EFRH_REG (0x78) +#define AW_PID_2032_EFRM2_REG (0x79) +#define AW_PID_2032_EFRM1_REG (0x7A) +#define AW_PID_2032_EFRL_REG (0x7B) +#define AW_PID_2032_TESTDET_REG (0x7C) +#define AW_PID_2032_TM_REG (0x7D) + +/******************************************** + * Register Access + *******************************************/ +#define AW_PID_2032_REG_MAX (0x7E) + +#define AW_PID_2032_REG_NONE_ACCESS (0) +#define AW_PID_2032_REG_RD_ACCESS (1 << 0) +#define AW_PID_2032_REG_WR_ACCESS (1 << 1) + +const unsigned char aw_pid_2032_reg_access[AW_PID_2032_REG_MAX] = { + [AW_PID_2032_ID_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_SYSST_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_SYSINT_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_SYSINTM_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_SYSCTRL_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_SYSCTRL2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_I2SCTRL_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_I2SCFG1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_I2SCFG2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_HAGCCFG1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_HAGCCFG2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_HAGCCFG3_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_HAGCCFG4_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_HAGCCFG5_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_HAGCCFG6_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_HAGCCFG7_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_HAGCST_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_PRODID_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_VBAT_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_TEMP_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_PVDD_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_HAGCCFG8_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_DBGCTRL_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_I2SINT_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_I2SCAPCNT_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_ANASTA1_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_ANASTA2_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_ANASTA3_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_ANASTA4_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_DSMCFG1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_DSMCFG2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_DSMCFG3_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_DSMCFG4_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_DSMCFG5_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_DSMCFG6_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_DSMCFG7_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_DSMCFG8_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_TESTIN_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_TESTOUT_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_VSNCTRL1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_ISNCTRL1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_ISNCTRL2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_VTMCTRL1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_VTMCTRL2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_VTMCTRL3_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_ISNDAT_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_VSNDAT_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_PWMCTRL_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_PWMCTRL2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_BSTCTRL1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_BSTCTRL2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_BSTCTRL3_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_BSTDBG1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_BSTDBG2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_BSTDBG3_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_PLLCTRL1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_PLLCTRL2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_PLLCTRL3_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_CDACTRL1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_CDACTRL2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_SADCCTRL_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_BSTCTRL8_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_TESTCTRL1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_TESTCTRL2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_EFCTRL1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_EFCTRL2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_EFWH_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_EFWM2_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_EFWM1_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_EFWL_REG] = (AW_PID_2032_REG_RD_ACCESS | AW_PID_2032_REG_WR_ACCESS), + [AW_PID_2032_EFRH_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_EFRM2_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_EFRM1_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_EFRL_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_TESTDET_REG] = (AW_PID_2032_REG_RD_ACCESS), + [AW_PID_2032_TM_REG] = (AW_PID_2032_REG_NONE_ACCESS), +}; + +/* detail information of registers begin */ +/* ID (0x00) detail */ +/* IDCODE bit 15:0 (ID 0x00) */ +#define AW_PID_2032_IDCODE_START_BIT (0) +#define AW_PID_2032_IDCODE_BITS_LEN (16) +#define AW_PID_2032_IDCODE_MASK \ + (~(((1< + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_PID_2055_REG_H__ +#define __AW882XX_PID_2055_REG_H__ + +#define AW_PID_2055_MONITOR_FILE "aw882xx_pid_2055_monitor.bin" + +/* registers list */ +#define AW_PID_2055_ID_REG (0x00) +#define AW_PID_2055_SYSST_REG (0x01) +#define AW_PID_2055_SYSINT_REG (0x02) +#define AW_PID_2055_SYSINTM_REG (0x03) +#define AW_PID_2055_SYSCTRL_REG (0x04) +#define AW_PID_2055_SYSCTRL2_REG (0x05) +#define AW_PID_2055_I2SCTRL1_REG (0x06) +#define AW_PID_2055_I2SCTRL2_REG (0x07) +#define AW_PID_2055_I2SCTRL3_REG (0x08) +#define AW_PID_2055_DACCFG1_REG (0x09) +#define AW_PID_2055_DACCFG2_REG (0x0A) +#define AW_PID_2055_DACCFG3_REG (0x0B) +#define AW_PID_2055_DACCFG4_REG (0x0C) +#define AW_PID_2055_DACCFG5_REG (0x0D) +#define AW_PID_2055_DACCFG6_REG (0x0E) +#define AW_PID_2055_DACCFG7_REG (0x0F) +#define AW_PID_2055_DACCFG8_REG (0x10) +#define AW_PID_2055_PWMCTRL1_REG (0x11) +#define AW_PID_2055_PWMCTRL2_REG (0x12) +#define AW_PID_2055_PWMCTRL3_REG (0x13) +#define AW_PID_2055_PWMCTRL4_REG (0x14) +#define AW_PID_2055_PWMCTRL5_REG (0x15) +#define AW_PID_2055_I2SCFG1_REG (0x16) +#define AW_PID_2055_DBGCTRL_REG (0x17) +#define AW_PID_2055_DITHERCFG1_REG (0x18) +#define AW_PID_2055_DACST_REG (0x20) +#define AW_PID_2055_VBAT_REG (0x21) +#define AW_PID_2055_TEMP_REG (0x22) +#define AW_PID_2055_PVDD_REG (0x23) +#define AW_PID_2055_BOPST_REG (0x24) +#define AW_PID_2055_I2SINT_REG (0x25) +#define AW_PID_2055_I2SCAPCNT_REG (0x26) +#define AW_PID_2055_ANASTA1_REG (0x27) +#define AW_PID_2055_ANASTA2_REG (0x28) +#define AW_PID_2055_ANASTA3_REG (0x29) +#define AW_PID_2055_DSMCFG1_REG (0x30) +#define AW_PID_2055_DSMCFG2_REG (0x31) +#define AW_PID_2055_DSMCFG3_REG (0x32) +#define AW_PID_2055_DSMCFG4_REG (0x33) +#define AW_PID_2055_DSMCFG5_REG (0x34) +#define AW_PID_2055_DSMCFG6_REG (0x35) +#define AW_PID_2055_DSMCFG7_REG (0x36) +#define AW_PID_2055_DSMCFG8_REG (0x37) +#define AW_PID_2055_TESTIN_REG (0x38) +#define AW_PID_2055_TESTOUT_REG (0x39) +#define AW_PID_2055_SADCCTRL1_REG (0x3A) +#define AW_PID_2055_SADCCTRL2_REG (0x3B) +#define AW_PID_2055_SADCCTRL3_REG (0x3C) +#define AW_PID_2055_SADCCTRL4_REG (0x3D) +#define AW_PID_2055_SADCCTRL5_REG (0x3E) +#define AW_PID_2055_SADCCTRL6_REG (0x3F) +#define AW_PID_2055_PLLCTRL1_REG (0x50) +#define AW_PID_2055_PLLCTRL2_REG (0x51) +#define AW_PID_2055_PLLCTRL3_REG (0x52) +#define AW_PID_2055_CDACTRL1_REG (0x53) +#define AW_PID_2055_CDACTRL2_REG (0x54) +#define AW_PID_2055_CDACTRL3_REG (0x55) +#define AW_PID_2055_BSTCTRL1_REG (0x60) +#define AW_PID_2055_BSTCTRL2_REG (0x61) +#define AW_PID_2055_BSTCTRL3_REG (0x62) +#define AW_PID_2055_BSTCTRL4_REG (0x63) +#define AW_PID_2055_BSTCTRL5_REG (0x64) +#define AW_PID_2055_BSTCTRL6_REG (0x65) +#define AW_PID_2055_BSTCTRL7_REG (0x66) +#define AW_PID_2055_BSTCTRL8_REG (0x67) +#define AW_PID_2055_CPCTRL1_REG (0x68) +#define AW_PID_2055_TESTCTRL1_REG (0x70) +#define AW_PID_2055_TESTCTRL2_REG (0x71) +#define AW_PID_2055_EFCTRL1_REG (0x72) +#define AW_PID_2055_EFCTRL2_REG (0x73) +#define AW_PID_2055_EFWH_REG (0x74) +#define AW_PID_2055_EFWL_REG (0x75) +#define AW_PID_2055_EFRH2_REG (0x76) +#define AW_PID_2055_EFRL2_REG (0x77) +#define AW_PID_2055_EFRH1_REG (0x78) +#define AW_PID_2055_EFRL1_REG (0x79) +#define AW_PID_2055_TM_REG (0x7C) + +/******************************************** + * Register Access + *******************************************/ +#define AW_PID_2055_REG_MAX (0x7D) + +#define AW_PID_2055_REG_NONE_ACCESS (0) +#define AW_PID_2055_REG_RD_ACCESS (1 << 0) +#define AW_PID_2055_REG_WR_ACCESS (1 << 1) + +const unsigned char aw_pid_2055_reg_access[AW_PID_2055_REG_MAX] = { + [AW_PID_2055_ID_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_SYSST_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_SYSINT_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_SYSINTM_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_SYSCTRL_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_SYSCTRL2_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_I2SCTRL1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_I2SCTRL2_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_I2SCTRL3_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DACCFG1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DACCFG2_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DACCFG3_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DACCFG4_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DACCFG5_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DACCFG6_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DACCFG7_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DACCFG8_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_PWMCTRL1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_PWMCTRL2_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_PWMCTRL3_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_PWMCTRL4_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_PWMCTRL5_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_I2SCFG1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DBGCTRL_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DITHERCFG1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DACST_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_VBAT_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_TEMP_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_PVDD_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_BOPST_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_I2SINT_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_I2SCAPCNT_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_ANASTA1_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_ANASTA2_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_ANASTA3_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_DSMCFG1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DSMCFG2_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DSMCFG3_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DSMCFG4_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DSMCFG5_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DSMCFG6_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DSMCFG7_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_DSMCFG8_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_TESTIN_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_TESTOUT_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_SADCCTRL1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_SADCCTRL2_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_SADCCTRL3_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_SADCCTRL4_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_SADCCTRL5_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_SADCCTRL6_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_PLLCTRL1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_PLLCTRL2_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_PLLCTRL3_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_CDACTRL1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_CDACTRL2_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_CDACTRL3_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_BSTCTRL1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_BSTCTRL2_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_BSTCTRL3_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_BSTCTRL4_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_BSTCTRL5_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_BSTCTRL6_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_BSTCTRL7_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_BSTCTRL8_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_CPCTRL1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_TESTCTRL1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_TESTCTRL2_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_EFCTRL1_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_EFCTRL2_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_EFWH_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_EFWL_REG] = (AW_PID_2055_REG_RD_ACCESS | AW_PID_2055_REG_WR_ACCESS), + [AW_PID_2055_EFRH2_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_EFRL2_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_EFRH1_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_EFRL1_REG] = (AW_PID_2055_REG_RD_ACCESS), + [AW_PID_2055_TM_REG] = (AW_PID_2055_REG_NONE_ACCESS), +}; + +/* detail information of registers begin */ +/* ID (0x00) detail */ +/* IDCODE bit 15:0 (ID 0x00) */ +#define AW_PID_2055_IDCODE_START_BIT (0) +#define AW_PID_2055_IDCODE_BITS_LEN (16) +#define AW_PID_2055_IDCODE_MASK \ + (~(((1< + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_PID_2055A_REG_H__ +#define __AW882XX_PID_2055A_REG_H__ + +#define AW_PID_2055A_MONITOR_FILE "aw882xx_pid_2055a_monitor.bin" + +/* registers list */ +#define AW_PID_2055A_ID_REG (0x00) +#define AW_PID_2055A_SYSST_REG (0x01) +#define AW_PID_2055A_SYSINT_REG (0x02) +#define AW_PID_2055A_SYSINTM_REG (0x03) +#define AW_PID_2055A_SYSCTRL_REG (0x04) +#define AW_PID_2055A_SYSCTRL2_REG (0x05) +#define AW_PID_2055A_I2SCTRL1_REG (0x06) +#define AW_PID_2055A_I2SCTRL2_REG (0x07) +#define AW_PID_2055A_DACCFG1_REG (0x08) +#define AW_PID_2055A_DACCFG2_REG (0x09) +#define AW_PID_2055A_DACCFG3_REG (0x0A) +#define AW_PID_2055A_DACCFG4_REG (0x0B) +#define AW_PID_2055A_DACCFG5_REG (0x0C) +#define AW_PID_2055A_DACCFG6_REG (0x0D) +#define AW_PID_2055A_DACCFG7_REG (0x0E) +#define AW_PID_2055A_DACCFG8_REG (0x0F) +#define AW_PID_2055A_PWMCTRL1_REG (0x10) +#define AW_PID_2055A_PWMCTRL2_REG (0x11) +#define AW_PID_2055A_PWMCTRL3_REG (0x12) +#define AW_PID_2055A_I2SCFG1_REG (0x13) +#define AW_PID_2055A_DBGCTRL_REG (0x14) +#define AW_PID_2055A_DITHERCFG1_REG (0x15) +#define AW_PID_2055A_DITHERCFG2_REG (0x16) +#define AW_PID_2055A_DITHERCFG3_REG (0x17) +#define AW_PID_2055A_DACST_REG (0x20) +#define AW_PID_2055A_I2SINT_REG (0x21) +#define AW_PID_2055A_I2SCAPCNT_REG (0x22) +#define AW_PID_2055A_ANASTA1_REG (0x23) +#define AW_PID_2055A_ANASTA2_REG (0x24) +#define AW_PID_2055A_ANASTA3_REG (0x25) +#define AW_PID_2055A_DSMCFG1_REG (0x30) +#define AW_PID_2055A_DSMCFG2_REG (0x31) +#define AW_PID_2055A_DSMCFG3_REG (0x32) +#define AW_PID_2055A_DSMCFG4_REG (0x33) +#define AW_PID_2055A_DSMCFG5_REG (0x34) +#define AW_PID_2055A_DSMCFG6_REG (0x35) +#define AW_PID_2055A_DSMCFG7_REG (0x36) +#define AW_PID_2055A_DSMCFG8_REG (0x37) +#define AW_PID_2055A_TESTIN_REG (0x38) +#define AW_PID_2055A_TESTOUT_REG (0x39) +#define AW_PID_2055A_PLLCTRL1_REG (0x50) +#define AW_PID_2055A_PLLCTRL2_REG (0x51) +#define AW_PID_2055A_PLLCTRL3_REG (0x52) +#define AW_PID_2055A_CDACTRL1_REG (0x53) +#define AW_PID_2055A_CDACTRL2_REG (0x54) +#define AW_PID_2055A_BSTCTRL1_REG (0x60) +#define AW_PID_2055A_BSTCTRL2_REG (0x61) +#define AW_PID_2055A_BSTCTRL3_REG (0x62) +#define AW_PID_2055A_BSTCTRL4_REG (0x63) +#define AW_PID_2055A_BSTCTRL5_REG (0x64) +#define AW_PID_2055A_BSTCTRL6_REG (0x65) +#define AW_PID_2055A_BSTCTRL7_REG (0x66) +#define AW_PID_2055A_BSTCRTL8_REG (0x67) +#define AW_PID_2055A_CPCTRL1_REG (0x68) +#define AW_PID_2055A_TESTCTRL1_REG (0x70) +#define AW_PID_2055A_TESTCTRL2_REG (0x71) +#define AW_PID_2055A_EFCTRL1_REG (0x72) +#define AW_PID_2055A_EFCTRL2_REG (0x73) +#define AW_PID_2055A_EFWH_REG (0x74) +#define AW_PID_2055A_EFWL_REG (0x75) +#define AW_PID_2055A_EFRH1_REG (0x76) +#define AW_PID_2055A_EFRH2_REG (0x77) +#define AW_PID_2055A_EFRL1_REG (0x78) +#define AW_PID_2055A_EFRL2_REG (0x79) +#define AW_PID_2055A_TM_REG (0x7C) + +/******************************************** + * Register Access + *******************************************/ +#define AW_PID_2055A_REG_MAX (0x7D) + +#define AW_PID_2055A_REG_NONE_ACCESS (0) +#define AW_PID_2055A_REG_RD_ACCESS (1 << 0) +#define AW_PID_2055A_REG_WR_ACCESS (1 << 1) + +const unsigned char aw_pid_2055a_reg_access[AW_PID_2055A_REG_MAX] = { + [AW_PID_2055A_ID_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_SYSST_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_SYSINT_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_SYSINTM_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_SYSCTRL_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_SYSCTRL2_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_I2SCTRL1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_I2SCTRL2_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DACCFG1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DACCFG2_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DACCFG3_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DACCFG4_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DACCFG5_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DACCFG6_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DACCFG7_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DACCFG8_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_PWMCTRL1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_PWMCTRL2_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_PWMCTRL3_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_I2SCFG1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DBGCTRL_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DITHERCFG1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DITHERCFG2_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DITHERCFG3_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DACST_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_I2SINT_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_I2SCAPCNT_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_ANASTA1_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_ANASTA2_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_ANASTA3_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_DSMCFG1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DSMCFG2_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DSMCFG3_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DSMCFG4_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DSMCFG5_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DSMCFG6_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DSMCFG7_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_DSMCFG8_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_TESTIN_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_TESTOUT_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_PLLCTRL1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_PLLCTRL2_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_PLLCTRL3_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_CDACTRL1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_CDACTRL2_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_BSTCTRL1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_BSTCTRL2_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_BSTCTRL3_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_BSTCTRL4_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_BSTCTRL5_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_BSTCTRL6_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_BSTCTRL7_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_BSTCRTL8_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_CPCTRL1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_TESTCTRL1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_TESTCTRL2_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_EFCTRL1_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_EFCTRL2_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_EFWH_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_EFWL_REG] = (AW_PID_2055A_REG_RD_ACCESS | AW_PID_2055A_REG_WR_ACCESS), + [AW_PID_2055A_EFRH1_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_EFRH2_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_EFRL1_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_EFRL2_REG] = (AW_PID_2055A_REG_RD_ACCESS), + [AW_PID_2055A_TM_REG] = (AW_PID_2055A_REG_NONE_ACCESS), +}; + +/* detail information of registers begin */ +/* ID (0x00) detail */ +/* IDCODE bit 15:0 (ID 0x00) */ +#define AW_PID_2055A_IDCODE_START_BIT (0) +#define AW_PID_2055A_IDCODE_BITS_LEN (16) +#define AW_PID_2055A_IDCODE_MASK \ + (~(((1< + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_PID_2071_REG_H__ +#define __AW882XX_PID_2071_REG_H__ + +#define AW_PID_2071_MONITOR_FILE "aw882xx_pid_2071_monitor.bin" + +/* registers list */ +#define AW_PID_2071_ID_REG (0x00) +#define AW_PID_2071_SYSST_REG (0x01) +#define AW_PID_2071_SYSINT_REG (0x02) +#define AW_PID_2071_SYSINTM_REG (0x03) +#define AW_PID_2071_SYSCTRL_REG (0x04) +#define AW_PID_2071_SYSCTRL2_REG (0x05) +#define AW_PID_2071_I2SCTRL_REG (0x06) +#define AW_PID_2071_I2SCFG1_REG (0x07) +#define AW_PID_2071_I2SCFG2_REG (0x08) +#define AW_PID_2071_HAGCCFG1_REG (0x09) +#define AW_PID_2071_HAGCCFG2_REG (0x0A) +#define AW_PID_2071_HAGCCFG3_REG (0x0B) +#define AW_PID_2071_HAGCCFG4_REG (0x0C) +#define AW_PID_2071_HAGCCFG5_REG (0x0D) +#define AW_PID_2071_HAGCCFG6_REG (0x0E) +#define AW_PID_2071_HAGCCFG7_REG (0x0F) +#define AW_PID_2071_HAGCST_REG (0x10) +#define AW_PID_2071_PRODID_REG (0x11) +#define AW_PID_2071_VBAT_REG (0x12) +#define AW_PID_2071_TEMP_REG (0x13) +#define AW_PID_2071_PVDD_REG (0x14) +#define AW_PID_2071_HAGCCFG8_REG (0x15) +#define AW_PID_2071_DBGCTRL_REG (0x20) +#define AW_PID_2071_I2SINT_REG (0x21) +#define AW_PID_2071_I2SCAPCNT_REG (0x22) +#define AW_PID_2071_ANASTA1_REG (0x23) +#define AW_PID_2071_ANASTA2_REG (0x24) +#define AW_PID_2071_ANASTA3_REG (0x25) +#define AW_PID_2071_ANASTA4_REG (0x26) +#define AW_PID_2071_DSMCFG8_REG (0x37) +#define AW_PID_2071_TESTIN_REG (0x38) +#define AW_PID_2071_TESTOUT_REG (0x39) +#define AW_PID_2071_SADCCTRL2_REG (0x3A) +#define AW_PID_2071_SADCCTRL3_REG (0x3B) +#define AW_PID_2071_SADCCTRL4_REG (0x3C) +#define AW_PID_2071_VSNCTRL1_REG (0x50) +#define AW_PID_2071_ISNCTRL1_REG (0x52) +#define AW_PID_2071_ISNCTRL2_REG (0x53) +#define AW_PID_2071_VTMCTRL1_REG (0x54) +#define AW_PID_2071_VTMCTRL2_REG (0x55) +#define AW_PID_2071_VTMCTRL3_REG (0x56) +#define AW_PID_2071_ISNDAT_REG (0x57) +#define AW_PID_2071_VSNDAT_REG (0x58) +#define AW_PID_2071_PWMCTRL_REG (0x59) +#define AW_PID_2071_PWMCTRL2_REG (0x5A) +#define AW_PID_2071_PWMCTRL3_REG (0x5B) +#define AW_PID_2071_VCALDAT_REG (0x5C) +#define AW_PID_2071_BSTCTRL1_REG (0x60) +#define AW_PID_2071_BSTCTRL2_REG (0x61) +#define AW_PID_2071_BSTCTRL3_REG (0x62) +#define AW_PID_2071_BSTDBG1_REG (0x63) +#define AW_PID_2071_BSTDBG2_REG (0x64) +#define AW_PID_2071_BSTDBG3_REG (0x65) +#define AW_PID_2071_PLLCTRL1_REG (0x66) +#define AW_PID_2071_PLLCTRL2_REG (0x67) +#define AW_PID_2071_PLLCTRL3_REG (0x68) +#define AW_PID_2071_CDACTRL1_REG (0x69) +#define AW_PID_2071_CDACTRL2_REG (0x6A) +#define AW_PID_2071_SADCCTRL_REG (0x6B) +#define AW_PID_2071_BSTCTRL8_REG (0x6C) +#define AW_PID_2071_DITHERCFG1_REG (0x6D) +#define AW_PID_2071_TESTCTRL1_REG (0x70) +#define AW_PID_2071_TESTCTRL2_REG (0x71) +#define AW_PID_2071_EFCTRL1_REG (0x72) +#define AW_PID_2071_EFCTRL2_REG (0x73) +#define AW_PID_2071_EFWH_REG (0x74) +#define AW_PID_2071_EFWM2_REG (0x75) +#define AW_PID_2071_EFWM1_REG (0x76) +#define AW_PID_2071_EFWL_REG (0x77) +#define AW_PID_2071_EFRH_REG (0x78) +#define AW_PID_2071_EFRM2_REG (0x79) +#define AW_PID_2071_EFRM1_REG (0x7A) +#define AW_PID_2071_EFRL_REG (0x7B) +#define AW_PID_2071_TESTDET_REG (0x7C) +#define AW_PID_2071_TM_REG (0x7D) + +/******************************************** + * Register Access + *******************************************/ +#define AW_PID_2071_REG_MAX (0x7E) + +#define AW_PID_2071_REG_NONE_ACCESS (0) +#define AW_PID_2071_REG_RD_ACCESS (1 << 0) +#define AW_PID_2071_REG_WR_ACCESS (1 << 1) + +const unsigned char aw_pid_2071_reg_access[AW_PID_2071_REG_MAX] = { + [AW_PID_2071_ID_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_SYSST_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_SYSINT_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_SYSINTM_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_SYSCTRL_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_SYSCTRL2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_I2SCTRL_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_I2SCFG1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_I2SCFG2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_HAGCCFG1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_HAGCCFG2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_HAGCCFG3_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_HAGCCFG4_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_HAGCCFG5_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_HAGCCFG6_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_HAGCCFG7_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_HAGCST_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_PRODID_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_VBAT_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_TEMP_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_PVDD_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_HAGCCFG8_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_DBGCTRL_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_I2SINT_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_I2SCAPCNT_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_ANASTA1_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_ANASTA2_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_ANASTA3_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_ANASTA4_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_DSMCFG8_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_TESTIN_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_TESTOUT_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_SADCCTRL2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_SADCCTRL3_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_SADCCTRL4_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_VSNCTRL1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_ISNCTRL1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_ISNCTRL2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_VTMCTRL1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_VTMCTRL2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_VTMCTRL3_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_ISNDAT_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_VSNDAT_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_PWMCTRL_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_PWMCTRL2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_PWMCTRL3_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_VCALDAT_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_BSTCTRL1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_BSTCTRL2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_BSTCTRL3_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_BSTDBG1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_BSTDBG2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_BSTDBG3_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_PLLCTRL1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_PLLCTRL2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_PLLCTRL3_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_CDACTRL1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_CDACTRL2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_SADCCTRL_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_BSTCTRL8_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_DITHERCFG1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_TESTCTRL1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_TESTCTRL2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_EFCTRL1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_EFCTRL2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_EFWH_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_EFWM2_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_EFWM1_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_EFWL_REG] = (AW_PID_2071_REG_RD_ACCESS | AW_PID_2071_REG_WR_ACCESS), + [AW_PID_2071_EFRH_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_EFRM2_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_EFRM1_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_EFRL_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_TESTDET_REG] = (AW_PID_2071_REG_RD_ACCESS), + [AW_PID_2071_TM_REG] = (AW_PID_2071_REG_NONE_ACCESS), +}; + +/* detail information of registers begin */ +/* ID (0x00) detail */ +/* IDCODE bit 15:0 (ID 0x00) */ +#define AW_PID_2071_IDCODE_START_BIT (0) +#define AW_PID_2071_IDCODE_BITS_LEN (16) +#define AW_PID_2071_IDCODE_MASK \ + (~(((1< + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_PID_2113_REG_H__ +#define __AW882XX_PID_2113_REG_H__ + +#define AW_PID_2113_MONITOR_FILE "aw882xx_pid_2113_monitor.bin" + +/* registers list */ +#define AW_PID_2113_ID_REG (0x00) +#define AW_PID_2113_SYSST_REG (0x01) +#define AW_PID_2113_SYSINT_REG (0x02) +#define AW_PID_2113_SYSINTM_REG (0x03) +#define AW_PID_2113_SYSCTRL_REG (0x04) +#define AW_PID_2113_SYSCTRL2_REG (0x05) +#define AW_PID_2113_I2SCTRL1_REG (0x06) +#define AW_PID_2113_I2SCTRL2_REG (0x07) +#define AW_PID_2113_I2SCTRL3_REG (0x08) +#define AW_PID_2113_DACCFG1_REG (0x09) +#define AW_PID_2113_DACCFG2_REG (0x0A) +#define AW_PID_2113_DACCFG3_REG (0x0B) +#define AW_PID_2113_DACCFG4_REG (0x0C) +#define AW_PID_2113_DACCFG5_REG (0x0D) +#define AW_PID_2113_DACCFG6_REG (0x0E) +#define AW_PID_2113_DACCFG7_REG (0x0F) +#define AW_PID_2113_DACCFG8_REG (0x10) +#define AW_PID_2113_PWMCTRL1_REG (0x11) +#define AW_PID_2113_PWMCTRL2_REG (0x12) +#define AW_PID_2113_I2SCFG1_REG (0x13) +#define AW_PID_2113_DBGCTRL_REG (0x14) +#define AW_PID_2113_DACCFG9_REG (0x15) +#define AW_PID_2113_DACCFG10_REG (0x16) +#define AW_PID_2113_DACST_REG (0x20) +#define AW_PID_2113_VBAT_REG (0x21) +#define AW_PID_2113_TEMP_REG (0x22) +#define AW_PID_2113_PVDD_REG (0x23) +#define AW_PID_2113_ISNDAT_REG (0x24) +#define AW_PID_2113_VSNDAT_REG (0x25) +#define AW_PID_2113_I2SINT_REG (0x26) +#define AW_PID_2113_I2SCAPCNT_REG (0x27) +#define AW_PID_2113_ANASTA1_REG (0x28) +#define AW_PID_2113_ANASTA2_REG (0x29) +#define AW_PID_2113_ANASTA3_REG (0x2A) +#define AW_PID_2113_TESTDET_REG (0x2B) +#define AW_PID_2113_DSMCFG1_REG (0x30) +#define AW_PID_2113_DSMCFG2_REG (0x31) +#define AW_PID_2113_DSMCFG3_REG (0x32) +#define AW_PID_2113_DSMCFG4_REG (0x33) +#define AW_PID_2113_DSMCFG5_REG (0x34) +#define AW_PID_2113_DSMCFG6_REG (0x35) +#define AW_PID_2113_DSMCFG7_REG (0x36) +#define AW_PID_2113_DSMCFG8_REG (0x37) +#define AW_PID_2113_TESTIN_REG (0x38) +#define AW_PID_2113_TESTOUT_REG (0x39) +#define AW_PID_2113_SADCCTRL1_REG (0x3A) +#define AW_PID_2113_SADCCTRL2_REG (0x3B) +#define AW_PID_2113_SADCCTRL3_REG (0x3C) +#define AW_PID_2113_SADCCTRL4_REG (0x3D) +#define AW_PID_2113_SADCCTRL5_REG (0x3E) +#define AW_PID_2113_SADCCTRL6_REG (0x3F) +#define AW_PID_2113_SADCCTRL7_REG (0x40) +#define AW_PID_2113_VSNTM1_REG (0x50) +#define AW_PID_2113_VSNTM2_REG (0x51) +#define AW_PID_2113_ISNCTRL1_REG (0x52) +#define AW_PID_2113_ISNCTRL2_REG (0x53) +#define AW_PID_2113_PLLCTRL1_REG (0x54) +#define AW_PID_2113_PLLCTRL2_REG (0x55) +#define AW_PID_2113_PLLCTRL3_REG (0x56) +#define AW_PID_2113_CDACTRL1_REG (0x57) +#define AW_PID_2113_CDACTRL2_REG (0x58) +#define AW_PID_2113_DITHERCFG1_REG (0x59) +#define AW_PID_2113_DITHERCFG2_REG (0x5A) +#define AW_PID_2113_DITHERCFG3_REG (0x5B) +#define AW_PID_2113_CPCTRL_REG (0x5C) +#define AW_PID_2113_BSTCTRL1_REG (0x60) +#define AW_PID_2113_BSTCTRL2_REG (0x61) +#define AW_PID_2113_BSTCTRL3_REG (0x62) +#define AW_PID_2113_BSTCTRL4_REG (0x63) +#define AW_PID_2113_BSTCTRL5_REG (0x64) +#define AW_PID_2113_BSTCTRL6_REG (0x65) +#define AW_PID_2113_BSTCTRL7_REG (0x66) +#define AW_PID_2113_BSTCTRL8_REG (0x67) +#define AW_PID_2113_BSTCTRL9_REG (0x68) +#define AW_PID_2113_TM_REG (0x6F) +#define AW_PID_2113_TESTCTRL1_REG (0x70) +#define AW_PID_2113_TESTCTRL2_REG (0x71) +#define AW_PID_2113_EFCTRL1_REG (0x72) +#define AW_PID_2113_EFCTRL2_REG (0x73) +#define AW_PID_2113_EFWH_REG (0x74) +#define AW_PID_2113_EFWM2_REG (0x75) +#define AW_PID_2113_EFWM1_REG (0x76) +#define AW_PID_2113_EFWL_REG (0x77) +#define AW_PID_2113_EFRH4_REG (0x78) +#define AW_PID_2113_EFRH3_REG (0x79) +#define AW_PID_2113_EFRH2_REG (0x7A) +#define AW_PID_2113_EFRH1_REG (0x7B) +#define AW_PID_2113_EFRL4_REG (0x7C) +#define AW_PID_2113_EFRL3_REG (0x7D) +#define AW_PID_2113_EFRL2_REG (0x7E) +#define AW_PID_2113_EFRL1_REG (0x7F) + +/******************************************** + * Register Access + *******************************************/ +#define AW_PID_2113_REG_MAX (0x80) + +#define AW_PID_2113_REG_NONE_ACCESS (0) +#define AW_PID_2113_REG_RD_ACCESS (1 << 0) +#define AW_PID_2113_REG_WR_ACCESS (1 << 1) + +const unsigned char aw_pid_2113_reg_access[AW_PID_2113_REG_MAX] = { + [AW_PID_2113_ID_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_SYSST_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_SYSINT_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_SYSINTM_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_SYSCTRL_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_SYSCTRL2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_I2SCTRL1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_I2SCTRL2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_I2SCTRL3_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DACCFG1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DACCFG2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DACCFG3_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DACCFG4_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DACCFG5_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DACCFG6_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DACCFG7_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DACCFG8_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_PWMCTRL1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_PWMCTRL2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_I2SCFG1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DBGCTRL_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DACCFG9_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DACCFG10_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DACST_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_VBAT_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_TEMP_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_PVDD_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_ISNDAT_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_VSNDAT_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_I2SINT_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_I2SCAPCNT_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_ANASTA1_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_ANASTA2_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_ANASTA3_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_TESTDET_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_DSMCFG1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DSMCFG2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DSMCFG3_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DSMCFG4_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DSMCFG5_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DSMCFG6_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DSMCFG7_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DSMCFG8_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_TESTIN_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_TESTOUT_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_SADCCTRL1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_SADCCTRL2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_SADCCTRL3_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_SADCCTRL4_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_SADCCTRL5_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_SADCCTRL6_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_SADCCTRL7_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_VSNTM1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_VSNTM2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_ISNCTRL1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_ISNCTRL2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_PLLCTRL1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_PLLCTRL2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_PLLCTRL3_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_CDACTRL1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_CDACTRL2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DITHERCFG1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DITHERCFG2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_DITHERCFG3_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_CPCTRL_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_BSTCTRL1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_BSTCTRL2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_BSTCTRL3_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_BSTCTRL4_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_BSTCTRL5_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_BSTCTRL6_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_BSTCTRL7_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_BSTCTRL8_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_BSTCTRL9_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_TM_REG] = (AW_PID_2113_REG_NONE_ACCESS), + [AW_PID_2113_TESTCTRL1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_TESTCTRL2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_EFCTRL1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_EFCTRL2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_EFWH_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_EFWM2_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_EFWM1_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_EFWL_REG] = (AW_PID_2113_REG_RD_ACCESS | AW_PID_2113_REG_WR_ACCESS), + [AW_PID_2113_EFRH4_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_EFRH3_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_EFRH2_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_EFRH1_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_EFRL4_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_EFRL3_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_EFRL2_REG] = (AW_PID_2113_REG_RD_ACCESS), + [AW_PID_2113_EFRL1_REG] = (AW_PID_2113_REG_RD_ACCESS), +}; + +/* detail information of registers begin */ +/* ID (0x00) detail */ +/* IDCODE bit 15:0 (ID 0x00) */ +#define AW_PID_2113_IDCODE_START_BIT (0) +#define AW_PID_2113_IDCODE_BITS_LEN (16) +#define AW_PID_2113_IDCODE_MASK \ + (~(((1< + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_PID_2308_REG_H__ +#define __AW882XX_PID_2308_REG_H__ + +#define AW_PID_2308_MONITOR_FILE "aw882xx_pid_2308_monitor.bin" + +/* registers list */ +#define AW_PID_2308_ID_REG (0x00) +#define AW_PID_2308_SYSST_REG (0x01) +#define AW_PID_2308_SYSINT_REG (0x02) +#define AW_PID_2308_SYSINTM_REG (0x03) +#define AW_PID_2308_SYSCTRL_REG (0x04) +#define AW_PID_2308_SYSCTRL2_REG (0x05) +#define AW_PID_2308_I2SCTRL1_REG (0x06) +#define AW_PID_2308_I2SCTRL2_REG (0x07) +#define AW_PID_2308_I2SCTRL3_REG (0x08) +#define AW_PID_2308_DACCFG1_REG (0x09) +#define AW_PID_2308_DACCFG2_REG (0x0A) +#define AW_PID_2308_DACCFG3_REG (0x0B) +#define AW_PID_2308_DACCFG4_REG (0x0C) +#define AW_PID_2308_DACCFG5_REG (0x0D) +#define AW_PID_2308_DACCFG6_REG (0x0E) +#define AW_PID_2308_DACCFG7_REG (0x0F) +#define AW_PID_2308_DACCFG8_REG (0x10) +#define AW_PID_2308_PWMCTRL1_REG (0x11) +#define AW_PID_2308_PWMCTRL2_REG (0x12) +#define AW_PID_2308_I2SCFG1_REG (0x13) +#define AW_PID_2308_MPDCFG5_REG (0x14) +#define AW_PID_2308_BOPCTRL1_REG (0x15) +#define AW_PID_2308_BOPCTRL2_REG (0x16) +#define AW_PID_2308_BOPCTRL3_REG (0x17) +#define AW_PID_2308_BOPCTRL4_REG (0x18) +#define AW_PID_2308_BOPCTRL5_REG (0x19) +#define AW_PID_2308_BOPCTRL6_REG (0x1A) +#define AW_PID_2308_BOPCTRL7_REG (0x1B) +#define AW_PID_2308_BOPCTRL8_REG (0x1C) +#define AW_PID_2308_BOPCTRL9_REG (0x1D) +#define AW_PID_2308_BOPCTRL10_REG (0x1E) +#define AW_PID_2308_DBGCTRL_REG (0x1F) +#define AW_PID_2308_DACST_REG (0x20) +#define AW_PID_2308_VBAT_REG (0x21) +#define AW_PID_2308_TEMP_REG (0x22) +#define AW_PID_2308_PVDD_REG (0x23) +#define AW_PID_2308_ISNDAT_REG (0x24) +#define AW_PID_2308_VSNDAT_REG (0x25) +#define AW_PID_2308_I2SINT_REG (0x26) +#define AW_PID_2308_I2SCAPCNT_REG (0x27) +#define AW_PID_2308_TESTDET_REG (0x28) +#define AW_PID_2308_ANASTA1_REG (0x29) +#define AW_PID_2308_ANASTA2_REG (0x2A) +#define AW_PID_2308_ANASTA3_REG (0x2B) +#define AW_PID_2308_ANASTA4_REG (0x2C) +#define AW_PID_2308_ANASTA5_REG (0x2D) +#define AW_PID_2308_TESTOUT_REG (0x2E) +#define AW_PID_2308_DC_DOUT_REG (0x2F) +#define AW_PID_2308_DSMCFG1_REG (0x30) +#define AW_PID_2308_DSMCFG2_REG (0x31) +#define AW_PID_2308_DSMCFG3_REG (0x32) +#define AW_PID_2308_DSMCFG4_REG (0x33) +#define AW_PID_2308_DSMCFG5_REG (0x34) +#define AW_PID_2308_DSMCFG6_REG (0x35) +#define AW_PID_2308_DSMCFG7_REG (0x36) +#define AW_PID_2308_DSMCFG8_REG (0x37) +#define AW_PID_2308_TESTIN_REG (0x38) +#define AW_PID_2308_DETCTRL1_REG (0x3A) +#define AW_PID_2308_DETCTRL2_REG (0x3B) +#define AW_PID_2308_MPDCFG1_REG (0x3C) +#define AW_PID_2308_MPDCFG2_REG (0x3D) +#define AW_PID_2308_MPDCFG3_REG (0x3E) +#define AW_PID_2308_MPDCFG4_REG (0x3F) +#define AW_PID_2308_ISNTM1_REG (0x50) +#define AW_PID_2308_ISNCTRL3_REG (0x51) +#define AW_PID_2308_VSNTM1_REG (0x52) +#define AW_PID_2308_VSNTM2_REG (0x53) +#define AW_PID_2308_ISNCTRL1_REG (0x54) +#define AW_PID_2308_ISNCTRL2_REG (0x55) +#define AW_PID_2308_PLLCTRL1_REG (0x56) +#define AW_PID_2308_PLLCTRL2_REG (0x57) +#define AW_PID_2308_PLLCTRL3_REG (0x58) +#define AW_PID_2308_PSMCTRL1_REG (0x59) +#define AW_PID_2308_PSMCTRL2_REG (0x5A) +#define AW_PID_2308_PSMCTRL3_REG (0x5B) +#define AW_PID_2308_NGCTRL1_REG (0x5C) +#define AW_PID_2308_NGCTRL2_REG (0x5D) +#define AW_PID_2308_NGCTRL3_REG (0x5E) +#define AW_PID_2308_CPCTRL_REG (0x5F) +#define AW_PID_2308_BSTCTRL1_REG (0x60) +#define AW_PID_2308_BSTCTRL2_REG (0x61) +#define AW_PID_2308_BSTCTRL3_REG (0x62) +#define AW_PID_2308_BSTCTRL4_REG (0x63) +#define AW_PID_2308_BSTCTRL5_REG (0x64) +#define AW_PID_2308_BSTCTRL6_REG (0x65) +#define AW_PID_2308_BSTCTRL7_REG (0x66) +#define AW_PID_2308_BSTCTRL8_REG (0x67) +#define AW_PID_2308_BSTCTRL9_REG (0x68) +#define AW_PID_2308_CDACTRL1_REG (0x69) +#define AW_PID_2308_CDACTRL2_REG (0x6A) +#define AW_PID_2308_CDACTRL3_REG (0x6B) +#define AW_PID_2308_CDACTRL4_REG (0x6C) +#define AW_PID_2308_CDACTRL5_REG (0x6D) +#define AW_PID_2308_TM2_REG (0x6E) +#define AW_PID_2308_TM_REG (0x6F) +#define AW_PID_2308_TESTCTRL1_REG (0x70) +#define AW_PID_2308_TESTCTRL2_REG (0x71) +#define AW_PID_2308_EFCTRL1_REG (0x72) +#define AW_PID_2308_EFCTRL2_REG (0x73) +#define AW_PID_2308_EFWH_REG (0x74) +#define AW_PID_2308_EFWM2_REG (0x75) +#define AW_PID_2308_EFWM1_REG (0x76) +#define AW_PID_2308_EFWL_REG (0x77) +#define AW_PID_2308_EFRH4_REG (0x78) +#define AW_PID_2308_EFRH3_REG (0x79) +#define AW_PID_2308_EFRH2_REG (0x7A) +#define AW_PID_2308_EFRH1_REG (0x7B) +#define AW_PID_2308_EFRL4_REG (0x7C) +#define AW_PID_2308_EFRL3_REG (0x7D) +#define AW_PID_2308_EFRL2_REG (0x7E) +#define AW_PID_2308_EFRL1_REG (0x7F) + +/******************************************** + * Register Access + *******************************************/ +#define AW_PID_2308_REG_MAX (0x80) + +#define REG_NONE_ACCESS (0) +#define REG_RD_ACCESS (1 << 0) +#define REG_WR_ACCESS (1 << 1) + +const unsigned char aw_pid_2308_reg_access[AW_PID_2308_REG_MAX] = { + [AW_PID_2308_ID_REG] = (REG_RD_ACCESS), + [AW_PID_2308_SYSST_REG] = (REG_RD_ACCESS), + [AW_PID_2308_SYSINT_REG] = (REG_RD_ACCESS), + [AW_PID_2308_SYSINTM_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_SYSCTRL_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_SYSCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_I2SCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_I2SCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_I2SCTRL3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DACCFG1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DACCFG2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DACCFG3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DACCFG4_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DACCFG5_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DACCFG6_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DACCFG7_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DACCFG8_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_PWMCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_PWMCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_I2SCFG1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_MPDCFG5_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BOPCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BOPCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BOPCTRL3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BOPCTRL4_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BOPCTRL5_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BOPCTRL6_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BOPCTRL7_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BOPCTRL8_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BOPCTRL9_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BOPCTRL10_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DBGCTRL_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DACST_REG] = (REG_RD_ACCESS), + [AW_PID_2308_VBAT_REG] = (REG_RD_ACCESS), + [AW_PID_2308_TEMP_REG] = (REG_RD_ACCESS), + [AW_PID_2308_PVDD_REG] = (REG_RD_ACCESS), + [AW_PID_2308_ISNDAT_REG] = (REG_RD_ACCESS), + [AW_PID_2308_VSNDAT_REG] = (REG_RD_ACCESS), + [AW_PID_2308_I2SINT_REG] = (REG_RD_ACCESS), + [AW_PID_2308_I2SCAPCNT_REG] = (REG_RD_ACCESS), + [AW_PID_2308_TESTDET_REG] = (REG_RD_ACCESS), + [AW_PID_2308_ANASTA1_REG] = (REG_RD_ACCESS), + [AW_PID_2308_ANASTA2_REG] = (REG_RD_ACCESS), + [AW_PID_2308_ANASTA3_REG] = (REG_RD_ACCESS), + [AW_PID_2308_ANASTA4_REG] = (REG_RD_ACCESS), + [AW_PID_2308_ANASTA5_REG] = (REG_RD_ACCESS), + [AW_PID_2308_TESTOUT_REG] = (REG_RD_ACCESS), + [AW_PID_2308_DC_DOUT_REG] = (REG_RD_ACCESS), + [AW_PID_2308_DSMCFG1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DSMCFG2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DSMCFG3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DSMCFG4_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DSMCFG5_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DSMCFG6_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DSMCFG7_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DSMCFG8_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_TESTIN_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DETCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_DETCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_MPDCFG1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_MPDCFG2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_MPDCFG3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_MPDCFG4_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_ISNTM1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_ISNCTRL3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_VSNTM1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_VSNTM2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_ISNCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_ISNCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_PLLCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_PLLCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_PLLCTRL3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_PSMCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_PSMCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_PSMCTRL3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_NGCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_NGCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_NGCTRL3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_CPCTRL_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BSTCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BSTCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BSTCTRL3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BSTCTRL4_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BSTCTRL5_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BSTCTRL6_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BSTCTRL7_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BSTCTRL8_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_BSTCTRL9_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_CDACTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_CDACTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_CDACTRL3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_CDACTRL4_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_CDACTRL5_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_TM2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_TM_REG] = (REG_NONE_ACCESS), + [AW_PID_2308_TESTCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_TESTCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_EFCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_EFCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_EFWH_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_EFWM2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_EFWM1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_EFWL_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW_PID_2308_EFRH4_REG] = (REG_RD_ACCESS), + [AW_PID_2308_EFRH3_REG] = (REG_RD_ACCESS), + [AW_PID_2308_EFRH2_REG] = (REG_RD_ACCESS), + [AW_PID_2308_EFRH1_REG] = (REG_RD_ACCESS), + [AW_PID_2308_EFRL4_REG] = (REG_RD_ACCESS), + [AW_PID_2308_EFRL3_REG] = (REG_RD_ACCESS), + [AW_PID_2308_EFRL2_REG] = (REG_RD_ACCESS), + [AW_PID_2308_EFRL1_REG] = (REG_RD_ACCESS), +}; + +/******************************************** + * Volume Coefficient + *******************************************/ +#define AW_PID_2308_VOL_STEP (64) +#define AW_PID_2308_MUTE_VOL (1023) + +/* detail information of registers begin */ +/* ID (0x00) detail */ +/* IDCODE bit 15:0 (ID 0x00) */ +#define AW_PID_2308_IDCODE_START_BIT (0) +#define AW_PID_2308_IDCODE_BITS_LEN (16) +#define AW_PID_2308_IDCODE_MASK \ + (~(((1< + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aw882xx_log.h" +#include "aw882xx.h" +#include "aw882xx_spin.h" + +static unsigned int g_spin_mode; +static unsigned int g_spin_value; + +static DEFINE_MUTEX(g_spin_lock); + +static int aw_dev_set_channal_mode(struct aw_device *aw_dev, + struct aw_spin_desc spin_desc, uint32_t spin_val) +{ + int ret; + struct aw_reg_ch *rx_desc = &spin_desc.rx_desc; + + ret = aw_dev->ops.aw_i2c_write_bits(aw_dev, rx_desc->reg, rx_desc->mask, + spin_desc.spin_table[spin_val].rx_val); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "set rx failed"); + return ret; + } + + aw_dev_dbg(aw_dev->dev, "set channel mode done!"); + return 0; +} + +static int aw_reg_write_spin(struct aw_device *aw_dev, + uint32_t spin_val, bool mixer_en) +{ + int ret; + struct aw_device *local_dev = NULL; + struct list_head *pos = NULL; + struct list_head *dev_list = NULL; + + ret = aw882xx_dev_get_list_head(&dev_list); + if (ret) { + aw_dev_err(aw_dev->dev, "get dev list failed"); + return ret; + } + + if ((g_spin_mode == AW_REG_MIXER_SPIN_MODE) && (mixer_en)) { + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + ret = aw882xx_dsp_set_mixer_en(local_dev, AW_AUDIO_MIX_ENABLE); + if (ret) + return ret; + } + } + + usleep_range(AW_100000_US, AW_100000_US + 10); + + list_for_each(pos, dev_list) { + local_dev = container_of(pos, struct aw_device, list_node); + ret = aw_dev_set_channal_mode(local_dev, local_dev->spin_desc, spin_val); + if (ret < 0) { + aw_dev_err(local_dev->dev, "set channal mode failed"); + return ret; + } + + if ((g_spin_mode == AW_REG_MIXER_SPIN_MODE) && (mixer_en)) { + ret = aw882xx_dsp_set_mixer_en(aw_dev, AW_AUDIO_MIX_DSIABLE); + if (ret) + return ret; + } + } + + return 0; +} + +int aw882xx_spin_set_record_val(struct aw_device *aw_dev) +{ + int ret = -1; + + mutex_lock(&g_spin_lock); + if (g_spin_mode == AW_ADSP_SPIN_MODE) { + ret = aw882xx_dsp_write_spin(g_spin_value); + if (ret) { + mutex_unlock(&g_spin_lock); + return ret; + } + } else if ((g_spin_mode == AW_REG_SPIN_MODE) || + (g_spin_mode == AW_REG_MIXER_SPIN_MODE)) { + ret = aw_dev_set_channal_mode(aw_dev, aw_dev->spin_desc, g_spin_value); + if (ret) { + mutex_unlock(&g_spin_lock); + return ret; + } + } else { + aw_dev_info(aw_dev->dev, "do nothing"); + } + mutex_unlock(&g_spin_lock); + + aw_dev_info(aw_dev->dev, "set record spin val done"); + return 0; +} + +int aw882xx_spin_value_get(struct aw_device *aw_dev, + uint32_t *spin_val, bool pstream) +{ + int ret = 0; + + if (((g_spin_mode == AW_REG_SPIN_MODE) || + (g_spin_mode == AW_REG_MIXER_SPIN_MODE)) || (!pstream)) + *spin_val = g_spin_value; + else if (g_spin_mode == AW_ADSP_SPIN_MODE) + ret = aw882xx_dsp_read_spin(spin_val); + + return ret; +} + +int aw882xx_spin_value_set(struct aw_device *aw_dev, uint32_t spin_val, bool pstream) +{ + int ret = 0; + + mutex_lock(&g_spin_lock); + if (pstream) { + if ((g_spin_mode == AW_REG_SPIN_MODE) || + (g_spin_mode == AW_REG_MIXER_SPIN_MODE)) + ret = aw_reg_write_spin(aw_dev, spin_val, true); + else if (g_spin_mode == AW_ADSP_SPIN_MODE) + ret = aw882xx_dsp_write_spin(spin_val); + else + aw_dev_info(aw_dev->dev, "can't set spin value"); + } else { + if ((g_spin_mode == AW_REG_SPIN_MODE) || + (g_spin_mode == AW_REG_MIXER_SPIN_MODE)) + ret = aw_reg_write_spin(aw_dev, spin_val, false); + else + aw_dev_info(aw_dev->dev, "stream no start only record spin angle"); + } + g_spin_value = spin_val; + mutex_unlock(&g_spin_lock); + + return ret; +} + +static int aw_parse_spin_table_dt(struct aw_device *aw_dev) +{ + int ret = -1; + const char *str_data = NULL; + char spin_table_str[AW_SPIN_MAX] = { 0 }; + struct aw_spin_desc *spin_desc = &aw_dev->spin_desc; + int i; + + ret = of_property_read_string(aw_dev->dev->of_node, "spin-data", &str_data); + if (ret < 0) { + aw_dev_err(aw_dev->dev, "get spin_data failed, close spin function"); + return ret; + } + + ret = sscanf(str_data, "%c %c %c %c", + &spin_table_str[AW_SPIN_0], &spin_table_str[AW_SPIN_90], + &spin_table_str[AW_SPIN_180], &spin_table_str[AW_SPIN_270]); + if (ret != AW_SPIN_MAX) { + aw_dev_err(aw_dev->dev, "unsupported str:%s, close spin function", str_data); + return -EINVAL; + } + + for (i = 0; i < AW_SPIN_MAX; i++) { + if (spin_table_str[i] == 'l' || spin_table_str[i] == 'L') { + spin_desc->spin_table[i].rx_val = spin_desc->rx_desc.left_val; + } else if (spin_table_str[i] == 'r' || spin_table_str[i] == 'R') { + spin_desc->spin_table[i].rx_val = spin_desc->rx_desc.right_val; + } else { + aw_dev_err(aw_dev->dev, "unsupported str:%s, close spin function", str_data); + return -EINVAL; + } + } + + return 0; +} + +static int aw_parse_spin_dts(struct aw_device *aw_dev) +{ + int ret = -1; + const char *spin_str = NULL; + + ret = of_property_read_string(aw_dev->dev->of_node, "spin-mode", &spin_str); + if (ret < 0) { + g_spin_mode = AW_SPIN_OFF_MODE; + aw_dev_info(aw_dev->dev, "spin-mode get failed, spin switch off, spin_mode:%d", g_spin_mode); + return 0; + } + + if (!strcmp(spin_str, "dsp_spin")) + g_spin_mode = AW_ADSP_SPIN_MODE; + else if (!strcmp(spin_str, "reg_spin")) + g_spin_mode = AW_REG_SPIN_MODE; + else if (!strcmp(spin_str, "reg_mixer_spin")) + g_spin_mode = AW_REG_MIXER_SPIN_MODE; + else + g_spin_mode = AW_SPIN_OFF_MODE; + + if ((g_spin_mode == AW_REG_SPIN_MODE) || + (g_spin_mode == AW_REG_MIXER_SPIN_MODE)) { + ret = aw_parse_spin_table_dt(aw_dev); + if (ret < 0) + return ret; + } + + aw_dev_info(aw_dev->dev, "spin mode is %d", g_spin_mode); + return 0; +} + +int aw882xx_spin_init(struct aw_spin_desc *spin_desc) +{ + int ret = 0; + struct aw_device *aw_dev = + container_of(spin_desc, struct aw_device, spin_desc); + + ret = aw_parse_spin_dts(aw_dev); + + if (g_spin_mode == AW_SPIN_OFF_MODE) + spin_desc->aw_spin_kcontrol_st = AW_SPIN_KCONTROL_DISABLE; + else + spin_desc->aw_spin_kcontrol_st = AW_SPIN_KCONTROL_ENABLE; + + aw_dev_info(aw_dev->dev, "aw_spin_kcontrol_st:%d", spin_desc->aw_spin_kcontrol_st); + + return ret; +} diff --git a/sound/soc/codecs/aw882xx/aw882xx_spin.h b/sound/soc/codecs/aw882xx/aw882xx_spin.h new file mode 100644 index 000000000000..eb303e324e3e --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_spin.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 + * aw882xx_spin.h spin_module + * + * Copyright (c) 2019 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __AW882XX_SPIN_H__ +#define __AW882XX_SPIN_H__ + + +enum { + AW_SPIN_OFF_MODE = 0, + AW_ADSP_SPIN_MODE, + AW_REG_SPIN_MODE, + AW_REG_MIXER_SPIN_MODE, + AW_SPIN_MODE_MAX, +}; + +int aw882xx_spin_init(struct aw_spin_desc *spin_desc); +int aw882xx_spin_value_set(struct aw_device *aw_dev, uint32_t spin_val, bool pstream); +int aw882xx_spin_value_get(struct aw_device *aw_dev, uint32_t *spin_val, bool pstream); +int aw882xx_spin_set_record_val(struct aw_device *aw_dev); + +#endif