diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 91ac99bc3..bbc83867a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1604,6 +1604,14 @@ config SND_SOC_RK817 tristate "Rockchip RK817 audio CODEC" depends on MFD_RK8XX || COMPILE_TEST +config SND_SOC_RK_DSM + tristate "Rockchip Delta-sigma Digital Converter Interface" + depends on ARCH_ROCKCHIP || COMPILE_TEST + help + This is a device driver for the digital speaker modulator (DSM) + embedded in some Rockchip SoCs (e.g. RV1106), used to drive a + Class-D speaker output alongside the analog acodec. + config SND_SOC_RL6231 tristate default y if SND_SOC_RT5514=y @@ -1919,6 +1927,15 @@ config SND_SOC_RTQ9128 To compile this driver as a module, choose M here: the module will be called snd-soc-rtq9128. +config SND_SOC_RV1106 + tristate "Rockchip RV1106 CODEC" + depends on ARCH_ROCKCHIP || COMPILE_TEST + select REGMAP_MMIO + help + This is a device driver for the analog audio codec (acodec) + embedded in the Rockchip RV1106 SoC, used for speaker/headphone + output and microphone input (e.g. on the Luckfox Pico 86-Panel). + config SND_SOC_SDW_MOCKUP tristate "SoundWire mockup codec" depends on EXPERT diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index da4077463..ae15009e0 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -231,6 +231,7 @@ snd-soc-pm4125-sdw-y := pm4125-sdw.o snd-soc-rk3308-y := rk3308_codec.o snd-soc-rk3328-y := rk3328_codec.o snd-soc-rk817-y := rk817_codec.o +snd-soc-rk-dsm-y := rk_dsm.o snd-soc-rl6231-y := rl6231.o snd-soc-rt-sdw-common-y := rt-sdw-common.o snd-soc-rl6347a-y := rl6347a.o @@ -283,6 +284,7 @@ snd-soc-rt9123-y := rt9123.o snd-soc-rt9123p-y := rt9123p.o snd-soc-rtq9124-y := rtq9124.o snd-soc-rtq9128-y := rtq9128.o +snd-soc-rv1106-y := rv1106_codec.o snd-soc-sdw-mockup-y := sdw-mockup.o snd-soc-sgtl5000-y := sgtl5000.o snd-soc-alc5623-y := alc5623.o @@ -662,6 +664,7 @@ endif obj-$(CONFIG_SND_SOC_RK3308) += snd-soc-rk3308.o obj-$(CONFIG_SND_SOC_RK3328) += snd-soc-rk3328.o obj-$(CONFIG_SND_SOC_RK817) += snd-soc-rk817.o +obj-$(CONFIG_SND_SOC_RK_DSM) += snd-soc-rk-dsm.o obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o obj-$(CONFIG_SND_SOC_RT_SDW_COMMON) += snd-soc-rt-sdw-common.o obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o @@ -715,6 +718,7 @@ obj-$(CONFIG_SND_SOC_RT9123) += snd-soc-rt9123.o obj-$(CONFIG_SND_SOC_RT9123P) += snd-soc-rt9123p.o obj-$(CONFIG_SND_SOC_RTQ9124) += snd-soc-rtq9124.o obj-$(CONFIG_SND_SOC_RTQ9128) += snd-soc-rtq9128.o +obj-$(CONFIG_SND_SOC_RV1106) += snd-soc-rv1106.o obj-$(CONFIG_SND_SOC_SDW_MOCKUP) += snd-soc-sdw-mockup.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o diff --git a/sound/soc/codecs/rk_dsm.c b/sound/soc/codecs/rk_dsm.c new file mode 100644 index 000000000..4bcbcbaf5 --- /dev/null +++ b/sound/soc/codecs/rk_dsm.c @@ -0,0 +1,651 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Rockchip Audio Delta-sigma Digital Converter Interface + * + * Copyright (C) 2023 Rockchip Electronics Co.,Ltd + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rk_dsm.h" + +#define RK3562_GRF_PERI_AUDIO_CON (0x0070) + +struct rk_dsm_soc_data { + int (*init)(struct device *dev); + void (*deinit)(struct device *dev); +}; + +struct rk_dsm_priv { + struct regmap *grf; + struct regmap *regmap; + struct clk *clk_dac; + struct clk *pclk; + unsigned int pa_ctl_delay_ms; + struct gpio_desc *pa_ctl; + struct reset_control *rc; + const struct rk_dsm_soc_data *data; +}; + +/* DAC digital gain */ +static const DECLARE_TLV_DB_SCALE(dac_tlv, -95625, 375, 0); + +/* DAC Cutoff for High Pass Filter */ +static const char * const dac_hpf_cutoff_text[] = { + "80Hz", "100Hz", "120Hz", "140Hz", +}; + +static SOC_ENUM_SINGLE_DECL(dac_hpf_cutoff_enum, DACHPF, 4, + dac_hpf_cutoff_text); + +static const char * const pa_ctl[] = {"Off", "On"}; + +static const struct soc_enum pa_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(pa_ctl), pa_ctl); + +static int rk_dsm_dac_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int val = snd_soc_component_read(component, mc->reg); + unsigned int sign = snd_soc_component_read(component, DACVOGP); + unsigned int mask = (1 << fls(mc->max)) - 1; + unsigned int shift = mc->shift; + int mid = mc->max / 2; + int uv; + + uv = (val >> shift) & mask; + if (sign) + uv = mid + uv; + else + uv = mid - uv; + + ucontrol->value.integer.value[0] = uv; + ucontrol->value.integer.value[1] = uv; + + return 0; +} + +static int rk_dsm_dac_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg = mc->reg; + unsigned int rreg = mc->rreg; + unsigned int shift = mc->shift; + unsigned int mask = (1 << fls(mc->max)) - 1; + unsigned int val, val_mask, sign; + int uv = ucontrol->value.integer.value[0]; + int min = mc->min; + int mid = mc->max / 2; + + if (uv > mid) { + sign = DSM_DACVOGP_VOLGPL0_POS | DSM_DACVOGP_VOLGPR0_POS; + uv = uv - mid; + } else { + sign = DSM_DACVOGP_VOLGPL0_NEG | DSM_DACVOGP_VOLGPR0_NEG; + uv = mid - uv; + } + + val = ((uv + min) & mask); + val_mask = mask << shift; + val = val << shift; + + snd_soc_component_update_bits(component, reg, val_mask, val); + snd_soc_component_update_bits(component, rreg, val_mask, val); + snd_soc_component_write(component, DACVOGP, sign); + + return 0; +} + +static int rk_dsm_dac_pa_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk_dsm_priv *rd = snd_soc_component_get_drvdata(component); + + if (!rd->pa_ctl) + return -EINVAL; + + ucontrol->value.enumerated.item[0] = gpiod_get_value(rd->pa_ctl); + + return 0; +} + +static int rk_dsm_dac_pa_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk_dsm_priv *rd = snd_soc_component_get_drvdata(component); + + if (!rd->pa_ctl) + return -EINVAL; + + gpiod_set_value(rd->pa_ctl, ucontrol->value.enumerated.item[0]); + + return 0; +} + +static const struct snd_kcontrol_new rk_dsm_snd_controls[] = { + SOC_DOUBLE_R_EXT_TLV("DAC Digital Volume", + DACVOLL0, DACVOLR0, 0, 0x1fe, 0, + rk_dsm_dac_vol_get, + rk_dsm_dac_vol_put, + dac_tlv), + + SOC_ENUM("DAC HPF Cutoff", dac_hpf_cutoff_enum), + SOC_SINGLE("DAC HPF Switch", DACHPF, 0, 1, 0), + SOC_ENUM_EXT("Power Amplifier", pa_enum, + rk_dsm_dac_pa_get, + rk_dsm_dac_pa_put), +}; + +/* + * ACDC_CLK D2A_CLK D2A_SYNC Sample rates supported + * 49.152MHz 49.152MHz 6.144MHz 12/24/48/96/192kHz + * 45.154MHz 45.154MHz 5.644MHz 11.025/22.05/44.1/88.2/176.4kHz + * 32.768MHz 32.768MHz 4.096MHz 8/16/32/64/128kHz + */ +static void rk_dsm_get_clk(unsigned int samplerate, + unsigned int *mclk, + unsigned int *sclk) +{ + switch (samplerate) { + case 12000: + case 24000: + case 48000: + case 96000: + case 192000: + *mclk = 49152000; + *sclk = 6144000; + break; + case 11025: + case 22050: + case 44100: + case 88200: + case 176400: + *mclk = 45158400; + *sclk = 5644800; + break; + case 8000: + case 16000: + case 32000: + case 64000: + case 128000: + *mclk = 32768000; + *sclk = 4096000; + break; + default: + *mclk = 0; + *sclk = 0; + break; + } +} + +static void rk_dsm_enable_clk_dac(struct rk_dsm_priv *rd) +{ + regmap_update_bits(rd->regmap, DACCLKCTRL, + DSM_DACCLKCTRL_DAC_CKE_MASK | + DSM_DACCLKCTRL_I2SRX_CKE_MASK | + DSM_DACCLKCTRL_CKE_BCLKRX_MASK | + DSM_DACCLKCTRL_DAC_SYNC_ENA_MASK | + DSM_DACCLKCTRL_DAC_MODE_ATTENU_MASK, + DSM_DACCLKCTRL_DAC_CKE_EN | + DSM_DACCLKCTRL_I2SRX_CKE_EN | + DSM_DACCLKCTRL_CKE_BCLKRX_EN | + DSM_DACCLKCTRL_DAC_SYNC_ENA_EN | + DSM_DACCLKCTRL_DAC_MODE_ATTENU_EN); +} + +static int rk_dsm_set_clk(struct rk_dsm_priv *rd, + struct snd_pcm_substream *substream, + unsigned int samplerate) +{ + unsigned int mclk, sclk, bclk; + unsigned int div_bclk; + + rk_dsm_get_clk(samplerate, &mclk, &sclk); + if (!mclk || !sclk) + return -EINVAL; + + bclk = 64 * samplerate; + div_bclk = DIV_ROUND_CLOSEST(mclk, bclk); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + clk_set_rate(rd->clk_dac, mclk); + + rk_dsm_enable_clk_dac(rd); + + regmap_update_bits(rd->regmap, DACSCLKRXINT_DIV, + DSM_DACSCLKRXINT_DIV_SCKRXDIV_MASK, + DSM_DACSCLKRXINT_DIV_SCKRXDIV(div_bclk)); + regmap_update_bits(rd->regmap, I2S_CKR0, + DSM_I2S_CKR0_RSD_MASK, + DSM_I2S_CKR0_RSD_64); + } + + return 0; +} + +static int rk_dsm_set_dai_fmt(struct snd_soc_dai *dai, + unsigned int fmt) +{ + struct rk_dsm_priv *rd = + snd_soc_component_get_drvdata(dai->component); + unsigned int mask = 0, val = 0; + + /* master mode only */ + regmap_update_bits(rd->regmap, I2S_CKR1, + DSM_I2S_CKR1_MSS_MASK, + DSM_I2S_CKR1_MSS_MASTER); + + mask = DSM_I2S_CKR1_CKP_MASK | + DSM_I2S_CKR1_RLP_MASK; + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + val = DSM_I2S_CKR1_CKP_NORMAL | + DSM_I2S_CKR1_RLP_NORMAL; + break; + case SND_SOC_DAIFMT_IB_IF: + val = DSM_I2S_CKR1_CKP_INVERTED | + DSM_I2S_CKR1_RLP_INVERTED; + break; + case SND_SOC_DAIFMT_IB_NF: + val = DSM_I2S_CKR1_CKP_INVERTED | + DSM_I2S_CKR1_RLP_NORMAL; + break; + case SND_SOC_DAIFMT_NB_IF: + val = DSM_I2S_CKR1_CKP_NORMAL | + DSM_I2S_CKR1_RLP_INVERTED; + break; + default: + return -EINVAL; + } + + regmap_update_bits(rd->regmap, I2S_CKR1, mask, val); + + return 0; +} + +static int rk_dsm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct rk_dsm_priv *rd = + snd_soc_component_get_drvdata(dai->component); + unsigned int srt = 0, val = 0; + + rk_dsm_set_clk(rd, substream, params_rate(params)); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + switch (params_rate(params)) { + case 8000: + case 11025: + case 12000: + srt = 0; + break; + case 16000: + case 22050: + case 24000: + srt = 1; + break; + case 32000: + case 44100: + case 48000: + srt = 2; + break; + case 64000: + case 88200: + case 96000: + srt = 3; + break; + case 128000: + case 176400: + case 192000: + srt = 4; + break; + default: + return -EINVAL; + } + + regmap_update_bits(rd->regmap, DACCFG1, + DSM_DACCFG1_DACSRT_MASK, + DSM_DACCFG1_DACSRT(srt)); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + val = 16; + break; + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S32_LE: + val = 24; + break; + default: + return -EINVAL; + } + + regmap_update_bits(rd->regmap, I2S_RXCR0, + DSM_I2S_RXCR0_VDW_MASK, + DSM_I2S_RXCR0_VDW(val)); + regmap_update_bits(rd->regmap, DACPWM_CTRL, + DSM_DACPWM_CTRL_PWM_MODE_CKE_MASK | + DSM_DACPWM_CTRL_PWM_EN_MASK, + DSM_DACPWM_CTRL_PWM_MODE_CKE_EN | + DSM_DACPWM_CTRL_PWM_EN); + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + regmap_update_bits(rd->regmap, I2S_XFER, + DSM_I2S_XFER_RXS_MASK, + DSM_I2S_XFER_RXS_START); + regmap_update_bits(rd->regmap, DACDIGEN, + DSM_DACDIGEN_DAC_GLBEN_MASK | + DSM_DACDIGEN_DACEN_L0R1_MASK, + DSM_DACDIGEN_DAC_GLBEN_EN | + DSM_DACDIGEN_DACEN_L0R1_EN); + } + + return 0; +} + +static int rk_dsm_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct rk_dsm_priv *rd = + snd_soc_component_get_drvdata(dai->component); + + gpiod_set_value(rd->pa_ctl, 1); + if (rd->pa_ctl_delay_ms) + msleep(rd->pa_ctl_delay_ms); + + return 0; +} + +static void rk_dsm_reset(struct rk_dsm_priv *rd) +{ + if (IS_ERR(rd->rc)) + return; + + reset_control_assert(rd->rc); + udelay(5); + reset_control_deassert(rd->rc); + udelay(5); +} + +static void rk_dsm_pcm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct rk_dsm_priv *rd = + snd_soc_component_get_drvdata(dai->component); + + gpiod_set_value(rd->pa_ctl, 0); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + regmap_update_bits(rd->regmap, DACPWM_CTRL, + DSM_DACPWM_CTRL_PWM_MODE_CKE_MASK | + DSM_DACPWM_CTRL_PWM_EN_MASK, + DSM_DACPWM_CTRL_PWM_MODE_CKE_DIS | + DSM_DACPWM_CTRL_PWM_DIS); + regmap_update_bits(rd->regmap, I2S_XFER, + DSM_I2S_XFER_RXS_MASK, + DSM_I2S_XFER_RXS_STOP); + regmap_update_bits(rd->regmap, I2S_CLR, + DSM_I2S_CLR_RXC_MASK, + DSM_I2S_CLR_RXC_CLR); + regmap_update_bits(rd->regmap, DACDIGEN, + DSM_DACDIGEN_DAC_GLBEN_MASK | + DSM_DACDIGEN_DACEN_L0R1_MASK, + DSM_DACDIGEN_DAC_GLBEN_DIS | + DSM_DACDIGEN_DACEN_L0R1_DIS); + } + + rk_dsm_reset(rd); +} + +static const struct snd_soc_dai_ops rd_dai_ops = { + .hw_params = rk_dsm_hw_params, + .set_fmt = rk_dsm_set_dai_fmt, + .startup = rk_dsm_pcm_startup, + .shutdown = rk_dsm_pcm_shutdown, +}; + +static struct snd_soc_dai_driver rd_dai[] = { + { + .name = "rk_dsm", + .id = 0, + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), + }, + .ops = &rd_dai_ops, + }, +}; + +static const struct snd_soc_component_driver soc_codec_dev_rd = { + .controls = rk_dsm_snd_controls, + .num_controls = ARRAY_SIZE(rk_dsm_snd_controls), +}; + +static const struct regmap_config rd_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = VERSION, + .cache_type = REGCACHE_FLAT, +}; + +static int rk3562_soc_init(struct device *dev) +{ + struct rk_dsm_priv *rd = dev_get_drvdata(dev); + + if (IS_ERR(rd->grf)) + return PTR_ERR(rd->grf); + + /* enable internal codec to i2s1 */ + return regmap_write(rd->grf, RK3562_GRF_PERI_AUDIO_CON, + (BIT(14) << 16 | BIT(14) | 0x0a100a10)); +} + +static void rk3562_soc_deinit(struct device *dev) +{ + struct rk_dsm_priv *rd = dev_get_drvdata(dev); + + if (IS_ERR(rd->grf)) + return; + + regmap_write(rd->grf, RK3562_GRF_PERI_AUDIO_CON, (BIT(14) << 16) | 0x0a100a10); +} + +static const struct rk_dsm_soc_data rk3562_data = { + .init = rk3562_soc_init, + .deinit = rk3562_soc_deinit, +}; + +#ifdef CONFIG_OF +static const struct of_device_id rd_of_match[] = { + { .compatible = "rockchip,rk3562-dsm", .data = &rk3562_data }, + {}, +}; +MODULE_DEVICE_TABLE(of, rd_of_match); +#endif + +#ifdef CONFIG_PM +static int rk_dsm_runtime_resume(struct device *dev) +{ + struct rk_dsm_priv *rd = dev_get_drvdata(dev); + int ret = 0; + + ret = clk_prepare_enable(rd->pclk); + if (ret) + return ret; + + regcache_cache_only(rd->regmap, false); + regcache_mark_dirty(rd->regmap); + + ret = clk_prepare_enable(rd->clk_dac); + if (ret) + goto err; + + return 0; +err: + clk_disable_unprepare(rd->pclk); + + return ret; +} + +static int rk_dsm_runtime_suspend(struct device *dev) +{ + struct rk_dsm_priv *rd = dev_get_drvdata(dev); + + regcache_cache_only(rd->regmap, true); + clk_disable_unprepare(rd->clk_dac); + clk_disable_unprepare(rd->pclk); + + return 0; +} +#endif + +static int rk_dsm_platform_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct rk_dsm_priv *rd; + void __iomem *base; + int ret = 0; + + rd = devm_kzalloc(&pdev->dev, sizeof(*rd), GFP_KERNEL); + if (!rd) + return -ENOMEM; + + rd->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); + if (IS_ERR(rd->grf)) + return PTR_ERR(rd->grf); + + if (device_property_read_u32(&pdev->dev, "rockchip,pa-ctl-delay-ms", + &rd->pa_ctl_delay_ms)) + rd->pa_ctl_delay_ms = 0; + + rd->rc = devm_reset_control_get(&pdev->dev, "reset"); + + rd->clk_dac = devm_clk_get(&pdev->dev, "dac"); + if (IS_ERR(rd->clk_dac)) + return PTR_ERR(rd->clk_dac); + + rd->pclk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(rd->pclk)) + return PTR_ERR(rd->pclk); + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + rd->regmap = + devm_regmap_init_mmio(&pdev->dev, base, &rd_regmap_config); + if (IS_ERR(rd->regmap)) + return PTR_ERR(rd->regmap); + + platform_set_drvdata(pdev, rd); + + rd->data = device_get_match_data(&pdev->dev); + if (rd->data && rd->data->init) { + ret = rd->data->init(&pdev->dev); + if (ret) + return ret; + } + + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = rk_dsm_runtime_resume(&pdev->dev); + if (ret) + goto err_pm_disable; + } + + regmap_update_bits(rd->regmap, DACPWM_CTRL, + DSM_DACPWM_CTRL_PWM_MODE_MASK, + DSM_DACPWM_CTRL_PWM_MODE_0); + + rd->pa_ctl = devm_gpiod_get_optional(&pdev->dev, "pa-ctl", + GPIOD_OUT_LOW); + + if (!rd->pa_ctl) { + dev_info(&pdev->dev, "no need pa-ctl gpio\n"); + } else if (IS_ERR(rd->pa_ctl)) { + ret = PTR_ERR(rd->pa_ctl); + dev_err(&pdev->dev, "fail to request gpio pa-ctl\n"); + goto err_suspend; + } + + ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_rd, + rd_dai, ARRAY_SIZE(rd_dai)); + + if (ret) + goto err_suspend; + + return 0; + +err_suspend: + if (!pm_runtime_status_suspended(&pdev->dev)) + rk_dsm_runtime_suspend(&pdev->dev); +err_pm_disable: + pm_runtime_disable(&pdev->dev); + + if (rd->data && rd->data->deinit) + rd->data->deinit(&pdev->dev); + + return ret; +} + +static void rk_dsm_platform_remove(struct platform_device *pdev) +{ + struct rk_dsm_priv *rd = dev_get_drvdata(&pdev->dev); + + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + rk_dsm_runtime_suspend(&pdev->dev); + + if (rd->data && rd->data->deinit) + rd->data->deinit(&pdev->dev); +} + +static const struct dev_pm_ops rd_pm = { + SET_RUNTIME_PM_OPS(rk_dsm_runtime_suspend, + rk_dsm_runtime_resume, NULL) +}; + +static struct platform_driver rk_dsm_driver = { + .driver = { + .name = "rk_dsm", + .of_match_table = of_match_ptr(rd_of_match), + .pm = &rd_pm, + }, + .probe = rk_dsm_platform_probe, + .remove = rk_dsm_platform_remove, +}; +module_platform_driver(rk_dsm_driver); + +MODULE_AUTHOR("Jason Zhu "); +MODULE_DESCRIPTION("ASoC Rockchip Delta-sigma Digital Converter Driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rk_dsm.h b/sound/soc/codecs/rk_dsm.h new file mode 100644 index 000000000..553b1c490 --- /dev/null +++ b/sound/soc/codecs/rk_dsm.h @@ -0,0 +1,168 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Rockchip Audio Delta-sigma Digital Converter driver + * + * Copyright (C) 2023 Rockchip Electronics Co., Ltd + * + */ + +#ifndef _RK_DSM_H +#define _RK_DSM_H + +#define DACVUCTL 0x0000 +#define DACVUCTIME 0x0004 +#define DACDIGEN 0x0008 +#define DACCLKCTRL 0x000c +#define DACINT_DIV 0x0014 +#define DACSCLKRXINT_DIV 0x0020 +#define DACPWM_DIV 0x0024 +#define DACPWM_CTRL 0x0028 +#define DACCFG1 0x0044 +#define DACMUTE 0x0048 +#define DACMUTEST 0x004c +#define DACVOLL0 0x0050 +#define DACVOLL1 0x0054 +#define DACVOLL2 0x0058 +#define DACVOLL3 0x005c +#define DACVOLR0 0x0060 +#define DACVOLR1 0x0064 +#define DACVOLR2 0x0068 +#define DACVOLR3 0x006c +#define DACVOGP 0x0070 +#define DACRVOLL0 0x0074 +#define DACRVOLL1 0x0078 +#define DACRVOLL2 0x007c +#define DACRVOLL3 0x0080 +#define DACRVOLR0 0x0084 +#define DACRVOLR1 0x0088 +#define DACRVOLR2 0x008c +#define DACRVOLR3 0x0090 +#define DACLMT0 0x0094 +#define DACLMT1 0x0098 +#define DACLMT2 0x009c +#define DACMIXCTRLL 0x00a0 +#define DACMIXCTRLR 0x00a4 +#define DACHPF 0x00a8 +#define I2S_RXCR0 0x010c +#define I2S_RXCR1 0x0110 +#define I2S_CKR0 0x0114 +#define I2S_CKR1 0x0118 +#define I2S_XFER 0x011c +#define I2S_CLR 0x0120 +#define VERSION 0x0140 + +/* DACDIGEN */ +#define DSM_DACDIGEN_DACEN_L0R1_MASK BIT(0) +#define DSM_DACDIGEN_DACEN_L0R1_EN BIT(0) +#define DSM_DACDIGEN_DACEN_L0R1_DIS 0 +#define DSM_DACDIGEN_DAC_GLBEN_MASK BIT(4) +#define DSM_DACDIGEN_DAC_GLBEN_EN BIT(4) +#define DSM_DACDIGEN_DAC_GLBEN_DIS 0 +/* DACCLKCTRL */ +#define DSM_DACCLKCTRL_DAC_MODE_ATTENU_MASK BIT(0) +#define DSM_DACCLKCTRL_DAC_MODE_ATTENU_EN BIT(0) +#define DSM_DACCLKCTRL_DAC_MODE_ATTENU_DIS 0 +#define DSM_DACCLKCTRL_DAC_SYNC_STATUS_MASK BIT(1) +#define DSM_DACCLKCTRL_DAC_SYNC_STATUS_DONE 0 +#define DSM_DACCLKCTRL_DAC_SYNC_ENA_MASK BIT(2) +#define DSM_DACCLKCTRL_DAC_SYNC_ENA_EN BIT(2) +#define DSM_DACCLKCTRL_DAC_SYNC_ENA_DIS 0 +#define DSM_DACCLKCTRL_CKE_BCLKRX_MASK BIT(3) +#define DSM_DACCLKCTRL_CKE_BCLKRX_EN BIT(3) +#define DSM_DACCLKCTRL_CKE_BCLKRX_DIS 0 +#define DSM_DACCLKCTRL_I2SRX_CKE_MASK BIT(4) +#define DSM_DACCLKCTRL_I2SRX_CKE_EN BIT(4) +#define DSM_DACCLKCTRL_I2SRX_CKE_DIS 0 +#define DSM_DACCLKCTRL_DAC_CKE_MASK BIT(5) +#define DSM_DACCLKCTRL_DAC_CKE_EN BIT(5) +#define DSM_DACCLKCTRL_DAC_CKE_DIS 0 +/* DACINT_DIV */ +#define DSM_DACINT_DIV_INT_DIV_CON_MASK GENMASK(7, 0) +#define DSM_DACINT_DIV_INT_DIV_CON(x) ((x) - 1) +/* DACSCLKRXINT_DIV */ +#define DSM_DACSCLKRXINT_DIV_SCKRXDIV_MASK GENMASK(7, 0) +#define DSM_DACSCLKRXINT_DIV_SCKRXDIV(x) ((x) - 1) +/* DACPWM_DIV */ +#define DSM_DACPWM_DIV_AUDIO_PWM_DIV_MASK GENMASK(7, 0) +#define DSM_DACPWM_DIV_AUDIO_PWM_DIV(x) ((x) - 1) +/* DACPWM_CTRL */ +#define DSM_DACPWM_CTRL_DITH_SEL_MASK GENMASK(2, 0) +#define DSM_DACPWM_CTRL_DITH_SEL(x) (x) +#define DSM_DACPWM_CTRL_PWM_EN_MASK BIT(3) +#define DSM_DACPWM_CTRL_PWM_EN BIT(3) +#define DSM_DACPWM_CTRL_PWM_DIS 0 +#define DSM_DACPWM_CTRL_PWM_MODE_MASK GENMASK(5, 4) +#define DSM_DACPWM_CTRL_PWM_MODE_1 (0x2 << 4) +#define DSM_DACPWM_CTRL_PWM_MODE_0 (0x1 << 4) +#define DSM_DACPWM_CTRL_PWM_MODE_DAC (0x0 << 4) +#define DSM_DACPWM_CTRL_PWM_MODE_CKE_MASK BIT(6) +#define DSM_DACPWM_CTRL_PWM_MODE_CKE_EN BIT(6) +#define DSM_DACPWM_CTRL_PWM_MODE_CKE_DIS 0 +/* DACCFG1 */ +#define DSM_DACCFG1_DACSRT_MASK GENMASK(4, 2) +#define DSM_DACCFG1_DACSRT(x) ((x) << 2) +/* DACMUTE */ +#define DSM_DACMUTE_DACMT_MASK BIT(0) +#define DSM_DACMUTE_DACUNMT_MASK BIT(1) +/* DACVOLL0 */ +#define DSM_DACVOLL0_DACLV0_MASK GENMASK(7, 0) +#define DSM_DACVOLL0_DACLV0(x) (x) +/* DACVOLR0 */ +#define DSM_DACVOLR0_DACRV0_MASK GENMASK(7, 0) +#define DSM_DACVOLR0_DACRV0(x) (x) +/* DACVOGP */ +#define DSM_DACVOGP_VOLGPL0_MASK BIT(0) +#define DSM_DACVOGP_VOLGPL0_POS BIT(0) +#define DSM_DACVOGP_VOLGPL0_NEG 0 +#define DSM_DACVOGP_VOLGPR0_MASK BIT(1) +#define DSM_DACVOGP_VOLGPR0_POS BIT(1) +#define DSM_DACVOGP_VOLGPR0_NEG 0 +/* DACMIXCTRLL */ +#define DSM_DACMIXCTRLL_MIXMODE_L0_MASK GENMASK(1, 0) +#define DSM_DACMIXCTRLL_MIXMODE_L0_LR 2 +#define DSM_DACMIXCTRLL_MIXMODE_L0_R 1 +#define DSM_DACMIXCTRLL_MIXMODE_L0_L 0 +/* DACMIXCTRLR */ +#define DSM_DACMIXCTRLR_MIXMODE_R0_MASK GENMASK(1, 0) +#define DSM_DACMIXCTRLR_MIXMODE_R0_LR 2 +#define DSM_DACMIXCTRLR_MIXMODE_R0_L 1 +#define DSM_DACMIXCTRLR_MIXMODE_R0_R 0 +/* DACHPF */ +#define DSM_DACHPF_HPFEN_L0R0_MASK BIT(0) +#define DSM_DACHPF_HPFEN_L0R0_EN BIT(0) +#define DSM_DACHPF_HPFCF_MASK GENMASK(5, 4) +#define DSM_DACHPF_HPFCF_140HZ (0x3 << 4) +#define DSM_DACHPF_HPFCF_120HZ (0x2 << 4) +#define DSM_DACHPF_HPFCF_100HZ (0x1 << 4) +#define DSM_DACHPF_HPFCF_80HZ (0x0 << 4) +/* I2S_RXCR0 */ +#define DSM_I2S_RXCR0_VDW_MASK GENMASK(4, 0) +#define DSM_I2S_RXCR0_VDW(x) ((x) - 1) +/* I2S_RXCR1 */ +#define DSM_I2S_RXCR1_CEX_MASK BIT(4) +#define DSM_I2S_RXCR1_CEX_EXCHANGE BIT(4) +#define DSM_I2S_RXCR1_RCSR_MASK GENMASK(7, 6) +#define DSM_I2S_RXCR1_RCSR_2CH (0x0 << 6) +/* I2S_CKR0 */ +#define DSM_I2S_CKR0_RSD_MASK GENMASK(3, 2) +#define DSM_I2S_CKR0_RSD_64 (0 << 2) +#define DSM_I2S_CKR0_RSD_128 (1 << 2) +#define DSM_I2S_CKR0_RSD_256 (2 << 2) +/* I2S_CKR1 */ +#define DSM_I2S_CKR1_RLP_MASK BIT(1) +#define DSM_I2S_CKR1_RLP_INVERTED BIT(1) +#define DSM_I2S_CKR1_RLP_NORMAL 0 +#define DSM_I2S_CKR1_CKP_MASK BIT(2) +#define DSM_I2S_CKR1_CKP_INVERTED BIT(2) +#define DSM_I2S_CKR1_CKP_NORMAL 0 +#define DSM_I2S_CKR1_MSS_MASK BIT(3) +#define DSM_I2S_CKR1_MSS_MASTER 0 +/* I2S_XFER */ +#define DSM_I2S_XFER_RXS_MASK BIT(1) +#define DSM_I2S_XFER_RXS_START BIT(1) +#define DSM_I2S_XFER_RXS_STOP 0 +/* I2S_CLR */ +#define DSM_I2S_CLR_RXC_MASK BIT(1) +#define DSM_I2S_CLR_RXC_CLR BIT(1) + +#endif diff --git a/sound/soc/codecs/rv1106_codec.c b/sound/soc/codecs/rv1106_codec.c new file mode 100644 index 000000000..32d5acc0c --- /dev/null +++ b/sound/soc/codecs/rv1106_codec.c @@ -0,0 +1,2332 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * rv1106_codec.c - Rockchip RV1106 SoC Codec Driver + * + * Copyright (C) 2022 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 6.18 port note: is a vendor-BSP-only header not + * present in mainline. Nothing in this file actually uses symbols from it + * (PERI_GRF_PERI_CON1 is defined locally below and the GRF is accessed via + * the generic syscon/regmap API), so the include is simply dropped. + * is replaced with , which is + * where gpiod_direction_output()/devm_gpiod_get_optional() actually live. + */ + +#include "rv1106_codec.h" + +#if defined(CONFIG_DEBUG_FS) +#include +#include +#include +#endif + +#define CODEC_DRV_NAME "rv1106-acodec" + +#define PERI_GRF_PERI_CON1 0x004 +#define ACODEC_AD2DA_LOOP_MSK (1 << 23) +#define ACODEC_AD2DA_LOOP_EN (1 << 7) +#define ACODEC_AD2DA_LOOP_DIS (1 << 7) +/* Control the i2s sdo sdi interface that connect to internal acodec + * 1: connect to internal acodec + * 0: connect to external acodec + */ +#define ACODEC_MSK (1 << 22) +#define ACODEC_EN (1 << 6) +#define ACODEC_DIS (0 << 6) + +#define LR(b, x, v) (((1 << b) & x) ? v : 0) +#define L(x, v) LR(0, x, v) +#define R(x, v) LR(1, x, v) + +#define ADCL (1 << 0) +#define ADCR (1 << 1) + +#define NOT_SPECIFIED (-1) + +enum soc_id_e { + SOC_RV1103 = 0x1103, + SOC_RV1106 = 0x1106, +}; + +enum adc_mode_e { + DIFF_ADCL = 0, /* Differential ADCL, the ADCR is not used */ + SING_ADCL, /* Single-end ADCL, the ADCR is not used */ + DIFF_ADCR, /* Differential ADCR, the ADCL is not used */ + SING_ADCR, /* Single-end ADCR, the ADCL is not used */ + SING_ADCLR, /* Single-end ADCL and ADCR */ + DIFF_ADCLR, /* Differential ADCL and ADCR (Not supported on rv1103 codec) */ + ADC_MODE_NUM, +}; + +struct rv1106_codec_priv { + const struct device *plat_dev; + struct device dev; + struct reset_control *reset; + struct regmap *regmap; + struct regmap *grf; + struct clk *pclk_acodec; + struct clk *mclk_acodec; + struct clk *mclk_cpu; + struct gpio_desc *pa_ctl_gpio; + struct snd_soc_component *component; + + enum adc_mode_e adc_mode; + enum soc_id_e soc_id; + + u32 pa_ctl_delay_ms; + u32 micbias_volt; + + /* AGC L/R Off/on */ + unsigned int agc_l; + unsigned int agc_r; + + /* AGC L/R Approximate Sample Rate */ + unsigned int agc_asr_l; + unsigned int agc_asr_r; + + /* ADC MIC Mute/Work */ + unsigned int mic_mute_l; + unsigned int mic_mute_r; + + /* DAC Control Manually */ + unsigned int dac_ctrl_manual; + + /* For the high pass filter */ + unsigned int hpf_cutoff; + + /* Specify init gains after codec startup */ + unsigned int init_mic_gain; + unsigned int init_alc_gain; + unsigned int init_lineout_gain; + + bool adc_enable; + bool dac_enable; + bool micbias_enable; + bool micbias_used; + +#if defined(CONFIG_DEBUG_FS) + struct dentry *dbg_codec; +#endif +}; + +static const DECLARE_TLV_DB_SCALE(rv1106_codec_alc_agc_gain_tlv, + -1800, 150, 2850); +static const DECLARE_TLV_DB_SCALE(rv1106_codec_alc_agc_max_gain_tlv, + -1350, 600, 2850); +static const DECLARE_TLV_DB_SCALE(rv1106_codec_alc_agc_min_gain_tlv, + -1800, 600, 2400); +static const DECLARE_TLV_DB_SCALE(rv1106_codec_adc_alc_gain_tlv, + -900, 150, 3750); +static const DECLARE_TLV_DB_SCALE(rv1106_codec_adc_dig_gain_tlv, + -9750, 50, 3000); +static const DECLARE_TLV_DB_SCALE(rv1106_codec_dac_lineout_gain_tlv, + -3900, 150, 600); + +static const DECLARE_TLV_DB_RANGE(rv1106_codec_adc_mic_gain_tlv, + 1, 1, TLV_DB_SCALE_ITEM(0, 0, 0), + 2, 2, TLV_DB_SCALE_ITEM(2000, 0, 0), + 3, 3, TLV_DB_SCALE_ITEM(1200, 0, 0), +); + +static const DECLARE_TLV_DB_RANGE(rv1106_codec_dac_hpmix_gain_tlv, + 1, 2, TLV_DB_SCALE_ITEM(0, 600, 0), +); + +static int check_micbias(int volt); + +static int rv1106_codec_adc_enable(struct rv1106_codec_priv *rv1106); +static int rv1106_codec_adc_disable(struct rv1106_codec_priv *rv1106); + +static int rv1106_codec_micbias_enable(struct rv1106_codec_priv *rv1106, + int micbias_volt); +static int rv1106_codec_hpmix_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rv1106_codec_hpmix_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rv1106_codec_micbias_disable(struct rv1106_codec_priv *rv1106); +static int rv1106_codec_hpf_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rv1106_codec_hpf_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rv1106_codec_adc_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rv1106_codec_adc_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rv1106_codec_agc_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rv1106_codec_agc_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rv1106_codec_agc_asr_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rv1106_codec_agc_asr_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rv1106_codec_mic_mute_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rv1106_codec_mic_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rv1106_codec_mic_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rv1106_codec_mic_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rv1106_codec_micbias_volts_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rv1106_codec_micbias_volts_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rv1106_codec_main_micbias_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rv1106_codec_main_micbias_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rv1106_codec_dac_ctrl_manual_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rv1106_codec_dac_ctrl_manual_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +static const char *offon_text[2] = { + [0] = "Off", + [1] = "On", +}; + +static const char *noneoffon_text[3] = { + [0] = "None", + [1] = "Off", + [2] = "On", +}; + +static const char *mute_text[2] = { + [0] = "Work", + [1] = "Mute", +}; + +/* ADC MICBIAS Volt */ +#define MICBIAS_VOLT_NUM 8 + +#define MICBIAS_VREFx0_8 0 +#define MICBIAS_VREFx0_825 1 +#define MICBIAS_VREFx0_85 2 +#define MICBIAS_VREFx0_875 3 +#define MICBIAS_VREFx0_9 4 +#define MICBIAS_VREFx0_925 5 +#define MICBIAS_VREFx0_95 6 +#define MICBIAS_VREFx0_975 7 + +static const char *micbias_volts_enum_array[MICBIAS_VOLT_NUM] = { + [MICBIAS_VREFx0_8] = "VREFx0_8", + [MICBIAS_VREFx0_825] = "VREFx0_825", + [MICBIAS_VREFx0_85] = "VREFx0_85", + [MICBIAS_VREFx0_875] = "VREFx0_875", + [MICBIAS_VREFx0_9] = "VREFx0_9", + [MICBIAS_VREFx0_925] = "VREFx0_925", + [MICBIAS_VREFx0_95] = "VREFx0_95", + [MICBIAS_VREFx0_975] = "VREFx0_975", +}; + +static const char *adc_mode_enum_array[ADC_MODE_NUM] = { + [DIFF_ADCL] = "DiffadcL", + [SING_ADCL] = "SingadcL", + [DIFF_ADCR] = "DiffadcR", + [SING_ADCR] = "SingadcR", + [SING_ADCLR] = "SingadcLR", + [DIFF_ADCLR] = "DiffadcLR", +}; + +static const struct soc_enum rv1106_adc_mode_enum_array[] = { + SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adc_mode_enum_array), adc_mode_enum_array), +}; + +static const struct soc_enum rv1106_micbias_volts_enum_array[] = { + SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(micbias_volts_enum_array), micbias_volts_enum_array), +}; + +/* ADC MICBIAS Main Switch */ +static const struct soc_enum rv1106_main_micbias_enum_array[] = { + SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(offon_text), offon_text), +}; + +static const struct soc_enum rv1106_hpf_enum_array[] = { + SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(offon_text), offon_text), +}; + +/* ALC AGC Switch */ +static const struct soc_enum rv1106_agc_enum_array[] = { + SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(offon_text), offon_text), + SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(offon_text), offon_text), +}; + +/* ADC MIC Mute/Work Switch */ +static const struct soc_enum rv1106_mic_mute_enum_array[] = { + SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(mute_text), mute_text), + SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(mute_text), mute_text), +}; + +/* DAC Control Manually */ +static const struct soc_enum rv1106_dac_pa_ctrl_maunal_enum_array[] = { + SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(noneoffon_text), noneoffon_text), +}; + +/* ALC AGC Approximate Sample Rate */ +#define AGC_ASR_NUM 8 + +#define AGC_ASR_96KHZ 0 +#define AGC_ASR_48KHZ 1 +#define AGC_ASR_44_1KHZ 2 +#define AGC_ASR_32KHZ 3 +#define AGC_ASR_24KHZ 4 +#define AGC_ASR_16KHZ 5 +#define AGC_ASR_12KHZ 6 +#define AGC_ASR_8KHZ 7 + +static const char *agc_asr_text[AGC_ASR_NUM] = { + [AGC_ASR_96KHZ] = "96KHz", + [AGC_ASR_48KHZ] = "48KHz", + [AGC_ASR_44_1KHZ] = "44.1KHz", + [AGC_ASR_32KHZ] = "32KHz", + [AGC_ASR_24KHZ] = "24KHz", + [AGC_ASR_16KHZ] = "16KHz", + [AGC_ASR_12KHZ] = "12KHz", + [AGC_ASR_8KHZ] = "8KHz", +}; + +static const struct soc_enum rv1106_agc_asr_enum_array[] = { + SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(agc_asr_text), agc_asr_text), + SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(agc_asr_text), agc_asr_text), +}; + +static const struct snd_kcontrol_new rv1106_codec_dapm_controls[] = { + /* ADC MIC */ + SOC_SINGLE_EXT_TLV("ADC MIC Left Gain", + ACODEC_ADC_ANA_CTL2, + ACODEC_ADC_L_MIC_GAIN_SFT, + ACODEC_ADC_MIC_GAIN_MAX, + 0, + rv1106_codec_mic_gain_get, + rv1106_codec_mic_gain_put, + rv1106_codec_adc_mic_gain_tlv), + SOC_SINGLE_EXT_TLV("ADC MIC Right Gain", + ACODEC_ADC_ANA_CTL2, + ACODEC_ADC_R_MIC_GAIN_SFT, + ACODEC_ADC_MIC_GAIN_MAX, + 0, + rv1106_codec_mic_gain_get, + rv1106_codec_mic_gain_put, + rv1106_codec_adc_mic_gain_tlv), + + /* ADC ALC */ + SOC_SINGLE_RANGE_TLV("ADC ALC Left Volume", + ACODEC_ADC_ANA_CTL4, + ACODEC_ADC_L_ALC_GAIN_SFT, + ACODEC_ADC_L_ALC_GAIN_MIN, + ACODEC_ADC_L_ALC_GAIN_MAX, + 0, rv1106_codec_adc_alc_gain_tlv), + SOC_SINGLE_RANGE_TLV("ADC ALC Right Volume", + ACODEC_ADC_ANA_CTL5, + ACODEC_ADC_R_ALC_GAIN_SFT, + ACODEC_ADC_R_ALC_GAIN_MIN, + ACODEC_ADC_R_ALC_GAIN_MAX, + 0, rv1106_codec_adc_alc_gain_tlv), + + /* ADC Digital Volume */ + SOC_SINGLE_RANGE_TLV("ADC Digital Left Volume", + ACODEC_ADC_L_DIG_VOL, + ACODEC_ADC_L_DIG_VOL_SFT, + ACODEC_ADC_L_DIG_VOL_MIN, + ACODEC_ADC_L_DIG_VOL_MAX, + 0, rv1106_codec_adc_dig_gain_tlv), + SOC_SINGLE_RANGE_TLV("ADC Digital Right Volume", + ACODEC_ADC_R_DIG_VOL, + ACODEC_ADC_R_DIG_VOL_SFT, + ACODEC_ADC_R_DIG_VOL_MIN, + ACODEC_ADC_R_DIG_VOL_MAX, + 0, rv1106_codec_adc_dig_gain_tlv), + + /* ADC High Pass Filter */ + SOC_ENUM_EXT("ADC HPF Cut-off", rv1106_hpf_enum_array[0], + rv1106_codec_hpf_get, rv1106_codec_hpf_put), + + /* ALC AGC Group */ + SOC_SINGLE_RANGE_TLV("ALC AGC Left Volume", + ACODEC_ADC_PGA_AGC_L_CTL3, + ACODEC_AGC_PGA_GAIN_SFT, + ACODEC_AGC_PGA_GAIN_MIN, + ACODEC_AGC_PGA_GAIN_MAX, + 0, rv1106_codec_alc_agc_gain_tlv), + SOC_SINGLE_RANGE_TLV("ALC AGC Right Volume", + ACODEC_ADC_PGA_AGC_R_CTL3, + ACODEC_AGC_PGA_GAIN_SFT, + ACODEC_AGC_PGA_GAIN_MIN, + ACODEC_AGC_PGA_GAIN_MAX, + 0, rv1106_codec_alc_agc_gain_tlv), + + /* ALC AGC MAX */ + SOC_SINGLE_RANGE_TLV("ALC AGC Left Max Volume", + ACODEC_ADC_PGA_AGC_L_CTL9, + ACODEC_AGC_MAX_GAIN_PGA_SFT, + ACODEC_AGC_MAX_GAIN_PGA_MIN, + ACODEC_AGC_MAX_GAIN_PGA_MAX, + 0, rv1106_codec_alc_agc_max_gain_tlv), + SOC_SINGLE_RANGE_TLV("ALC AGC Right Max Volume", + ACODEC_ADC_PGA_AGC_R_CTL9, + ACODEC_AGC_MAX_GAIN_PGA_SFT, + ACODEC_AGC_MAX_GAIN_PGA_MIN, + ACODEC_AGC_MAX_GAIN_PGA_MAX, + 0, rv1106_codec_alc_agc_max_gain_tlv), + + /* ALC AGC MIN */ + SOC_SINGLE_RANGE_TLV("ALC AGC Left Min Volume", + ACODEC_ADC_PGA_AGC_L_CTL9, + ACODEC_AGC_MIN_GAIN_PGA_SFT, + ACODEC_AGC_MIN_GAIN_PGA_MIN, + ACODEC_AGC_MIN_GAIN_PGA_MAX, + 0, rv1106_codec_alc_agc_min_gain_tlv), + SOC_SINGLE_RANGE_TLV("ALC AGC Right Min Volume", + ACODEC_ADC_PGA_AGC_R_CTL9, + ACODEC_AGC_MIN_GAIN_PGA_SFT, + ACODEC_AGC_MIN_GAIN_PGA_MIN, + ACODEC_AGC_MIN_GAIN_PGA_MAX, + 0, rv1106_codec_alc_agc_min_gain_tlv), + + /* ALC AGC Switch */ + SOC_ENUM_EXT("ALC AGC Left Switch", rv1106_agc_enum_array[0], + rv1106_codec_agc_get, rv1106_codec_agc_put), + SOC_ENUM_EXT("ALC AGC Right Switch", rv1106_agc_enum_array[1], + rv1106_codec_agc_get, rv1106_codec_agc_put), + + /* ALC AGC Approximate Sample Rate */ + SOC_ENUM_EXT("AGC Left Approximate Sample Rate", rv1106_agc_asr_enum_array[0], + rv1106_codec_agc_asr_get, rv1106_codec_agc_asr_put), + SOC_ENUM_EXT("AGC Right Approximate Sample Rate", rv1106_agc_asr_enum_array[1], + rv1106_codec_agc_asr_get, rv1106_codec_agc_asr_put), + + /* ADC Mode */ + SOC_ENUM_EXT("ADC Mode", rv1106_adc_mode_enum_array[0], + rv1106_codec_adc_mode_get, rv1106_codec_adc_mode_put), + + /* ADC MICBIAS Voltage */ + SOC_ENUM_EXT("ADC MICBIAS Voltage", rv1106_micbias_volts_enum_array[0], + rv1106_codec_micbias_volts_get, rv1106_codec_micbias_volts_put), + + /* ADC Main MICBIAS Switch */ + SOC_ENUM_EXT("ADC Main MICBIAS", rv1106_main_micbias_enum_array[0], + rv1106_codec_main_micbias_get, rv1106_codec_main_micbias_put), + + /* ADC MIC Mute/Work Switch */ + SOC_ENUM_EXT("ADC MIC Left Switch", rv1106_mic_mute_enum_array[0], + rv1106_codec_mic_mute_get, rv1106_codec_mic_mute_put), + SOC_ENUM_EXT("ADC MIC Right Switch", rv1106_mic_mute_enum_array[1], + rv1106_codec_mic_mute_get, rv1106_codec_mic_mute_put), + + /* DAC LINEOUT */ + SOC_SINGLE_RANGE_TLV("DAC LINEOUT Volume", + ACODEC_DAC_ANA_CTL2, + ACODEC_DAC_LINEOUT_GAIN_SFT, + ACODEC_DAC_LINEOUT_GAIN_MIN, + ACODEC_DAC_LINEOUT_GAIN_MAX, + 0, rv1106_codec_dac_lineout_gain_tlv), + + /* DAC HPMIX */ + SOC_SINGLE_EXT_TLV("DAC HPMIX Volume", + ACODEC_DAC_HPMIX_CTL, + ACODEC_DAC_HPMIX_GAIN_SFT, + ACODEC_DAC_HPMIX_GAIN_MAX, + 0, + rv1106_codec_hpmix_gain_get, + rv1106_codec_hpmix_gain_put, + rv1106_codec_dac_hpmix_gain_tlv), + + /* DAC Control Manually */ + SOC_ENUM_EXT("DAC Control Manually", rv1106_dac_pa_ctrl_maunal_enum_array[0], + rv1106_codec_dac_ctrl_manual_get, rv1106_codec_dac_ctrl_manual_put), +}; + +static unsigned int using_adc_lr(enum adc_mode_e adc_mode) +{ + if (adc_mode >= SING_ADCLR && adc_mode <= DIFF_ADCLR) + return (ADCL | ADCR); + else if (adc_mode >= DIFF_ADCR && adc_mode <= SING_ADCR) + return ADCR; + else + return ADCL; +} + +static bool using_adc_diff(enum adc_mode_e adc_mode) +{ + if (adc_mode == DIFF_ADCL || + adc_mode == DIFF_ADCR || + adc_mode == DIFF_ADCLR) + return true; + else + return false; +} + +static int check_adc_mode(struct rv1106_codec_priv *rv1106) +{ + if (rv1106->soc_id == SOC_RV1103 && + (rv1106->adc_mode == DIFF_ADCLR || + rv1106->adc_mode == DIFF_ADCR)) { + dev_err(rv1106->plat_dev, + "%s: Differential mode rv1103 only supports 'DiffadcL'\n", __func__); + return -EINVAL; + } + + return 0; +} + +static int rv1106_codec_adc_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = rv1106->adc_mode; + + return 0; +} + +static int rv1106_codec_adc_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + unsigned int last_mode = rv1106->adc_mode; + + rv1106->adc_mode = ucontrol->value.integer.value[0]; + if (check_adc_mode(rv1106)) { + dev_err(rv1106->plat_dev, + "%s - something error checking ADC mode\n", __func__); + rv1106->adc_mode = last_mode; + return 0; + } + + return 0; +} + +static int rv1106_codec_agc_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + + if (e->shift_l) + ucontrol->value.integer.value[0] = rv1106->agc_r; + else + ucontrol->value.integer.value[0] = rv1106->agc_l; + + return 0; +} + +static int rv1106_codec_agc_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int value = ucontrol->value.integer.value[0]; + + if (value) { + /* ALC AGC On */ + if (e->shift_l) { + /* ALC AGC Right On */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_PGA_AGC_R_CTL9, + ACODEC_AGC_FUNC_SEL_MSK, + ACODEC_AGC_FUNC_SEL_EN); + regmap_update_bits(rv1106->regmap, ACODEC_ADC_HPF_PGA_CTL, + ACODEC_ADC_R_PGA_MSK, + ACODEC_ADC_PGA_ALCR_EN); + + rv1106->agc_r = 1; + } else { + /* ALC AGC Left On */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_PGA_AGC_L_CTL9, + ACODEC_AGC_FUNC_SEL_MSK, + ACODEC_AGC_FUNC_SEL_EN); + regmap_update_bits(rv1106->regmap, ACODEC_ADC_HPF_PGA_CTL, + ACODEC_ADC_L_PGA_MSK, + ACODEC_ADC_PGA_ALCL_EN); + + rv1106->agc_l = 1; + } + } else { + /* ALC AGC Off */ + if (e->shift_l) { + /* ALC AGC Right Off */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_PGA_AGC_R_CTL9, + ACODEC_AGC_FUNC_SEL_MSK, + ACODEC_AGC_FUNC_SEL_DIS); + regmap_update_bits(rv1106->regmap, ACODEC_ADC_HPF_PGA_CTL, + ACODEC_ADC_R_PGA_MSK, + ACODEC_ADC_PGA_ALCR_DIS); + + rv1106->agc_r = 0; + } else { + /* ALC AGC Left Off */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_PGA_AGC_L_CTL9, + ACODEC_AGC_FUNC_SEL_MSK, + ACODEC_AGC_FUNC_SEL_DIS); + regmap_update_bits(rv1106->regmap, ACODEC_ADC_HPF_PGA_CTL, + ACODEC_ADC_L_PGA_MSK, + ACODEC_ADC_PGA_ALCL_DIS); + + rv1106->agc_l = 0; + } + } + + return 0; +} + +static int rv1106_codec_agc_asr_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int value; + + if (e->shift_l) { + regmap_read(rv1106->regmap, ACODEC_ADC_PGA_AGC_R_CTL4, &value); + rv1106->agc_asr_r = value >> ACODEC_AGC_APPROX_RATE_SFT; + ucontrol->value.integer.value[0] = rv1106->agc_asr_r; + } else { + regmap_read(rv1106->regmap, ACODEC_ADC_PGA_AGC_L_CTL4, &value); + rv1106->agc_asr_l = value >> ACODEC_AGC_APPROX_RATE_SFT; + ucontrol->value.integer.value[0] = rv1106->agc_asr_l; + } + + return 0; +} + +static int rv1106_codec_agc_asr_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int value; + + value = ucontrol->value.integer.value[0] << ACODEC_AGC_APPROX_RATE_SFT; + + if (e->shift_l) { + /* ALC AGC Right Approximate Sample Rate */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_PGA_AGC_R_CTL4, + ACODEC_AGC_APPROX_RATE_MSK, + value); + rv1106->agc_asr_r = ucontrol->value.integer.value[0]; + } else { + /* ALC AGC Left Approximate Sample Rate */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_PGA_AGC_L_CTL4, + ACODEC_AGC_APPROX_RATE_MSK, + value); + rv1106->agc_asr_l = ucontrol->value.integer.value[0]; + } + + return 0; +} + +static int rv1106_codec_mic_mute_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int value; + + if (e->shift_l) { + /* ADC MIC Right Mute/Work Infos */ + regmap_read(rv1106->regmap, ACODEC_ADC_BIST_MODE_SEL, &value); + rv1106->mic_mute_r = (value & ACODEC_ADC_R_BIST_SINE) >> + ACODEC_ADC_R_BIST_SFT; + ucontrol->value.integer.value[0] = rv1106->mic_mute_r; + } else { + /* ADC MIC Left Mute/Work Infos */ + regmap_read(rv1106->regmap, ACODEC_ADC_BIST_MODE_SEL, &value); + rv1106->mic_mute_l = (value & ACODEC_ADC_L_BIST_SINE) >> + ACODEC_ADC_L_BIST_SFT; + ucontrol->value.integer.value[0] = rv1106->mic_mute_l; + } + + return 0; +} + +static int rv1106_codec_mic_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int value; + + if (e->shift_l) { + /* ADC MIC Right Mute/Work Configuration */ + value = ucontrol->value.integer.value[0] << ACODEC_ADC_R_BIST_SFT; + regmap_update_bits(rv1106->regmap, ACODEC_ADC_BIST_MODE_SEL, + ACODEC_ADC_R_BIST_SINE, + value); + rv1106->mic_mute_r = ucontrol->value.integer.value[0]; + } else { + /* ADC MIC Left Mute/Work Configuration */ + value = ucontrol->value.integer.value[0] << ACODEC_ADC_L_BIST_SFT; + regmap_update_bits(rv1106->regmap, ACODEC_ADC_BIST_MODE_SEL, + ACODEC_ADC_L_BIST_SINE, + value); + rv1106->mic_mute_l = ucontrol->value.integer.value[0]; + } + + return 0; +} + +static int rv1106_codec_micbias_volts_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = rv1106->micbias_volt; + + return 0; +} + +static int rv1106_codec_micbias_volts_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + unsigned int volt = ucontrol->value.integer.value[0]; + int ret; + + ret = check_micbias(volt); + if (ret < 0) { + dev_err(rv1106->plat_dev, "Invalid micbias volt: %d\n", + volt); + return ret; + } + + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL0, + ACODEC_ADC_LEVEL_RANGE_MICBIAS_MSK, + volt); + + rv1106->micbias_volt = volt; + + return 0; +} + +static int rv1106_codec_main_micbias_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = rv1106->micbias_enable; + + return 0; +} + +static int rv1106_codec_main_micbias_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + unsigned int on = ucontrol->value.integer.value[0]; + + if (on) { + if (!rv1106->micbias_enable) + rv1106_codec_micbias_enable(rv1106, rv1106->micbias_volt); + } else { + if (rv1106->micbias_enable) + rv1106_codec_micbias_disable(rv1106); + } + + return 0; +} + +static int rv1106_codec_mic_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + /* + * 6.18 port note: snd_soc_get_volsw_range()/snd_soc_put_volsw_range() + * no longer exist as separate mainline entry points -- the unified + * snd_soc_get_volsw()/snd_soc_put_volsw() already honour the xmin + * field of struct soc_mixer_control (populated via SOC_SINGLE_VALUE), + * so they are a drop-in replacement here. + */ + return snd_soc_get_volsw(kcontrol, ucontrol); +} + +static int rv1106_codec_mic_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + unsigned int index = ucontrol->value.integer.value[0]; + + /* + * From the TRM, the gain of MIC Boost only supports: + * 0dB (index == 1) + * 20dB(index == 2) + * 12dB(index == 3) + */ + if ((index < ACODEC_ADC_MIC_GAIN_MIN) || + (index > ACODEC_ADC_MIC_GAIN_MAX)) { + dev_err(rv1106->plat_dev, "%s: invalid mic gain index: %d\n", + __func__, index); + return -EINVAL; + } + + return snd_soc_put_volsw(kcontrol, ucontrol); +} + +static int rv1106_codec_hpf_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + unsigned int value; + + regmap_read(rv1106->regmap, ACODEC_ADC_HPF_PGA_CTL, &value); + if (value & ACODEC_ADC_HPF_MSK) + rv1106->hpf_cutoff = 1; + else + rv1106->hpf_cutoff = 0; + + ucontrol->value.integer.value[0] = rv1106->hpf_cutoff; + + return 0; +} + +static int rv1106_codec_hpf_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + unsigned int value = ucontrol->value.integer.value[0]; + + if (value) { + /* Enable high pass filter for ADCs */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_HPF_PGA_CTL, + ACODEC_ADC_HPF_MSK, + ACODEC_ADC_HPF_EN); + } else { + /* Disable high pass filter for ADCs. */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_HPF_PGA_CTL, + ACODEC_ADC_HPF_MSK, + ACODEC_ADC_HPF_DIS); + } + + rv1106->hpf_cutoff = value; + + return 0; +} + +static void rv1106_codec_pa_ctrl(struct rv1106_codec_priv *rv1106, bool on) +{ + if (!rv1106->pa_ctl_gpio) + return; + + if (on) { + gpiod_direction_output(rv1106->pa_ctl_gpio, on); + msleep(rv1106->pa_ctl_delay_ms); + } else { + gpiod_direction_output(rv1106->pa_ctl_gpio, on); + } +} + +static int rv1106_codec_reset(struct snd_soc_component *component) +{ + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + + reset_control_assert(rv1106->reset); + usleep_range(10000, 11000); /* estimated value */ + reset_control_deassert(rv1106->reset); + + regmap_write(rv1106->regmap, ACODEC_GLB_CON, 0x00); + usleep_range(10000, 11000); /* estimated value */ + regmap_write(rv1106->regmap, ACODEC_GLB_CON, + ACODEC_CODEC_SYS_WORK | + ACODEC_CODEC_CORE_WORK); + + return 0; +} + +static int rv1106_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + + switch (level) { + case SND_SOC_BIAS_ON: + break; + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + regcache_cache_only(rv1106->regmap, false); + regcache_sync(rv1106->regmap); + break; + case SND_SOC_BIAS_OFF: + break; + } + + return 0; +} + +static int rv1106_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_component *component = codec_dai->component; + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + unsigned int adc_aif1 = 0, adc_aif2 = 0, dac_aif1 = 0, dac_aif2 = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: /* 6.18: was SND_SOC_DAIFMT_CBS_CFS */ + adc_aif2 |= ACODEC_ADC_IO_MODE_SLAVE; + adc_aif2 |= ACODEC_ADC_MODE_SLAVE; + dac_aif2 |= ACODEC_DAC_IO_MODE_SLAVE; + dac_aif2 |= ACODEC_DAC_MODE_SLAVE; + break; + case SND_SOC_DAIFMT_CBP_CFP: /* 6.18: was SND_SOC_DAIFMT_CBM_CFM */ + adc_aif2 |= ACODEC_ADC_IO_MODE_MASTER; + adc_aif2 |= ACODEC_ADC_MODE_MASTER; + dac_aif2 |= ACODEC_DAC_IO_MODE_MASTER; + dac_aif2 |= ACODEC_DAC_MODE_MASTER; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + adc_aif1 |= ACODEC_ADC_I2S_MODE_PCM; + dac_aif1 |= ACODEC_DAC_I2S_MODE_PCM; + break; + case SND_SOC_DAIFMT_I2S: + adc_aif1 |= ACODEC_ADC_I2S_MODE_I2S; + dac_aif1 |= ACODEC_DAC_I2S_MODE_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + adc_aif1 |= ACODEC_ADC_I2S_MODE_RJ; + dac_aif1 |= ACODEC_DAC_I2S_MODE_RJ; + break; + case SND_SOC_DAIFMT_LEFT_J: + adc_aif1 |= ACODEC_ADC_I2S_MODE_LJ; + dac_aif1 |= ACODEC_DAC_I2S_MODE_LJ; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + adc_aif1 |= ACODEC_ADC_I2S_LRC_POL_NORMAL; + adc_aif2 |= ACODEC_ADC_I2S_BIT_CLK_POL_NORMAL; + dac_aif1 |= ACODEC_DAC_I2S_LRC_POL_NORMAL; + dac_aif2 |= ACODEC_DAC_I2S_BIT_CLK_POL_NORMAL; + break; + case SND_SOC_DAIFMT_IB_IF: + adc_aif1 |= ACODEC_ADC_I2S_LRC_POL_REVERSAL; + adc_aif2 |= ACODEC_ADC_I2S_BIT_CLK_POL_REVERSAL; + dac_aif1 |= ACODEC_DAC_I2S_LRC_POL_REVERSAL; + dac_aif2 |= ACODEC_DAC_I2S_BIT_CLK_POL_REVERSAL; + break; + case SND_SOC_DAIFMT_IB_NF: + adc_aif1 |= ACODEC_ADC_I2S_LRC_POL_NORMAL; + adc_aif2 |= ACODEC_ADC_I2S_BIT_CLK_POL_REVERSAL; + dac_aif1 |= ACODEC_DAC_I2S_LRC_POL_NORMAL; + dac_aif2 |= ACODEC_DAC_I2S_BIT_CLK_POL_REVERSAL; + break; + case SND_SOC_DAIFMT_NB_IF: + adc_aif1 |= ACODEC_ADC_I2S_LRC_POL_REVERSAL; + adc_aif2 |= ACODEC_ADC_I2S_BIT_CLK_POL_NORMAL; + dac_aif1 |= ACODEC_DAC_I2S_LRC_POL_REVERSAL; + dac_aif2 |= ACODEC_DAC_I2S_BIT_CLK_POL_NORMAL; + break; + default: + return -EINVAL; + } + + regmap_update_bits(rv1106->regmap, ACODEC_ADC_I2S_CTL0, + ACODEC_ADC_I2S_LRC_POL_MSK | + ACODEC_ADC_I2S_MODE_MSK, + adc_aif1); + regmap_update_bits(rv1106->regmap, ACODEC_ADC_I2S_CTL1, + ACODEC_ADC_IO_MODE_MSK | + ACODEC_ADC_MODE_MSK | + ACODEC_ADC_I2S_BIT_CLK_POL_MSK, + adc_aif2); + + regmap_update_bits(rv1106->regmap, ACODEC_DAC_I2S_CTL0, + ACODEC_DAC_I2S_LRC_POL_MSK | + ACODEC_DAC_I2S_MODE_MSK, + dac_aif1); + regmap_update_bits(rv1106->regmap, ACODEC_ADC_I2S_CTL1, + ACODEC_DAC_IO_MODE_MSK | + ACODEC_DAC_MODE_MSK | + ACODEC_DAC_I2S_BIT_CLK_POL_MSK, + dac_aif2); + + return 0; +} + +static int rv1106_codec_dac_dig_config(struct rv1106_codec_priv *rv1106, + struct snd_pcm_hw_params *params) +{ + unsigned int dac_aif1 = 0, dac_aif2 = 0; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + dac_aif1 |= ACODEC_DAC_I2S_VALID_LEN_16BITS; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + dac_aif1 |= ACODEC_DAC_I2S_VALID_LEN_20BITS; + break; + case SNDRV_PCM_FORMAT_S24_LE: + dac_aif1 |= ACODEC_DAC_I2S_VALID_LEN_24BITS; + break; + case SNDRV_PCM_FORMAT_S32_LE: + dac_aif1 |= ACODEC_DAC_I2S_VALID_LEN_32BITS; + break; + default: + return -EINVAL; + } + + dac_aif1 |= ACODEC_DAC_I2S_LR_NORMAL; + dac_aif2 |= ACODEC_DAC_I2S_WORK; + + regmap_update_bits(rv1106->regmap, ACODEC_DAC_I2S_CTL0, + ACODEC_DAC_I2S_VALID_LEN_MSK | + ACODEC_DAC_I2S_LR_MSK, + dac_aif1); + regmap_update_bits(rv1106->regmap, ACODEC_DAC_I2S_CTL1, + ACODEC_DAC_I2S_MSK, + dac_aif2); + + return 0; +} + +static int rv1106_codec_adc_dig_config(struct rv1106_codec_priv *rv1106, + struct snd_pcm_hw_params *params) +{ + unsigned int adc_aif1 = 0, adc_aif2 = 0; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + adc_aif1 |= ACODEC_ADC_I2S_VALID_LEN_16BITS; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + adc_aif1 |= ACODEC_ADC_I2S_VALID_LEN_20BITS; + break; + case SNDRV_PCM_FORMAT_S24_LE: + adc_aif1 |= ACODEC_ADC_I2S_VALID_LEN_24BITS; + break; + case SNDRV_PCM_FORMAT_S32_LE: + adc_aif1 |= ACODEC_ADC_I2S_VALID_LEN_32BITS; + break; + default: + return -EINVAL; + } + + adc_aif1 |= ACODEC_ADC_I2S_DATA_SEL_NORMAL; + adc_aif2 |= ACODEC_ADC_I2S_WORK; + + regmap_update_bits(rv1106->regmap, ACODEC_ADC_I2S_CTL0, + ACODEC_ADC_I2S_VALID_LEN_MSK | + ACODEC_ADC_I2S_DATA_SEL_MSK, + adc_aif1); + regmap_update_bits(rv1106->regmap, ACODEC_ADC_I2S_CTL1, + ACODEC_ADC_I2S_MSK, + adc_aif2); + + return 0; +} + +static int rv1106_codec_dac_mute(struct rv1106_codec_priv *rv1106, int mute) +{ + if (mute) { + /* Mute DAC HPMIX/LINEOUT */ + regmap_update_bits(rv1106->regmap, + ACODEC_DAC_ANA_CTL1, + ACODEC_DAC_L_LINEOUT_MUTE_MSK, + ACODEC_DAC_L_LINEOUT_MUTE); + regmap_update_bits(rv1106->regmap, + ACODEC_DAC_HPMIX_CTL, + ACODEC_DAC_HPMIX_MUTE_MSK, + ACODEC_DAC_HPMIX_MUTE); + rv1106_codec_pa_ctrl(rv1106, false); + } else { + /* Unmute DAC HPMIX/LINEOUT */ + regmap_update_bits(rv1106->regmap, + ACODEC_DAC_HPMIX_CTL, + ACODEC_DAC_HPMIX_MUTE_MSK, + ACODEC_DAC_HPMIX_WORK); + regmap_update_bits(rv1106->regmap, + ACODEC_DAC_ANA_CTL1, + ACODEC_DAC_L_LINEOUT_MUTE_MSK, + ACODEC_DAC_L_LINEOUT_WORK); + rv1106_codec_pa_ctrl(rv1106, true); + } + + return 0; +} + +static int rv1106_mute_stream(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_component *component = dai->component; + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (rv1106->dac_ctrl_manual == 1) + mute = 1; /* Force DAC control off manually */ + else if (rv1106->dac_ctrl_manual == 2) + mute = 0; /* Force DAC control on manually */ + + rv1106_codec_dac_mute(rv1106, mute); + } + + return 0; +} + +static int rv1106_codec_dac_enable(struct rv1106_codec_priv *rv1106) +{ + /* Step 01 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, + ACODEC_DAC_IBIAS_MSK, + ACODEC_DAC_IBIAS_EN); + udelay(20); + + /* Step 02 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, + ACODEC_DAC_L_REF_VOL_BUF_MSK, + ACODEC_DAC_L_REF_VOL_BUF_EN); + /* Waiting the stable reference voltage */ + usleep_range(1000, 2000); + + /* Step 03 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL1, + ACODEC_DAC_L_LINEOUT_MSK, + ACODEC_DAC_L_LINEOUT_EN); + udelay(20); + + /* Step 04 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL1, + ACODEC_DAC_L_LINEOUT_SIGNAL_MSK, + ACODEC_DAC_L_LINEOUT_SIGNAL_WORK); + udelay(20); + + /* Step 05 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_HPMIX_CTL, + ACODEC_DAC_HPMIX_MSK, + ACODEC_DAC_HPMIX_EN); + udelay(20); + + /* Step 06 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_HPMIX_CTL, + ACODEC_DAC_HPMIX_MDL_MSK, + ACODEC_DAC_HPMIX_MDL_WORK); + udelay(20); + + /* Step 07 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_HPMIX_CTL, + ACODEC_DAC_HPMIX_SEL_MSK, + ACODEC_DAC_HPMIX_I2S); + /* Waiting HPMIX be stable */ + usleep_range(18000, 20000); + + /* Step 08 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, + ACODEC_DAC_L_REF_VOL_MSK, + ACODEC_DAC_L_REF_VOL_EN); + udelay(20); + + /* Step 09 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, + ACODEC_DAC_L_CLK_MSK, + ACODEC_DAC_L_CLK_EN); + udelay(20); + + /* Step 10 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, + ACODEC_DAC_SRC_SIGNAL_MSK, + ACODEC_DAC_SRC_SIGNAL_EN); + udelay(20); + + /* Step 11 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, + ACODEC_DAC_L_SIGNAL_MSK, + ACODEC_DAC_L_SIGNAL_WORK); + udelay(20); + + /* Step 12 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_HPMIX_CTL, + ACODEC_DAC_HPMIX_MUTE_MSK, + ACODEC_DAC_HPMIX_WORK); + udelay(20); + + /* Step 13 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL1, + ACODEC_DAC_L_LINEOUT_MUTE_MSK, + ACODEC_DAC_L_LINEOUT_WORK); + + /* Skip setting gains that Step 14/15 */ + + rv1106->dac_enable = true; + return 0; +} + +static int rv1106_codec_dac_disable(struct rv1106_codec_priv *rv1106) +{ + /* Step 01 */ + /* Skip cleaning the gain to GAIN_LINEOUTL */ + + /* Step 02 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL1, + ACODEC_DAC_L_LINEOUT_MUTE_MSK, + ACODEC_DAC_L_LINEOUT_MUTE); + + /* Step 03 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL1, + ACODEC_DAC_L_LINEOUT_SIGNAL_MSK, + ACODEC_DAC_L_LINEOUT_SIGNAL_INIT); + /* Step 04 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL1, + ACODEC_DAC_L_LINEOUT_MSK, + ACODEC_DAC_L_LINEOUT_DIS); + /* Step 05 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_HPMIX_CTL, + ACODEC_DAC_HPMIX_MUTE_MSK, + ACODEC_DAC_HPMIX_MUTE); + /* Step 06 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_HPMIX_CTL, + ACODEC_DAC_HPMIX_MDL_MSK, + ACODEC_DAC_HPMIX_MDL_INIT); + /* Step 07 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_HPMIX_CTL, + ACODEC_DAC_HPMIX_MSK, + ACODEC_DAC_HPMIX_DIS); + /* Step 08 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, + ACODEC_DAC_SRC_SIGNAL_MSK, + ACODEC_DAC_SRC_SIGNAL_DIS); + /* Step 09 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, + ACODEC_DAC_L_CLK_MSK, + ACODEC_DAC_L_CLK_DIS); + + /* Step 10 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, + ACODEC_DAC_L_REF_VOL_MSK, + ACODEC_DAC_L_REF_VOL_DIS); + /* Step 11 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, + ACODEC_DAC_L_REF_VOL_BUF_MSK, + ACODEC_DAC_L_REF_VOL_BUF_DIS); + + /* Step 12 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, + ACODEC_DAC_IBIAS_MSK, + ACODEC_DAC_IBIAS_DIS); + + /* Step 13 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, + ACODEC_DAC_L_SIGNAL_MSK, + ACODEC_DAC_L_SIGNAL_INIT); + + + rv1106->dac_enable = false; + + return 0; +} + +static int rv1106_codec_power_on(struct rv1106_codec_priv *rv1106) +{ + /* vendor step 1 */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, + ACODEC_DAC_L_REF_POP_SOUND_MSK, + ACODEC_DAC_L_REF_POP_SOUND_WORK); + /* vendor step 2. Charging */ + regmap_update_bits(rv1106->regmap, ACODEC_CURRENT_CHARGE_CTL, + ACODEC_ADC_CURRENT_CHARGE_MSK, + ACODEC_ADC_SEL_I(0xff)); + /* vendor step 3. Supply the power of the analog part. */ + /* vendor step 4 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL0, + ACODEC_ADC_REF_VOL_MSK, ACODEC_ADC_REF_VOL_EN); + /* vendor step 5. Wait charging completed */ + msleep(20); + /* vendor step 6 */ + regmap_update_bits(rv1106->regmap, ACODEC_CURRENT_CHARGE_CTL, + ACODEC_ADC_CURRENT_CHARGE_MSK, + ACODEC_ADC_SEL_I(0x02)); + return 0; +} + +static int rv1106_codec_power_off(struct rv1106_codec_priv *rv1106) +{ + /* + * 0. Keep the power on and disable the DAC and ADC path. + */ + + /* vendor step 1 */ + regmap_update_bits(rv1106->regmap, ACODEC_CURRENT_CHARGE_CTL, + ACODEC_ADC_CURRENT_CHARGE_MSK, + ACODEC_ADC_SEL_I(0xff)); + /* vendor step 3 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL0, + ACODEC_ADC_REF_VOL_MSK, + ACODEC_ADC_REF_VOL_DIS); + /* vendor step 3. Wait until the voltage of VCM keep stable at AGND. */ + msleep(20); + + return 0; +} + +static int rv1106_codec_adc_i2s_route(struct rv1106_codec_priv *rv1106) +{ + regmap_write(rv1106->grf, PERI_GRF_PERI_CON1, + ACODEC_MSK | ACODEC_EN); + return 0; +} + +static int check_micbias(int volt) +{ + switch (volt) { + case ACODEC_ADC_MICBIAS_VOLT_0_975: + case ACODEC_ADC_MICBIAS_VOLT_0_95: + case ACODEC_ADC_MICBIAS_VOLT_0_925: + case ACODEC_ADC_MICBIAS_VOLT_0_9: + case ACODEC_ADC_MICBIAS_VOLT_0_875: + case ACODEC_ADC_MICBIAS_VOLT_0_85: + case ACODEC_ADC_MICBIAS_VOLT_0_825: + case ACODEC_ADC_MICBIAS_VOLT_0_8: + return 0; + } + + return -EINVAL; +} + +static int rv1106_codec_micbias_enable(struct rv1106_codec_priv *rv1106, + int volt) +{ + int ret; + + if (!rv1106->micbias_used) + return 0; + + /* 0. Power up the ACODEC and keep the AVDDH stable */ + + /* vendor step 1 */ + ret = check_micbias(volt); + if (ret < 0) { + dev_err(rv1106->plat_dev, "This is an invalid volt: %d\n", + volt); + return ret; + } + + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL0, + ACODEC_ADC_LEVEL_RANGE_MICBIAS_MSK, + volt); + + /* vendor step 4 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL0, + ACODEC_MICBIAS_MSK, + ACODEC_MICBIAS_WORK); + + /* waiting micbias stabled*/ + mdelay(20); + + rv1106->micbias_enable = true; + + return 0; +} + +static int rv1106_codec_micbias_disable(struct rv1106_codec_priv *rv1106) +{ + if (!rv1106->micbias_used) + return 0; + + /* Step 0. Enable the MICBIAS and keep the Audio Codec stable */ + /* Do nothing */ + + /* vendor step 1 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL0, + ACODEC_MICBIAS_MSK, + ACODEC_MICBIAS_RST); + + rv1106->micbias_enable = false; + + return 0; +} + +static int rv1106_codec_hpmix_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + /* 6.18 port note: see rv1106_codec_mic_gain_get() above. */ + return snd_soc_get_volsw(kcontrol, ucontrol); +} + +static int rv1106_codec_hpmix_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + unsigned int index = ucontrol->value.integer.value[0]; + + if ((index < ACODEC_DAC_HPMIX_GAIN_MIN) || + (index > ACODEC_DAC_HPMIX_GAIN_MAX)) { + dev_err(rv1106->plat_dev, "%s: invalid gain index: %d\n", + __func__, index); + return -EINVAL; + } + + return snd_soc_put_volsw(kcontrol, ucontrol); +} + +static int rv1106_codec_dac_ctrl_manual_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = rv1106->dac_ctrl_manual; + + return 0; +} + +static int rv1106_codec_dac_ctrl_manual_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + + rv1106->dac_ctrl_manual = ucontrol->value.integer.value[0]; + + if (rv1106->dac_ctrl_manual == 0) + return 0; + + if (rv1106->dac_ctrl_manual == 1) + rv1106_codec_dac_mute(rv1106, 1); /* Force DAC control off manually */ + else if (rv1106->dac_ctrl_manual == 2) + rv1106_codec_dac_mute(rv1106, 0); /* Force DAC control on manually */ + + return 0; +} + +static int rv1106_codec_adc_enable(struct rv1106_codec_priv *rv1106) +{ + unsigned int lr = using_adc_lr(rv1106->adc_mode); + bool is_diff = using_adc_diff(rv1106->adc_mode); + unsigned int agc_func_en; + int ret; + + dev_dbg(rv1106->plat_dev, "%s: soc_id: 0x%x lr: %d is_diff: %d\n", + __func__, rv1106->soc_id, lr, is_diff); + + ret = check_adc_mode(rv1106); + if (ret < 0) { + dev_err(rv1106->plat_dev, + "%s - something error checking ADC mode: %d\n", + __func__, ret); + return ret; + } + + /* vendor step 00 */ + if (rv1106->soc_id == SOC_RV1103 && rv1106->adc_mode == DIFF_ADCL) { + /* The ADCL is differential mode on rv1103 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL3, + ACODEC_ADC_L_MODE_SEL_MSK, + ACODEC_ADC_L_FULL_DIFFER2); + } else if (rv1106->soc_id == SOC_RV1106 && is_diff) { + /* The differential mode on rv1106 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL3, + L(lr, ACODEC_ADC_L_MODE_SEL_MSK) | + R(lr, ACODEC_ADC_R_MODE_SEL_MSK), + L(lr, ACODEC_ADC_L_FULL_DIFFER) | + R(lr, ACODEC_ADC_R_FULL_DIFFER)); + } else { + /* The single-end mode */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL3, + L(lr, ACODEC_ADC_L_MODE_SEL_MSK) | + R(lr, ACODEC_ADC_R_MODE_SEL_MSK), + L(lr, ACODEC_ADC_L_SINGLE_END) | + R(lr, ACODEC_ADC_R_SINGLE_END)); + } + + /* vendor step 01 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL1, + L(lr, ACODEC_ADC_L_MIC_MSK) | + R(lr, ACODEC_ADC_R_MIC_MSK), + L(lr, ACODEC_ADC_L_MIC_WORK) | + R(lr, ACODEC_ADC_R_MIC_WORK)); + + /* vendor step 02 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL0, + ACODEC_ADC_IBIAS_MSK, + ACODEC_ADC_IBIAS_EN); + + /* vendor step 03 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL1, + L(lr, ACODEC_ADC_L_REF_VOL_BUF_MSK) | + R(lr, ACODEC_ADC_R_REF_VOL_BUF_MSK), + L(lr, ACODEC_ADC_L_REF_VOL_BUF_EN) | + R(lr, ACODEC_ADC_R_REF_VOL_BUF_EN)); + /* waiting VREF be stable */ + msleep(100); + + /* vendor step 04 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL3, + L(lr, ACODEC_MIC_L_MSK) | + R(lr, ACODEC_MIC_R_MSK), + L(lr, ACODEC_MIC_L_EN) | + R(lr, ACODEC_MIC_R_EN)); + + /* vendor step 05 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL3, + L(lr, ACODEC_ADC_L_MSK) | + R(lr, ACODEC_ADC_R_MSK), + L(lr, ACODEC_ADC_L_EN) | + R(lr, ACODEC_ADC_R_EN)); + + /* vendor step 06 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL6, + L(lr, ACODEC_ADC_L_CLK_MSK) | + R(lr, ACODEC_ADC_R_CLK_MSK), + L(lr, ACODEC_ADC_L_CLK_WORK) | + R(lr, ACODEC_ADC_R_CLK_WORK)); + + /* vendor step 07 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL6, + L(lr, ACODEC_ADC_L_WORK) | + R(lr, ACODEC_ADC_R_WORK), + L(lr, ACODEC_ADC_L_WORK) | + R(lr, ACODEC_ADC_R_WORK)); + + /* vendor step 08 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL6, + L(lr, ACODEC_ADC_L_SIGNAL_EN) | + R(lr, ACODEC_ADC_R_SIGNAL_EN), + L(lr, ACODEC_ADC_L_SIGNAL_EN) | + R(lr, ACODEC_ADC_R_SIGNAL_EN)); + + /* vendor step 09 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL6, + L(lr, ACODEC_ADC_L_ALC_MSK) | + R(lr, ACODEC_ADC_R_ALC_MSK), + L(lr, ACODEC_ADC_L_ALC_WORK) | + R(lr, ACODEC_ADC_R_ALC_WORK)); + + /* vendor step 10 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL1, + L(lr, ACODEC_ADC_L_MIC_SIGNAL_MSK) | + R(lr, ACODEC_ADC_R_MIC_SIGNAL_MSK), + L(lr, ACODEC_ADC_L_MIC_SIGNAL_WORK) | + R(lr, ACODEC_ADC_R_MIC_SIGNAL_WORK)); + + /* vendor step 11, configure GAIN_MICL/R by user */ + + /* vendor step 12, configure GAIN_ALCL/R by user */ + + /* vendor step 13 */ + regmap_read(rv1106->regmap, ACODEC_ADC_ANA_CTL1, &agc_func_en); + if (agc_func_en & ACODEC_AGC_FUNC_SEL_EN) { + regmap_update_bits(rv1106->regmap, + ACODEC_ADC_ANA_CTL1, + L(lr, ACODEC_ADC_L_ZERO_CROSS_DET_MSK) | + R(lr, ACODEC_ADC_R_ZERO_CROSS_DET_MSK), + L(lr, ACODEC_ADC_L_ZERO_CROSS_DET_EN) | + R(lr, ACODEC_ADC_R_ZERO_CROSS_DET_EN)); + } + + rv1106->adc_enable = true; + + return 0; +} + +static int rv1106_codec_adc_disable(struct rv1106_codec_priv *rv1106) +{ + /* vendor step 1 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL1, + ACODEC_ADC_L_ZERO_CROSS_DET_MSK | + ACODEC_ADC_R_ZERO_CROSS_DET_MSK, + ACODEC_ADC_L_ZERO_CROSS_DET_DIS | + ACODEC_ADC_R_ZERO_CROSS_DET_DIS); + + /* vendor step 2 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL6, + ACODEC_ADC_L_WORK | + ACODEC_ADC_R_WORK, + ACODEC_ADC_L_INIT | + ACODEC_ADC_R_INIT); + + /* vendor step 3 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL6, + ACODEC_ADC_L_CLK_WORK | + ACODEC_ADC_R_CLK_WORK, + ACODEC_ADC_L_CLK_RST | + ACODEC_ADC_R_CLK_RST); + + /* vendor step 4 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL3, + ACODEC_ADC_L_MSK | + ACODEC_ADC_R_MSK, + ACODEC_ADC_L_DIS | + ACODEC_ADC_R_DIS); + + /* vendor step 5 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL3, + ACODEC_MIC_L_MSK | + ACODEC_MIC_R_MSK, + ACODEC_MIC_L_DIS | + ACODEC_MIC_R_DIS); + + /* vendor step 6 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL1, + ACODEC_ADC_L_REF_VOL_BUF_MSK | + ACODEC_ADC_R_REF_VOL_BUF_MSK, + ACODEC_ADC_L_REF_VOL_BUF_DIS | + ACODEC_ADC_R_REF_VOL_BUF_DIS); + + /* vendor step 7 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL0, + ACODEC_ADC_IBIAS_MSK, + ACODEC_ADC_IBIAS_DIS); + + /* vendor step 8 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL6, + ACODEC_ADC_L_SIGNAL_EN | + ACODEC_ADC_R_SIGNAL_EN, + ACODEC_ADC_L_SIGNAL_DIS | + ACODEC_ADC_R_SIGNAL_DIS); + + /* vendor step 9 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL6, + ACODEC_ADC_L_ALC_MSK | + ACODEC_ADC_R_ALC_MSK, + ACODEC_ADC_L_ALC_INIT | + ACODEC_ADC_R_ALC_INIT); + + /* vendor step 10 */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL1, + ACODEC_ADC_L_MIC_SIGNAL_MSK | + ACODEC_ADC_R_MIC_SIGNAL_MSK, + ACODEC_ADC_L_MIC_SIGNAL_INIT | + ACODEC_ADC_R_MIC_SIGNAL_INIT); + + rv1106->adc_enable = false; + + return 0; +} + +static int rv1106_codec_open_capture(struct rv1106_codec_priv *rv1106) +{ + rv1106_codec_adc_enable(rv1106); + + return 0; +} + +static int rv1106_codec_close_capture(struct rv1106_codec_priv *rv1106) +{ + rv1106_codec_adc_disable(rv1106); + return 0; +} + +static int rv1106_codec_open_playback(struct rv1106_codec_priv *rv1106) +{ + rv1106_codec_dac_enable(rv1106); + return 0; +} + +static int rv1106_codec_close_playback(struct rv1106_codec_priv *rv1106) +{ + rv1106_codec_dac_disable(rv1106); + return 0; +} + +static int rv1106_codec_dlp_down(struct rv1106_codec_priv *rv1106) +{ + rv1106_codec_micbias_disable(rv1106); + rv1106_codec_power_off(rv1106); + return 0; +} + +static int rv1106_codec_dlp_up(struct rv1106_codec_priv *rv1106) +{ + rv1106_codec_power_on(rv1106); + rv1106_codec_micbias_enable(rv1106, rv1106->micbias_volt); + return 0; +} + +static int rv1106_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + rv1106_codec_open_playback(rv1106); + rv1106_codec_dac_dig_config(rv1106, params); + } else { + rv1106_codec_open_capture(rv1106); + rv1106_codec_adc_dig_config(rv1106, params); + } + + return 0; +} + +static void rv1106_pcm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + rv1106_codec_close_playback(rv1106); + else + rv1106_codec_close_capture(rv1106); + + regcache_cache_only(rv1106->regmap, false); + regcache_sync(rv1106->regmap); +} + +static const struct snd_soc_dai_ops rv1106_dai_ops = { + .hw_params = rv1106_hw_params, + .set_fmt = rv1106_set_dai_fmt, + .mute_stream = rv1106_mute_stream, + .shutdown = rv1106_pcm_shutdown, +}; + +static struct snd_soc_dai_driver rv1106_dai[] = { + { + .name = "rv1106-hifi", + .id = ACODEC_HIFI, + .playback = { + .stream_name = "HiFi Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S20_3LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), + }, + .capture = { + .stream_name = "HiFi Capture", + .channels_min = 1, + .channels_max = 4, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S20_3LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), + }, + .ops = &rv1106_dai_ops, + }, +}; + +static int rv1106_suspend(struct snd_soc_component *component) +{ + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + + rv1106_codec_dlp_down(rv1106); + clk_disable_unprepare(rv1106->mclk_acodec); + clk_disable_unprepare(rv1106->pclk_acodec); + rv1106_set_bias_level(component, SND_SOC_BIAS_OFF); + return 0; +} + +static int rv1106_resume(struct snd_soc_component *component) +{ + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + int ret = 0; + + ret = clk_prepare_enable(rv1106->pclk_acodec); + if (ret < 0) { + dev_err(rv1106->plat_dev, + "Failed to enable acodec pclk_acodec: %d\n", ret); + goto out; + } + + ret = clk_prepare_enable(rv1106->mclk_acodec); + if (ret < 0) { + dev_err(rv1106->plat_dev, + "Failed to enable acodec mclk_acodec: %d\n", ret); + goto out; + } + + rv1106_codec_dlp_up(rv1106); +out: + rv1106_set_bias_level(component, SND_SOC_BIAS_STANDBY); + return ret; +} + +static int rv1106_codec_default_gains(struct rv1106_codec_priv *rv1106) +{ + int gainl, gainr; + + /** + * MIC Gain + * 0dB (0x01) + * 20dB (0x02) + * 12dB (0x03) + */ + if (rv1106->init_mic_gain == NOT_SPECIFIED) { + gainl = ACODEC_ADC_L_MIC_GAIN_0DB; + gainr = ACODEC_ADC_R_MIC_GAIN_0DB; + } else { + gainl = ((rv1106->init_mic_gain >> 4) & 0x03) << ACODEC_ADC_L_MIC_GAIN_SFT; + gainr = ((rv1106->init_mic_gain >> 0) & 0x03) << ACODEC_ADC_R_MIC_GAIN_SFT; + } + + /* Prepare ADC gains */ + /* vendor step 12, set MIC PGA default gains */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL2, + ACODEC_ADC_L_MIC_GAIN_MSK | + ACODEC_ADC_R_MIC_GAIN_MSK, + gainl | gainr); + + /** + * ALC Gain (0dB: 0x06) + * min: -9.0dB (0x00) + * max: +37.5dB (0x1f) + * step: +1.5dB + */ + if (rv1106->init_alc_gain == NOT_SPECIFIED) { + gainl = ACODEC_ADC_L_ALC_GAIN_0DB; + gainr = ACODEC_ADC_R_ALC_GAIN_0DB; + } else { + gainl = ((rv1106->init_alc_gain >> 4) & 0x1f); + gainr = ((rv1106->init_alc_gain >> 0) & 0x1f); + } + /* vendor step 13, set ALC default gains */ + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL4, + ACODEC_ADC_L_ALC_GAIN_MSK, + gainl); + regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL5, + ACODEC_ADC_R_ALC_GAIN_MSK, + gainr); + + /* Prepare DAC gains */ + /* Step 19, set LINEOUT default gains */ + regmap_update_bits(rv1106->regmap, ACODEC_DAC_GAIN_SEL, + ACODEC_DAC_DIG_GAIN_MSK, + ACODEC_DAC_DIG_GAIN(ACODEC_DAC_DIG_0DB)); /* The calibrated fixed gain */ + /** + * Lineout Gain (0dB: 0x1a) + * min: -39.0dB (0x00) + * max: +6.0dB (0x1f) + * step: +1.5dB + */ + if (rv1106->init_lineout_gain == NOT_SPECIFIED) + gainl = ACODEC_DAC_LINEOUT_GAIN_0DB; + else + gainl = rv1106->init_lineout_gain & 0x1f; + regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL2, + ACODEC_DAC_LINEOUT_GAIN_MSK, + gainl); + return 0; +} + +static int rv1106_codec_check_micbias(struct rv1106_codec_priv *rv1106, + struct device_node *np) +{ + /* Check internal of acodec micbias */ + rv1106->micbias_used = + of_property_read_bool(np, "acodec,micbias"); + + /* Using 0.9*AVDD by default */ + rv1106->micbias_volt = ACODEC_ADC_MICBIAS_VOLT_0_9; + + return 0; +} + +static int rv1106_codec_dapm_controls_prepare(struct rv1106_codec_priv *rv1106) +{ + rv1106->adc_mode = DIFF_ADCL; + rv1106->dac_ctrl_manual = 0; + rv1106->hpf_cutoff = 0; + rv1106->agc_l = 0; + rv1106->agc_r = 0; + rv1106->agc_asr_l = AGC_ASR_96KHZ; + rv1106->agc_asr_r = AGC_ASR_96KHZ; + + return 0; +} + +static int rv1106_codec_prepare(struct rv1106_codec_priv *rv1106) +{ + /* Clear registers for ADC and DAC */ + rv1106_codec_close_playback(rv1106); + rv1106_codec_close_capture(rv1106); + rv1106_codec_default_gains(rv1106); + rv1106_codec_dapm_controls_prepare(rv1106); + + return 0; +} + +static int rv1106_probe(struct snd_soc_component *component) +{ + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + + rv1106->component = component; + rv1106_codec_reset(component); + rv1106_codec_dlp_up(rv1106); + rv1106_codec_prepare(rv1106); + + regcache_cache_only(rv1106->regmap, false); + regcache_sync(rv1106->regmap); + + return 0; +} + +static void rv1106_remove(struct snd_soc_component *component) +{ + struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); + + rv1106_codec_pa_ctrl(rv1106, false); + rv1106_codec_micbias_disable(rv1106); + rv1106_codec_power_off(rv1106); + regcache_cache_only(rv1106->regmap, false); + regcache_sync(rv1106->regmap); +} + +static const struct snd_soc_component_driver soc_codec_dev_rv1106 = { + .probe = rv1106_probe, + .remove = rv1106_remove, + .suspend = rv1106_suspend, + .resume = rv1106_resume, + .set_bias_level = rv1106_set_bias_level, + .controls = rv1106_codec_dapm_controls, + .num_controls = ARRAY_SIZE(rv1106_codec_dapm_controls), +}; + +/* Set the default value or reset value */ +static const struct reg_default rv1106_codec_reg_defaults[] = { + { ACODEC_RESET_CTL, 0x03 }, +}; + +static bool rv1106_codec_write_read_reg(struct device *dev, unsigned int reg) +{ + /* All registers can be read / write */ + return true; +} + +static bool rv1106_codec_volatile_reg(struct device *dev, unsigned int reg) +{ + /* All registers can be read / write */ + return true; +} + +static const struct regmap_config rv1106_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = ACODEC_REG_MAX, + .writeable_reg = rv1106_codec_write_read_reg, + .readable_reg = rv1106_codec_write_read_reg, + .volatile_reg = rv1106_codec_volatile_reg, + .reg_defaults = rv1106_codec_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(rv1106_codec_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +static ssize_t adc_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rv1106_codec_priv *rv1106 = + container_of(dev, struct rv1106_codec_priv, dev); + + return sprintf(buf, "%d\n", rv1106->adc_enable); +} + +static ssize_t adc_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rv1106_codec_priv *rv1106 = + container_of(dev, struct rv1106_codec_priv, dev); + unsigned long enable; + int ret = kstrtoul(buf, 10, &enable); + + if (ret < 0) { + dev_err(dev, "Invalid enable: %ld, ret: %d\n", + enable, ret); + return -EINVAL; + } + + if (enable) + rv1106_codec_open_capture(rv1106); + else + rv1106_codec_close_capture(rv1106); + + dev_info(dev, "ADC enable: %ld\n", enable); + + return count; +} + +static ssize_t dac_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rv1106_codec_priv *rv1106 = + container_of(dev, struct rv1106_codec_priv, dev); + + return sprintf(buf, "%d\n", rv1106->dac_enable); +} + +static ssize_t dac_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rv1106_codec_priv *rv1106 = + container_of(dev, struct rv1106_codec_priv, dev); + unsigned long enable; + int ret = kstrtoul(buf, 10, &enable); + + if (ret < 0) { + dev_err(dev, "Invalid enable: %ld, ret: %d\n", + enable, ret); + return -EINVAL; + } + + if (enable) + rv1106_codec_open_playback(rv1106); + else + rv1106_codec_close_playback(rv1106); + + dev_info(dev, "DAC enable: %ld\n", enable); + + return count; +} + +static const struct device_attribute acodec_attrs[] = { + __ATTR_RW(adc_enable), + __ATTR_RW(dac_enable), +}; + +static void rv1106_codec_device_release(struct device *dev) +{ + /* Do nothing */ +} + +static int rv1106_codec_sysfs_init(struct platform_device *pdev, + struct rv1106_codec_priv *rv1106) +{ + struct device *dev = &rv1106->dev; + int i; + + dev->release = rv1106_codec_device_release; + dev->parent = &pdev->dev; + set_dev_node(dev, dev_to_node(&pdev->dev)); + dev_set_name(dev, "acodec_attrs"); + + if (device_register(dev)) { + dev_err(&pdev->dev, + "Register 'acodec_attrs' failed\n"); + dev->parent = NULL; + return -ENOMEM; + } + + for (i = 0; i < ARRAY_SIZE(acodec_attrs); i++) { + if (device_create_file(dev, &acodec_attrs[i])) { + dev_err(&pdev->dev, + "Create 'acodec_attrs' failed\n"); + device_unregister(dev); + return -ENOMEM; + } + } + + return 0; +} + +static int rv1106_codec_sysfs_exit(struct rv1106_codec_priv *rv1106) +{ + struct device *dev = &rv1106->dev; + int i; + + for (i = 0; i < ARRAY_SIZE(acodec_attrs); i++) + device_remove_file(dev, &acodec_attrs[i]); + + device_unregister(dev); + return 0; +} + +#if defined(CONFIG_DEBUG_FS) +static int rv1106_codec_debugfs_reg_show(struct seq_file *s, void *v) +{ + struct rv1106_codec_priv *rv1106 = s->private; + unsigned int i; + unsigned int val; + + for (i = ACODEC_RESET_CTL; i <= ACODEC_ADC_PGA_AGC_R_CTL9; i += 4) { + regmap_read(rv1106->regmap, i, &val); + if (!(i % 16)) + seq_printf(s, "\nR:%04x: ", i); + seq_printf(s, "%08x ", val); + } + + seq_puts(s, "\n"); + + return 0; +} + +static ssize_t rv1106_codec_debugfs_reg_operate(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct rv1106_codec_priv *rv1106 = + ((struct seq_file *)file->private_data)->private; + unsigned int reg, val; + char op; + char kbuf[32]; + int ret; + + if (count >= sizeof(kbuf)) + return -EINVAL; + + if (copy_from_user(kbuf, buf, count)) + return -EFAULT; + kbuf[count] = '\0'; + + ret = sscanf(kbuf, "%c,%x,%x", &op, ®, &val); + if (ret != 3) { + pr_err("sscanf failed: %d\n", ret); + return -EFAULT; + } + + if (op == 'w') { + pr_info("Write reg: 0x%04x with val: 0x%08x\n", reg, val); + regmap_write(rv1106->regmap, reg, val); + regcache_cache_only(rv1106->regmap, false); + regcache_sync(rv1106->regmap); + pr_info("Read back reg: 0x%04x with val: 0x%08x\n", reg, val); + } else if (op == 'r') { + regmap_read(rv1106->regmap, reg, &val); + pr_info("Read reg: 0x%04x with val: 0x%08x\n", reg, val); + } else { + pr_err("This is an invalid operation: %c\n", op); + } + + return count; +} + +static int rv1106_codec_debugfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, + rv1106_codec_debugfs_reg_show, inode->i_private); +} + +static const struct file_operations rv1106_codec_reg_debugfs_fops = { + .owner = THIS_MODULE, + .open = rv1106_codec_debugfs_open, + .read = seq_read, + .write = rv1106_codec_debugfs_reg_operate, + .llseek = seq_lseek, + .release = single_release, +}; +#endif /* CONFIG_DEBUG_FS */ + +static const struct of_device_id rv1106_codec_of_match[] = { + { .compatible = "rockchip,rv1103-codec", .data = (void *)SOC_RV1103}, + { .compatible = "rockchip,rv1106-codec", .data = (void *)SOC_RV1106}, + {}, +}; +MODULE_DEVICE_TABLE(of, rv1106_codec_of_match); + +static int rv1106_platform_probe(struct platform_device *pdev) +{ + const struct of_device_id *of_id; + struct device_node *np = pdev->dev.of_node; + struct rv1106_codec_priv *rv1106; + struct resource *res; + void __iomem *base; + int ret; + + rv1106 = devm_kzalloc(&pdev->dev, sizeof(*rv1106), GFP_KERNEL); + if (!rv1106) + return -ENOMEM; + + of_id = of_match_device(rv1106_codec_of_match, &pdev->dev); + if (of_id) + rv1106->soc_id = (enum soc_id_e)of_id->data; + dev_info(&pdev->dev, "current soc_id: rv%x\n", rv1106->soc_id); + + rv1106->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); + if (IS_ERR(rv1106->grf)) + return dev_err_probe(&pdev->dev, PTR_ERR(rv1106->grf), + "Missing 'rockchip,grf' property\n"); + + rv1106->plat_dev = &pdev->dev; + rv1106->reset = devm_reset_control_get(&pdev->dev, "acodec-reset"); + if (IS_ERR(rv1106->reset)) { + ret = PTR_ERR(rv1106->reset); + if (ret != -ENOENT) + return ret; + + dev_dbg(&pdev->dev, "No reset control found\n"); + rv1106->reset = NULL; + } + + rv1106->init_mic_gain = NOT_SPECIFIED; + of_property_read_u32(np, "init-mic-gain", &rv1106->init_mic_gain); + + rv1106->init_alc_gain = NOT_SPECIFIED; + of_property_read_u32(np, "init-alc-gain", &rv1106->init_alc_gain); + + rv1106->init_lineout_gain = NOT_SPECIFIED; + of_property_read_u32(np, "init-lineout-gain", &rv1106->init_lineout_gain); + + rv1106->pa_ctl_gpio = devm_gpiod_get_optional(&pdev->dev, "pa-ctl", + GPIOD_OUT_LOW); + if (IS_ERR(rv1106->pa_ctl_gpio)) + return dev_err_probe(&pdev->dev, PTR_ERR(rv1106->pa_ctl_gpio), + "Unable to claim gpio pa-ctl\n"); + + if (rv1106->pa_ctl_gpio) + of_property_read_u32(np, "pa-ctl-delay-ms", + &rv1106->pa_ctl_delay_ms); + + dev_info(&pdev->dev, "%s pa_ctl_gpio and pa_ctl_delay_ms: %d\n", + rv1106->pa_ctl_gpio ? "Use" : "No use", + rv1106->pa_ctl_delay_ms); + + /* Close external PA during startup. */ + rv1106_codec_pa_ctrl(rv1106, false); + + rv1106->pclk_acodec = devm_clk_get(&pdev->dev, "pclk_acodec"); + if (IS_ERR(rv1106->pclk_acodec)) + return dev_err_probe(&pdev->dev, PTR_ERR(rv1106->pclk_acodec), + "Can't get acodec pclk_acodec\n"); + + rv1106->mclk_acodec = devm_clk_get(&pdev->dev, "mclk_acodec"); + if (IS_ERR(rv1106->mclk_acodec)) + return dev_err_probe(&pdev->dev, PTR_ERR(rv1106->mclk_acodec), + "Can't get acodec mclk_acodec\n"); + + rv1106->mclk_cpu = devm_clk_get(&pdev->dev, "mclk_cpu"); + if (IS_ERR(rv1106->mclk_cpu)) + return dev_err_probe(&pdev->dev, PTR_ERR(rv1106->mclk_cpu), + "Can't get acodec mclk_cpu\n"); + + ret = rv1106_codec_sysfs_init(pdev, rv1106); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "Sysfs init failed\n"); + +#if defined(CONFIG_DEBUG_FS) + rv1106->dbg_codec = debugfs_create_dir(CODEC_DRV_NAME, NULL); + if (IS_ERR(rv1106->dbg_codec)) + dev_err(&pdev->dev, + "Failed to create debugfs dir for rv1106!\n"); + else + debugfs_create_file("reg", 0644, rv1106->dbg_codec, + rv1106, &rv1106_codec_reg_debugfs_fops); +#endif + + ret = clk_prepare_enable(rv1106->pclk_acodec); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to enable acodec pclk_acodec: %d\n", ret); + goto failed_2; + } + + ret = clk_prepare_enable(rv1106->mclk_acodec); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to enable acodec mclk_acodec: %d\n", ret); + goto failed_1; + } + + /** + * In PERICRU_PERICLKSEL_CON08, the mclk_acodec_t/rx_div are div 4 + * by default, we need to calibrate once, make the div is 1 and keep + * the rate of mclk_acodec is the same with mclk_i2s. + * + * FIXME: need to handle div dynamically if the DSMAUDIO is enabled. + */ + clk_set_rate(rv1106->mclk_acodec, clk_get_rate(rv1106->mclk_cpu)); + + rv1106_codec_check_micbias(rv1106, np); + + ret = rv1106_codec_adc_i2s_route(rv1106); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to route ADC to i2s: %d\n", + ret); + goto failed; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) { + ret = PTR_ERR(base); + dev_err(&pdev->dev, "Failed to ioremap resource\n"); + goto failed; + } + + rv1106->regmap = devm_regmap_init_mmio(&pdev->dev, base, + &rv1106_codec_regmap_config); + if (IS_ERR(rv1106->regmap)) { + ret = PTR_ERR(rv1106->regmap); + dev_err(&pdev->dev, "Failed to regmap mmio\n"); + goto failed; + } + + platform_set_drvdata(pdev, rv1106); + ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_rv1106, + rv1106_dai, ARRAY_SIZE(rv1106_dai)); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); + goto failed; + } + + return ret; + +failed: + clk_disable_unprepare(rv1106->mclk_acodec); +failed_1: + clk_disable_unprepare(rv1106->pclk_acodec); +failed_2: +#if defined(CONFIG_DEBUG_FS) + debugfs_remove_recursive(rv1106->dbg_codec); +#endif + rv1106_codec_sysfs_exit(rv1106); + + return ret; +} + +static void rv1106_platform_remove(struct platform_device *pdev) +{ + struct rv1106_codec_priv *rv1106 = + (struct rv1106_codec_priv *)platform_get_drvdata(pdev); + + clk_disable_unprepare(rv1106->mclk_acodec); + clk_disable_unprepare(rv1106->pclk_acodec); +#if defined(CONFIG_DEBUG_FS) + debugfs_remove_recursive(rv1106->dbg_codec); +#endif + rv1106_codec_sysfs_exit(rv1106); +} + +static struct platform_driver rv1106_codec_driver = { + .driver = { + .name = CODEC_DRV_NAME, + .of_match_table = of_match_ptr(rv1106_codec_of_match), + }, + .probe = rv1106_platform_probe, + .remove = rv1106_platform_remove, +}; +module_platform_driver(rv1106_codec_driver); + +MODULE_DESCRIPTION("ASoC RV1106 Codec Driver"); +MODULE_AUTHOR("Jason Zhu "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rv1106_codec.h b/sound/soc/codecs/rv1106_codec.h new file mode 100644 index 000000000..a62fd549f --- /dev/null +++ b/sound/soc/codecs/rv1106_codec.h @@ -0,0 +1,753 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * rv1106_codec.h - Rockchip RV1106 SoC Codec Driver + * + * Copyright (C) 2022 Rockchip Electronics Co., Ltd. + */ + +#ifndef __RV1106_CODEC_H__ +#define __RV1106_CODEC_H__ + +#define ACODEC_RESET_CTL 0x00 /* REG 0x00 */ +#define ACODEC_GLB_CON ACODEC_RESET_CTL +#define ACODEC_MUTE_DA_DITHER_CTL 0x04 /* REG 0x01 */ + +/* ADC DIGITAL REGISTERS */ +#define ACODEC_ADC_I2S_CTL0 0x08 /* REG 0x02 */ +#define ACODEC_ADC_I2S_CTL1 0x0c /* REG 0x03 */ +#define ACODEC_DAC_I2S_CTL0 0x10 /* REG 0x04 */ +#define ACODEC_DAC_I2S_CTL1 0x14 /* REG 0x05 */ +#define ACODEC_DAC_GAIN_SEL 0x18 /* REG 0x06 */ +#define ACODEC_DAC_L_BIST_MODE_SEL 0x1c /* REG 0x07 */ +#define ACODEC_ADC_L_DIG_VOL 0x20 /* REG 0x08 */ +#define ACODEC_ADC_R_DIG_VOL 0x24 /* REG 0x09 */ +#define ACODEC_ADC_HPF_PGA_CTL 0x28 /* REG 0x0a */ +#define ACODEC_INIT_DELAY_CNT1 0x2c /* REG 0x0b */ +#define ACODEC_INIT_DELAY_CNT2 0x30 /* REG 0x0c */ +#define ACODEC_ADC_BIST_MODE_SEL 0x34 /* REG 0x0d */ +#define ACODEC_DAC_CONFIG_OUTPUT 0x38 /* REG 0x0e */ +#define ACODEC_LINEOUT_CTL 0x80 /* REG 0x20 */ +#define ACODEC_CURRENT_CHARGE_CTL 0x84 /* REG 0x21 */ + +#define ACODEC_ADC_ANA_CTL0 0x88 /* REG 0x22 */ +#define ACODEC_ADC_ANA_CTL1 0x8c /* REG 0x23 */ +#define ACODEC_ADC_ANA_CTL2 0x90 /* REG 0x24 */ +#define ACODEC_ADC_ANA_CTL3 0x94 /* REG 0x25 */ +#define ACODEC_ADC_ANA_CTL4 0x98 /* REG 0x26 */ +#define ACODEC_ADC_ANA_CTL5 0x9c /* REG 0x27 */ +#define ACODEC_ADC_ANA_CTL6 0xa0 /* REG 0x28 */ + +#define ACODEC_DAC_ANA_CTL0 0xa4 /* REG 0x29 */ +#define ACODEC_DAC_ANA_CTL1 0xa8 /* REG 0x2a */ +#define ACODEC_DAC_ANA_CTL2 0xac /* REG 0x2b */ +#define ACODEC_DAC_HPMIX_CTL 0xbc /* REG 0x2f */ + +/* The description of the agc register for the left channel */ +#define ACODEC_ADC_PGA_AGC_L_CTL0 0x100 /* REG 0x40 */ +#define ACODEC_ADC_PGA_AGC_L_CTL1 0x104 /* REG 0x41 */ +#define ACODEC_ADC_PGA_AGC_L_CTL2 0x108 /* REG 0x42 */ +#define ACODEC_ADC_PGA_AGC_L_CTL3 0x10c /* REG 0x43 */ +#define ACODEC_ADC_PGA_AGC_L_CTL4 0x110 /* REG 0x44 */ +#define ACODEC_ADC_PGA_AGC_L_CTL5 0x114 /* REG 0x45 */ +#define ACODEC_ADC_PGA_AGC_L_CTL6 0x118 /* REG 0x46 */ +#define ACODEC_ADC_PGA_AGC_L_CTL7 0x11c /* REG 0x47 */ +#define ACODEC_ADC_PGA_AGC_L_CTL8 0x120 /* REG 0x48 */ +#define ACODEC_ADC_PGA_AGC_L_CTL9 0x124 /* REG 0x49 */ + +/* The description of the agc register for the right channel */ +#define ACODEC_ADC_PGA_AGC_R_CTL0 0x140 /* REG 0x50 */ +#define ACODEC_ADC_PGA_AGC_R_CTL1 0x144 /* REG 0x51 */ +#define ACODEC_ADC_PGA_AGC_R_CTL2 0x148 /* REG 0x52 */ +#define ACODEC_ADC_PGA_AGC_R_CTL3 0x14c /* REG 0x53 */ +#define ACODEC_ADC_PGA_AGC_R_CTL4 0x150 /* REG 0x54 */ +#define ACODEC_ADC_PGA_AGC_R_CTL5 0x154 /* REG 0x55 */ +#define ACODEC_ADC_PGA_AGC_R_CTL6 0x158 /* REG 0x56 */ +#define ACODEC_ADC_PGA_AGC_R_CTL7 0x15c /* REG 0x57 */ +#define ACODEC_ADC_PGA_AGC_R_CTL8 0x160 /* REG 0x58 */ +#define ACODEC_ADC_PGA_AGC_R_CTL9 0x164 /* REG 0x59 */ + +#define ACODEC_REG_MAX ACODEC_ADC_PGA_AGC_R_CTL9 + +/* ACODEC_RESET_CTL */ +#define ACODEC_CODEC_BIST_MSK (1 << 7) +#define ACODEC_CODEC_BIST_WORK (1 << 7) +#define ACODEC_CODEC_BIST_RST (0 << 7) +#define ACODEC_CODEC_CORE_RST_MSK (1 << 1) +#define ACODEC_CODEC_CORE_WORK (1 << 1) +#define ACODEC_CODEC_CORE_RST (0 << 1) +#define ACODEC_CODEC_SYS_RST_MSK (1 << 0) +#define ACODEC_CODEC_SYS_WORK (1 << 0) +#define ACODEC_CODEC_SYS_RST (0 << 0) + +/* ACODEC_MUTE_DA_DITHER_CTL */ +#define ACODEC_DAC_MUTE_MSK (1 << 7) +#define ACODEC_DAC_MUTE_EN (1 << 7) +#define ACODEC_DAC_MUTE_DIS (0 << 7) +#define ACODEC_DITHER_LEVEL_SEL (1 << 3) +#define ACODEC_DA_MSK (1 << 2) +#define ACODEC_DA_EN (1 << 2) +#define ACODEC_DA_DIS (0 << 2) +#define ACODEC_DITHER_MSK (1 << 1) +#define ACODEC_DITHER_EN (1 << 1) +#define ACODEC_DITHER_DIS (0 << 1) +#define ACODEC_DITHER_SIGN (1 << 0) + +/* ACODEC_ADC_I2S_CTL0 */ +#define ACODEC_ADC_I2S_LRC_POL_MSK (1 << 7) +#define ACODEC_ADC_I2S_LRC_POL_REVERSAL (1 << 7) +#define ACODEC_ADC_I2S_LRC_POL_NORMAL (0 << 7) +#define ACODEC_ADC_I2S_VALID_LEN_SFT 5 +#define ACODEC_ADC_I2S_VALID_LEN_MSK (0x3 << ACODEC_ADC_I2S_VALID_LEN_SFT) +#define ACODEC_ADC_I2S_VALID_LEN_32BITS (0x3 << ACODEC_ADC_I2S_VALID_LEN_SFT) +#define ACODEC_ADC_I2S_VALID_LEN_24BITS (0x2 << ACODEC_ADC_I2S_VALID_LEN_SFT) +#define ACODEC_ADC_I2S_VALID_LEN_20BITS (0x1 << ACODEC_ADC_I2S_VALID_LEN_SFT) +#define ACODEC_ADC_I2S_VALID_LEN_16BITS (0x0 << ACODEC_ADC_I2S_VALID_LEN_SFT) +#define ACODEC_ADC_I2S_MODE_SFT 3 +#define ACODEC_ADC_I2S_MODE_MSK (0x3 << ACODEC_ADC_I2S_MODE_SFT) +#define ACODEC_ADC_I2S_MODE_PCM (0x3 << ACODEC_ADC_I2S_MODE_SFT) +#define ACODEC_ADC_I2S_MODE_I2S (0x2 << ACODEC_ADC_I2S_MODE_SFT) +#define ACODEC_ADC_I2S_MODE_LJ (0x1 << ACODEC_ADC_I2S_MODE_SFT) +#define ACODEC_ADC_I2S_MODE_RJ (0x0 << ACODEC_ADC_I2S_MODE_SFT) +#define ACODEC_ADC_I2S_SEL_DATA_MSK (1 << 2) +#define ACODEC_ADC_I2S_SEL_ADC_DATA (1 << 2) +#define ACODEC_ADC_I2S_SEL_ADCL_DACL_DATA (0 << 2) +#define ACODEC_ADC_I2S_DATA_SEL 0 +#define ACODEC_ADC_I2S_DATA_SEL_MSK (0x3 << ACODEC_ADC_I2S_DATA_SEL) +#define ACODEC_ADC_I2S_DATA_SWAP (0x3 << ACODEC_ADC_I2S_DATA_SEL) +#define ACODEC_ADC_I2S_DATA_SEL_LEFT (0x2 << ACODEC_ADC_I2S_DATA_SEL) +#define ACODEC_ADC_I2S_DATA_SEL_RIGHT (0x1 << ACODEC_ADC_I2S_DATA_SEL) +#define ACODEC_ADC_I2S_DATA_SEL_NORMAL (0x0 << ACODEC_ADC_I2S_DATA_SEL) + +/* ACODEC_ADC_I2S_CTL1 */ +#define ACODEC_DAC_IO_MODE_MSK (0x1 << 7) +#define ACODEC_DAC_IO_MODE_MASTER (0x1 << 7) +#define ACODEC_DAC_IO_MODE_SLAVE (0x0 << 7) +#define ACODEC_DAC_MODE_MSK (0x1 << 6) +#define ACODEC_DAC_MODE_MASTER (0x1 << 6) +#define ACODEC_DAC_MODE_SLAVE (0x0 << 6) +#define ACODEC_ADC_IO_MODE_MSK (0x1 << 5) +#define ACODEC_ADC_IO_MODE_MASTER (0x1 << 5) +#define ACODEC_ADC_IO_MODE_SLAVE (0x0 << 5) +#define ACODEC_ADC_MODE_MSK (0x1 << 4) +#define ACODEC_ADC_MODE_MASTER (0x1 << 4) +#define ACODEC_ADC_MODE_SLAVE (0x0 << 4) +#define ACODEC_ADC_I2S_FRAME_LEN_SFT 2 +#define ACODEC_ADC_I2S_FRAME_LEN_MSK (0x3 << ACODEC_ADC_I2S_FRAME_LEN_SFT) +#define ACODEC_ADC_I2S_FRAME_32BITS (0x3 << ACODEC_ADC_I2S_FRAME_LEN_SFT) +#define ACODEC_ADC_I2S_FRAME_24BITS (0x1 << ACODEC_ADC_I2S_FRAME_LEN_SFT) +#define ACODEC_ADC_I2S_MSK (0x1 << 1) +#define ACODEC_ADC_I2S_WORK (0x1 << 1) +#define ACODEC_ADC_I2S_RESET (0x0 << 1) +#define ACODEC_ADC_I2S_BIT_CLK_POL_MSK (0x1 << 0) +#define ACODEC_ADC_I2S_BIT_CLK_POL_REVERSAL (0x1 << 0) +#define ACODEC_ADC_I2S_BIT_CLK_POL_NORMAL (0x0 << 0) + +/* ACODEC_DAC_I2S_CTL0 */ +#define ACODEC_DAC_I2S_LRC_POL_MSK (0x1 << 7) +#define ACODEC_DAC_I2S_LRC_POL_REVERSAL (0x1 << 7) +#define ACODEC_DAC_I2S_LRC_POL_NORMAL (0x0 << 7) +#define ACODEC_DAC_I2S_VALID_LEN_SFT 5 +#define ACODEC_DAC_I2S_VALID_LEN_MSK (0x3 << ACODEC_DAC_I2S_VALID_LEN_SFT) +#define ACODEC_DAC_I2S_VALID_LEN_32BITS (0x3 << ACODEC_DAC_I2S_VALID_LEN_SFT) +#define ACODEC_DAC_I2S_VALID_LEN_24BITS (0x2 << ACODEC_DAC_I2S_VALID_LEN_SFT) +#define ACODEC_DAC_I2S_VALID_LEN_20BITS (0x1 << ACODEC_DAC_I2S_VALID_LEN_SFT) +#define ACODEC_DAC_I2S_VALID_LEN_16BITS (0x0 << ACODEC_DAC_I2S_VALID_LEN_SFT) +#define ACODEC_DAC_I2S_MODE_SFT 3 +#define ACODEC_DAC_I2S_MODE_MSK (0x3 << ACODEC_DAC_I2S_MODE_SFT) +#define ACODEC_DAC_I2S_MODE_PCM (0x3 << ACODEC_DAC_I2S_MODE_SFT) +#define ACODEC_DAC_I2S_MODE_I2S (0x2 << ACODEC_DAC_I2S_MODE_SFT) +#define ACODEC_DAC_I2S_MODE_LJ (0x1 << ACODEC_DAC_I2S_MODE_SFT) +#define ACODEC_DAC_I2S_MODE_RJ (0x0 << ACODEC_DAC_I2S_MODE_SFT) +#define ACODEC_DAC_I2S_LR_MSK (0x1 << 2) +#define ACODEC_DAC_I2S_LR_SWAP (0x1 << 2) +#define ACODEC_DAC_I2S_LR_NORMAL (0x0 << 2) + +/* ACODEC_DAC_I2S_CTL1 */ +#define ACODEC_DAC_DE_EMPHASIS_FILTER_SFT 4 +#define ACODEC_DAC_DE_EMPHASIS_FILTER_MSK (0x3 << ACODEC_DAC_I2S_VALID_LEN_SFT) +#define ACODEC_DAC_48_DE_EMPHASIS_FILTER (0x3 << ACODEC_DAC_I2S_VALID_LEN_SFT) +#define ACODEC_DAC_441_DE_EMPHASIS_FILTER (0x2 << ACODEC_DAC_I2S_VALID_LEN_SFT) +#define ACODEC_DAC_32_DE_EMPHASIS_FILTER (0x1 << ACODEC_DAC_I2S_VALID_LEN_SFT) +#define ACODEC_DAC_NO_DE_EMPHASIS_FILTER (0x0 << ACODEC_DAC_I2S_VALID_LEN_SFT) +#define ACODEC_DAC_I2S_FRAME_LEN_SFT 2 +#define ACODEC_DAC_I2S_FRAME_LEN_MSK (0x3 << ACODEC_DAC_I2S_FRAME_LEN_SFT) +#define ACODEC_DAC_I2S_FRAME_32BITS (0x3 << ACODEC_DAC_I2S_FRAME_LEN_SFT) +#define ACODEC_DAC_I2S_FRAME_24BITS (0x2 << ACODEC_DAC_I2S_FRAME_LEN_SFT) +#define ACODEC_DAC_I2S_FRAME_20BITS (0x1 << ACODEC_DAC_I2S_FRAME_LEN_SFT) +#define ACODEC_DAC_I2S_FRAME_16BITS (0x0 << ACODEC_DAC_I2S_FRAME_LEN_SFT) +#define ACODEC_DAC_I2S_MSK (0x1 << 1) +#define ACODEC_DAC_I2S_WORK (0x1 << 1) +#define ACODEC_DAC_I2S_RESET (0x0 << 1) +#define ACODEC_DAC_I2S_BIT_CLK_POL_MSK (0x1 << 0) +#define ACODEC_DAC_I2S_BIT_CLK_POL_REVERSAL (0x1 << 0) +#define ACODEC_DAC_I2S_BIT_CLK_POL_NORMAL (0x0 << 0) + +/* ACODEC_DAC_GAIN_SEL */ +#define ACODEC_DAC_DIG_GAIN_SFT 0 +#define ACODEC_DAC_DIG_GAIN_MSK (0xff << ACODEC_DAC_DIG_GAIN_SFT) +#define ACODEC_DAC_DIG_GAIN(x) ((x) & ACODEC_DAC_DIG_GAIN_MSK) +#define ACODEC_DAC_DIG_0DB 0xed + +/* ACODEC_DAC_L_BIST_MODE_SEL */ +#define ACODEC_DAC_L_CH_BIST_SFT 4 +#define ACODEC_DAC_L_CH_BIST_MSK (0x3 << ACODEC_DAC_L_CH_BIST_SFT) +#define ACODEC_DAC_L_CH_BIST_SINE (0x1 << ACODEC_DAC_L_CH_BIST_SFT) +#define ACODEC_DAC_L_CH_BIST_LEFT (0x0 << ACODEC_DAC_L_CH_BIST_SFT) /* normal mode */ + +/* ACODEC_ADC_L_DIG_VOL */ +#define ACODEC_ADC_L_DIG_VOL_MAX 0xff +#define ACODEC_ADC_L_DIG_VOL_MIN 0 +#define ACODEC_ADC_L_DIG_VOL_SFT 0 +#define ACODEC_ADC_L_DIG_VOL_MUTE 0 +#define ACODEC_ADC_L_DIG_VOL_0DB 0xc3 + +/* ACODEC_ADC_R_DIG_VOL */ +#define ACODEC_ADC_R_DIG_VOL_MAX 0xff +#define ACODEC_ADC_R_DIG_VOL_MIN 0 +#define ACODEC_ADC_R_DIG_VOL_SFT 0 +#define ACODEC_ADC_R_DIG_VOL_MUTE 0 +#define ACODEC_ADC_R_DIG_VOL_0DB 0xc3 + +/* ACODEC_ADC_HPF_PGA_CTL */ +#define ACODEC_ADC_FILTER_MSK (1 << 7) +#define ACODEC_ADC_FILTER_EN (1 << 7) +#define ACODEC_ADC_FILTER_DIS (0 << 7) +#define ACODEC_ADC_AGC_MSK (1 << 6) +#define ACODEC_ADC_FILTER_OUTPUT (1 << 6) +#define ACODEC_ADC_SINC_OUTPUT (0 << 6) +#define ACODEC_ADC_L_PGA_MSK (1 << 5) +#define ACODEC_ADC_PGA_ALCL_EN (1 << 5) +#define ACODEC_ADC_PGA_ALCL_DIS (0 << 5) +#define ACODEC_ADC_R_PGA_MSK (1 << 4) +#define ACODEC_ADC_PGA_ALCR_EN (1 << 4) +#define ACODEC_ADC_PGA_ALCR_DIS (0 << 4) +#define ACODEC_ADC_HPF_SFT 2 +#define ACODEC_ADC_HPF_MSK (3 << ACODEC_ADC_HPF_SFT) +#define ACODEC_ADC_HPF_EN (3 << ACODEC_ADC_HPF_SFT) +#define ACODEC_ADC_HPF_DIS (0 << ACODEC_ADC_HPF_SFT) +#define ACODEC_ADC_R_DATA_POL_INV_MSK (1 << 1) +#define ACODEC_ADC_R_DATA_POL_INV_EN (1 << 1) +#define ACODEC_ADC_R_DATA_POL_INV_DIS (0 << 1) +#define ACODEC_ADC_L_DATA_POL_INV_MSK (1 << 0) +#define ACODEC_ADC_L_DATA_POL_INV_EN (1 << 0) +#define ACODEC_ADC_L_DATA_POL_INV_DIS (0 << 0) + +/* ACODEC_ADC_BIST_MODE_SEL */ +#define ACODEC_ADC_R_BIST_SFT 6 +#define ACODEC_ADC_R_BIST_MSK (0x3 << ACODEC_ADC_R_BIST_SFT) +#define ACODEC_ADC_R_BIST_SINE (0x1 << ACODEC_ADC_R_BIST_SFT) +#define ACODEC_ADC_BIST_RIGHT (0x0 << ACODEC_ADC_R_BIST_SFT) /* normal mode */ +#define ACODEC_ADC_L_BIST_SFT 4 +#define ACODEC_ADC_L_BIST_MSK (0x3 << ACODEC_ADC_L_BIST_SFT) +#define ACODEC_ADC_L_BIST_SINE (0x1 << ACODEC_ADC_L_BIST_SFT) +#define ACODEC_ADC_BIST_LEFT (0x0 << ACODEC_ADC_L_BIST_SFT) /* normal mode */ + +/* ACODEC_LINEOUT_CTL */ +#define ACODEC_DAC_LINEOUT_EN_SFT 7 +#define ACODEC_DAC_LINEOUT_EN_WORK (0x1 << ACODEC_DAC_LINEOUT_EN_SFT) +#define ACODEC_DAC_LINEOUT_EN_RST (0x0 << ACODEC_DAC_LINEOUT_EN_SFT) +#define ACODEC_DAC_LINEOUT_INI_SFT 6 +#define ACODEC_DAC_LINEOUT_INI_WORK (0x1 << ACODEC_DAC_LINEOUT_INI_SFT) +#define ACODEC_DAC_LINEOUT_INI_RST (0x0 << ACODEC_DAC_LINEOUT_INI_SFT) +#define ACODEC_DAC_IBIAS_SEL_SFT 0 +#define ACODEC_DAC_IBIAS_SEL_MSK (0xf << ACODEC_DAC_IBIAS_SEL_SFT) + +/* ACODEC_CURRENT_CHARGE_CTL */ +#define ACODEC_ADC_CURRENT_CHARGE_SFT 0 +#define ACODEC_ADC_CURRENT_CHARGE_MSK (0xff << ACODEC_ADC_CURRENT_CHARGE_SFT) +/* + * 1: Choose the current I + * 0: Don't choose the current I + */ +#define ACODEC_ADC_SEL_I(x) (x & 0xff) + +/* ACODEC_ADC_ANA_CTL0 */ +#define ACODEC_ADC_REF_VOL_MSK (0x1 << 5) +#define ACODEC_ADC_REF_VOL_EN (0x1 << 5) +#define ACODEC_ADC_REF_VOL_DIS (0x0 << 5) +#define ACODEC_ADC_IBIAS_MSK (0x1 << 4) +#define ACODEC_ADC_IBIAS_EN (0x1 << 4) +#define ACODEC_ADC_IBIAS_DIS (0x0 << 4) +#define ACODEC_MICBIAS_SFT 3 +#define ACODEC_MICBIAS_MSK (0x1 << 3) +#define ACODEC_MICBIAS_WORK (0x1 << 3) +#define ACODEC_MICBIAS_RST (0x0 << 3) +#define ACODEC_ADC_LEVEL_RANGE_MICBIAS_SFT 0 +#define ACODEC_ADC_LEVEL_RANGE_MICBIAS_MSK (0x7 << ACODEC_ADC_LEVEL_RANGE_MICBIAS_SFT) +#define ACODEC_ADC_MICBIAS_VOLT_0_975 (0x7 << ACODEC_ADC_LEVEL_RANGE_MICBIAS_SFT) +#define ACODEC_ADC_MICBIAS_VOLT_0_95 (0x6 << ACODEC_ADC_LEVEL_RANGE_MICBIAS_SFT) +#define ACODEC_ADC_MICBIAS_VOLT_0_925 (0x5 << ACODEC_ADC_LEVEL_RANGE_MICBIAS_SFT) +#define ACODEC_ADC_MICBIAS_VOLT_0_9 (0x4 << ACODEC_ADC_LEVEL_RANGE_MICBIAS_SFT) +#define ACODEC_ADC_MICBIAS_VOLT_0_875 (0x3 << ACODEC_ADC_LEVEL_RANGE_MICBIAS_SFT) +#define ACODEC_ADC_MICBIAS_VOLT_0_85 (0x2 << ACODEC_ADC_LEVEL_RANGE_MICBIAS_SFT) +#define ACODEC_ADC_MICBIAS_VOLT_0_825 (0x1 << ACODEC_ADC_LEVEL_RANGE_MICBIAS_SFT) +#define ACODEC_ADC_MICBIAS_VOLT_0_8 (0x0 << ACODEC_ADC_LEVEL_RANGE_MICBIAS_SFT) + +/* ACODEC_ADC_ANA_CTL1 */ +#define ACODEC_ADC_L_MIC_MSK (0x1 << 7) +#define ACODEC_ADC_L_MIC_WORK (0x1 << 7) +#define ACODEC_ADC_L_MIC_MUTE (0x0 << 7) +#define ACODEC_ADC_L_MIC_SIGNAL_MSK (0x1 << 6) +#define ACODEC_ADC_L_MIC_SIGNAL_WORK (0x1 << 6) +#define ACODEC_ADC_L_MIC_SIGNAL_INIT (0x0 << 6) +#define ACODEC_ADC_L_REF_VOL_BUF_MSK (0x1 << 5) +#define ACODEC_ADC_L_REF_VOL_BUF_EN (0x1 << 5) +#define ACODEC_ADC_L_REF_VOL_BUF_DIS (0x0 << 5) +#define ACODEC_ADC_L_ZERO_CROSS_DET_MSK (0x1 << 4) +#define ACODEC_ADC_L_ZERO_CROSS_DET_EN (0x1 << 4) +#define ACODEC_ADC_L_ZERO_CROSS_DET_DIS (0x0 << 4) +#define ACODEC_ADC_R_MIC_MSK (0x1 << 3) +#define ACODEC_ADC_R_MIC_WORK (0x1 << 3) +#define ACODEC_ADC_R_MIC_MUTE (0x0 << 3) +#define ACODEC_ADC_R_MIC_SIGNAL_MSK (0x1 << 2) +#define ACODEC_ADC_R_MIC_SIGNAL_WORK (0x1 << 2) +#define ACODEC_ADC_R_MIC_SIGNAL_INIT (0x0 << 2) +#define ACODEC_ADC_R_REF_VOL_BUF_MSK (0x1 << 1) +#define ACODEC_ADC_R_REF_VOL_BUF_EN (0x1 << 1) +#define ACODEC_ADC_R_REF_VOL_BUF_DIS (0x0 << 1) +#define ACODEC_ADC_R_ZERO_CROSS_DET_MSK (0x1 << 0) +#define ACODEC_ADC_R_ZERO_CROSS_DET_EN (0x1 << 0) +#define ACODEC_ADC_R_ZERO_CROSS_DET_DIS (0x0 << 0) + +/* ACODEC_ADC_ANA_CTL2 */ +#define ACODEC_ADC_MIC_GAIN_MAX 0x3 +#define ACODEC_ADC_MIC_GAIN_MIN 0x1 +#define ACODEC_ADC_L_MIC_GAIN_SFT 6 +#define ACODEC_ADC_L_MIC_GAIN_MSK (0x3 << ACODEC_ADC_L_MIC_GAIN_SFT) +#define ACODEC_ADC_L_MIC_GAIN_12DB (0x3 << ACODEC_ADC_L_MIC_GAIN_SFT) +#define ACODEC_ADC_L_MIC_GAIN_20DB (0x2 << ACODEC_ADC_L_MIC_GAIN_SFT) +#define ACODEC_ADC_L_MIC_GAIN_0DB (0x1 << ACODEC_ADC_L_MIC_GAIN_SFT) +#define ACODEC_ADC_R_MIC_GAIN_SFT 4 +#define ACODEC_ADC_R_MIC_GAIN_MSK (0x3 << ACODEC_ADC_R_MIC_GAIN_SFT) +#define ACODEC_ADC_R_MIC_GAIN_12DB (0x3 << ACODEC_ADC_R_MIC_GAIN_SFT) +#define ACODEC_ADC_R_MIC_GAIN_20DB (0x2 << ACODEC_ADC_R_MIC_GAIN_SFT) +#define ACODEC_ADC_R_MIC_GAIN_0DB (0x1 << ACODEC_ADC_R_MIC_GAIN_SFT) +#define ACODEC_ADC_IBIAS_SEL_SFT 0 +#define ACODEC_ADC_IBIAS_SEL_MSK (0xf << ACODEC_ADC_IBIAS_SEL_SFT) + +/* ACODEC_ADC_ANA_CTL3 */ +#define ACODEC_ADC_L_MODE_SEL_SFT 6 +#define ACODEC_ADC_L_MODE_SEL_MSK (0x3 << ACODEC_ADC_L_MODE_SEL_SFT) +#define ACODEC_ADC_L_FULL_DIFFER2 (0x2 << ACODEC_ADC_L_MODE_SEL_SFT) /* Only used for rv1103 acodec */ +#define ACODEC_ADC_L_SINGLE_END (0x1 << ACODEC_ADC_L_MODE_SEL_SFT) +#define ACODEC_ADC_L_FULL_DIFFER (0x0 << ACODEC_ADC_L_MODE_SEL_SFT) +#define ACODEC_ADC_L_MSK (0x1 << 5) +#define ACODEC_ADC_L_EN (0x1 << 5) +#define ACODEC_ADC_L_DIS (0x0 << 5) +#define ACODEC_MIC_L_MSK (0x1 << 4) +#define ACODEC_MIC_L_EN (0x1 << 4) +#define ACODEC_MIC_L_DIS (0x0 << 4) +#define ACODEC_ADC_R_MODE_SEL_SFT 2 +#define ACODEC_ADC_R_MODE_SEL_MSK (0x3 << ACODEC_ADC_R_MODE_SEL_SFT) +#define ACODEC_ADC_R_SINGLE_END (0x1 << ACODEC_ADC_R_MODE_SEL_SFT) +#define ACODEC_ADC_R_FULL_DIFFER (0x0 << ACODEC_ADC_R_MODE_SEL_SFT) +#define ACODEC_ADC_R_MSK (0x1 << 1) +#define ACODEC_ADC_R_EN (0x1 << 1) +#define ACODEC_ADC_R_DIS (0x0 << 1) +#define ACODEC_MIC_R_MSK (0x1 << 0) +#define ACODEC_MIC_R_EN (0x1 << 0) +#define ACODEC_MIC_R_DIS (0x0 << 0) + +/* ACODEC_ADC_ANA_CTL4 */ +#define ACODEC_ADC_L_ALC_GAIN_MAX 0x1f +#define ACODEC_ADC_L_ALC_GAIN_MIN 0 +#define ACODEC_ADC_L_ALC_GAIN_SFT 0 +#define ACODEC_ADC_L_ALC_GAIN_MSK (0x1f << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_37_5 (0x1f << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_36 (0x1e << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_34_5 (0x1d << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_33 (0x1c << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_31_5 (0x1b << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_30 (0x1a << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_28_5 (0x19 << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_27 (0x18 << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_25_5 (0x17 << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_24 (0x16 << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_22_5 (0x15 << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_21 (0x14 << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_19_5 (0x13 << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_18 (0x12 << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_16_5 (0x11 << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_15 (0x10 << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_13_5 (0x0f << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_12 (0x0e << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_10_5 (0x0d << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_9 (0x0c << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_7_5 (0x0b << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_6 (0x0a << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_4_5 (0x09 << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_3 (0x08 << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_PDB_1_5 (0x07 << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_0DB (0x06 << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_NDB_1_5 (0x05 << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_NDB_3 (0x04 << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_NDB_4_5 (0x03 << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_NDB_6 (0x02 << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_NDB_7_5 (0x01 << ACODEC_ADC_L_ALC_GAIN_SFT) +#define ACODEC_ADC_L_ALC_GAIN_NDB_9 (0x00 << ACODEC_ADC_L_ALC_GAIN_SFT) + +/* ACODEC_ADC_ANA_CTL5 */ +#define ACODEC_ADC_R_ALC_GAIN_MAX 0x1f +#define ACODEC_ADC_R_ALC_GAIN_MIN 0 +#define ACODEC_ADC_R_ALC_GAIN_SFT 0 +#define ACODEC_ADC_R_ALC_GAIN_MSK (0x1f << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_37_5 (0x1f << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_36 (0x1e << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_34_5 (0x1d << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_33 (0x1c << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_31_5 (0x1b << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_30 (0x1a << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_28_5 (0x19 << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_27 (0x18 << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_25_5 (0x17 << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_24 (0x16 << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_22_5 (0x15 << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_21 (0x14 << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_19_5 (0x13 << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_18 (0x12 << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_16_5 (0x11 << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_15 (0x10 << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_13_5 (0x0f << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_12 (0x0e << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_10_5 (0x0d << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_9 (0x0c << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_7_5 (0x0b << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_6 (0x0a << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_4_5 (0x09 << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_3 (0x08 << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_PDB_1_5 (0x07 << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_0DB (0x06 << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_NDB_1_5 (0x05 << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_NDB_3 (0x04 << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_NDB_4_5 (0x03 << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_NDB_6 (0x02 << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_NDB_7_5 (0x01 << ACODEC_ADC_R_ALC_GAIN_SFT) +#define ACODEC_ADC_R_ALC_GAIN_NDB_9 (0x00 << ACODEC_ADC_R_ALC_GAIN_SFT) + +/* ACODEC_ADC_ANA_CTL6 */ +#define ACODEC_ADC_L_ALC_MSK (0x1 << 7) +#define ACODEC_ADC_L_ALC_WORK (0x1 << 7) +#define ACODEC_ADC_L_ALC_INIT (0x0 << 7) +#define ACODEC_ADC_L_CLK_MSK (0x1 << 6) +#define ACODEC_ADC_L_CLK_WORK (0x1 << 6) +#define ACODEC_ADC_L_CLK_RST (0x0 << 6) +#define ACODEC_ADC_L_WORK (0x1 << 5) +#define ACODEC_ADC_L_INIT (0x0 << 5) +#define ACODEC_ADC_L_SIGNAL_EN (0x1 << 4) +#define ACODEC_ADC_L_SIGNAL_DIS (0x0 << 4) +#define ACODEC_ADC_R_ALC_MSK (0x1 << 3) +#define ACODEC_ADC_R_ALC_WORK (0x1 << 3) +#define ACODEC_ADC_R_ALC_INIT (0x0 << 3) +#define ACODEC_ADC_R_CLK_MSK (0x1 << 2) +#define ACODEC_ADC_R_CLK_WORK (0x1 << 2) +#define ACODEC_ADC_R_CLK_RST (0x0 << 2) +#define ACODEC_ADC_R_WORK (0x1 << 1) +#define ACODEC_ADC_R_INIT (0x0 << 1) +#define ACODEC_ADC_R_SIGNAL_EN (0x1 << 0) +#define ACODEC_ADC_R_SIGNAL_DIS (0x0 << 0) + +/* ACODEC_DAC_ANA_CTL0 */ +#define ACODEC_DAC_IBIAS_MSK (0x1 << 7) +#define ACODEC_DAC_IBIAS_EN (0x1 << 7) +#define ACODEC_DAC_IBIAS_DIS (0x0 << 7) +#define ACODEC_DAC_L_REF_VOL_BUF_MSK (0x1 << 6) +#define ACODEC_DAC_L_REF_VOL_BUF_EN (0x1 << 6) +#define ACODEC_DAC_L_REF_VOL_BUF_DIS (0x0 << 6) +#define ACODEC_DAC_L_REF_POP_SOUND_MSK (0x3 << 4) +#define ACODEC_DAC_L_REF_POP_SOUND_WORK (0x2 << 4) +#define ACODEC_DAC_L_REF_POP_SOUND_INIT (0x1 << 4) +#define ACODEC_DAC_L_REF_POP_SOUND_DIS (0x0 << 4) +#define ACODEC_DAC_L_REF_VOL_MSK (0x1 << 3) +#define ACODEC_DAC_L_REF_VOL_EN (0x1 << 3) +#define ACODEC_DAC_L_REF_VOL_DIS (0x0 << 3) +#define ACODEC_DAC_L_CLK_MSK (0x1 << 2) +#define ACODEC_DAC_L_CLK_EN (0x1 << 2) +#define ACODEC_DAC_L_CLK_DIS (0x0 << 2) +#define ACODEC_DAC_SRC_SIGNAL_MSK (0x1 << 1) +#define ACODEC_DAC_SRC_SIGNAL_EN (0x1 << 1) +#define ACODEC_DAC_SRC_SIGNAL_DIS (0x0 << 1) +#define ACODEC_DAC_L_SIGNAL_MSK (0x1 << 0) +#define ACODEC_DAC_L_SIGNAL_WORK (0x1 << 0) +#define ACODEC_DAC_L_SIGNAL_INIT (0x0 << 0) + +/* ACODEC_DAC_ANA_CTL1 */ +#define ACODEC_DAC_L_LINEOUT_MUTE_MSK (0x1 << 6) +#define ACODEC_DAC_L_LINEOUT_MUTE (0x0 << 6) +#define ACODEC_DAC_L_LINEOUT_WORK (0x1 << 6) +#define ACODEC_DAC_L_LINEOUT_SIGNAL_MSK (0x1 << 5) +#define ACODEC_DAC_L_LINEOUT_SIGNAL_WORK (0x1 << 5) +#define ACODEC_DAC_L_LINEOUT_SIGNAL_INIT (0x0 << 5) +#define ACODEC_DAC_L_LINEOUT_MSK (0x1 << 4) +#define ACODEC_DAC_L_LINEOUT_EN (0x1 << 4) +#define ACODEC_DAC_L_LINEOUT_DIS (0x0 << 4) +#define ACODEC_DAC_DRV_STRENGTH_SFT 0 +#define ACODEC_DAC_DRV_STRENGTH_MSK (0xf << ACODEC_DAC_DRV_STRENGTH_SFT) +#define ACODEC_DAC_DRV_STRENGTH_20_4 (0x8 << ACODEC_DAC_DRV_STRENGTH_SFT) +#define ACODEC_DAC_DRV_STRENGTH_22_7 (0x7 << ACODEC_DAC_DRV_STRENGTH_SFT) +#define ACODEC_DAC_DRV_STRENGTH_25_7 (0x6 << ACODEC_DAC_DRV_STRENGTH_SFT) +#define ACODEC_DAC_DRV_STRENGTH_29_7 (0x5 << ACODEC_DAC_DRV_STRENGTH_SFT) +#define ACODEC_DAC_DRV_STRENGTH_35_5 (0x4 << ACODEC_DAC_DRV_STRENGTH_SFT) +#define ACODEC_DAC_DRV_STRENGTH_44_2 (0x3 << ACODEC_DAC_DRV_STRENGTH_SFT) +#define ACODEC_DAC_DRV_STRENGTH_60_1 (0x2 << ACODEC_DAC_DRV_STRENGTH_SFT) +#define ACODEC_DAC_DRV_STRENGTH_100 (0x1 << ACODEC_DAC_DRV_STRENGTH_SFT) + +/* ACODEC_DAC_ANA_CTL2 */ +#define ACODEC_DAC_LINEOUT_GAIN_MAX 0x1e +#define ACODEC_DAC_LINEOUT_GAIN_MIN 0 +#define ACODEC_DAC_LINEOUT_GAIN_SFT 0 +#define ACODEC_DAC_LINEOUT_GAIN_MSK (0x1f << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_PDB_6_0 (0x1f << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_PDB_6 (0x1e << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_PDB_4_5 (0x1d << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_PDB_3 (0x1c << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_PDB_1_5 (0x1b << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_0DB (0x1a << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_1_5 (0x19 << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_3 (0x18 << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_4_5 (0x17 << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_6 (0x16 << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_7_5 (0x15 << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_9 (0x14 << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_10_5 (0x13 << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_12 (0x12 << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_13_5 (0x11 << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_15 (0x10 << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_16_5 (0x0f << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_18 (0x0e << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_19_5 (0x0d << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_21 (0x0c << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_22_5 (0x0b << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_24 (0x0a << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_25_5 (0x09 << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_27 (0x08 << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_28_5 (0x07 << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_30 (0x06 << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_31_5 (0x05 << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_33 (0x04 << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_34_5 (0x03 << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_36 (0x02 << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_37_5 (0x01 << ACODEC_DAC_LINEOUT_GAIN_SFT) +#define ACODEC_DAC_LINEOUT_GAIN_NDB_39 (0x00 << ACODEC_DAC_LINEOUT_GAIN_SFT) + +/* ACODEC_DAC_HPMIX_CTL */ +#define ACODEC_DAC_HPMIX_MSK (0x1 << 7) +#define ACODEC_DAC_HPMIX_EN (0x1 << 7) +#define ACODEC_DAC_HPMIX_DIS (0x0 << 7) +#define ACODEC_DAC_HPMIX_GAIN_SFT 5 +#define ACODEC_DAC_HPMIX_GAIN_MAX 2 +#define ACODEC_DAC_HPMIX_GAIN_MIN 1 +#define ACODEC_DAC_HPMIX_GAIN_MSK (0x3 << ACODEC_DAC_HPMIX_GAIN_SFT) +#define ACODEC_DAC_HPMIX_GAIN_6DB (0x2 << ACODEC_DAC_HPMIX_GAIN_SFT) +#define ACODEC_DAC_HPMIX_GAIN_0DB (0x1 << ACODEC_DAC_HPMIX_GAIN_SFT) +#define ACODEC_DAC_HPMIX_MDL_MSK (0x1 << 4) +#define ACODEC_DAC_HPMIX_MDL_WORK (0x1 << 4) +#define ACODEC_DAC_HPMIX_MDL_INIT (0x0 << 4) +#define ACODEC_DAC_HPMIX_MUTE_MSK (0x1 << 3) +#define ACODEC_DAC_HPMIX_WORK (0x1 << 3) +#define ACODEC_DAC_HPMIX_MUTE (0x0 << 3) +#define ACODEC_DAC_HPMIX_SEL_SFT 0 +#define ACODEC_DAC_HPMIX_SEL_MSK (0x7 << ACODEC_DAC_HPMIX_SEL_SFT) +#define ACODEC_DAC_HPMIX_ADCR (0x4 << ACODEC_DAC_HPMIX_SEL_SFT) +#define ACODEC_DAC_HPMIX_ADCL (0x2 << ACODEC_DAC_HPMIX_SEL_SFT) +#define ACODEC_DAC_HPMIX_I2S (0x1 << ACODEC_DAC_HPMIX_SEL_SFT) + +/* ACODEC_ADC_PGA_AGC_L_CTL0 */ +#define ACODEC_GAIN_ATTACK_MSK (1 << 6) +#define ACODEC_GAIN_ATTACK_JACK (1 << 6) +#define ACODEC_GAIN_ATTACK_NORMAL (0 << 6) +#define ACODEC_CTRL_GEN_SFT 4 +#define ACODEC_CTRL_GEN_MSK (0x3 << ACODEC_ALC_CTRL_GEN_SFT) +#define ACODEC_CTRL_GEN_JACK3 (0x3 << ACODEC_ALC_CTRL_GEN_SFT) +#define ACODEC_CTRL_GEN_JACK2 (0x2 << ACODEC_ALC_CTRL_GEN_SFT) +#define ACODEC_CTRL_GEN_JACK1 (0x1 << ACODEC_ALC_CTRL_GEN_SFT) +#define ACODEC_CTRL_GEN_NORMAL (0x0 << ACODEC_ALC_CTRL_GEN_SFT) +#define ACODEC_AGC_HOLD_TIME_SFT 0 +#define ACODEC_AGC_HOLD_TIME_MSK (0xf << ACODEC_AGC_HOLD_TIME_SFT) +#define ACODEC_AGC_HOLD_TIME_1S (0xa << ACODEC_AGC_HOLD_TIME_SFT) +#define ACODEC_AGC_HOLD_TIME_512MS (0x9 << ACODEC_AGC_HOLD_TIME_SFT) +#define ACODEC_AGC_HOLD_TIME_256MS (0x8 << ACODEC_AGC_HOLD_TIME_SFT) +#define ACODEC_AGC_HOLD_TIME_128MS (0x7 << ACODEC_AGC_HOLD_TIME_SFT) +#define ACODEC_AGC_HOLD_TIME_64MS (0x6 << ACODEC_AGC_HOLD_TIME_SFT) +#define ACODEC_AGC_HOLD_TIME_32MS (0x5 << ACODEC_AGC_HOLD_TIME_SFT) +#define ACODEC_AGC_HOLD_TIME_16MS (0x4 << ACODEC_AGC_HOLD_TIME_SFT) +#define ACODEC_AGC_HOLD_TIME_8MS (0x3 << ACODEC_AGC_HOLD_TIME_SFT) +#define ACODEC_AGC_HOLD_TIME_4MS (0x2 << ACODEC_AGC_HOLD_TIME_SFT) +#define ACODEC_AGC_HOLD_TIME_2MS (0x1 << ACODEC_AGC_HOLD_TIME_SFT) +#define ACODEC_AGC_HOLD_TIME_0MS (0x0 << ACODEC_AGC_HOLD_TIME_SFT) + +/* ACODEC_ADC_PGA_AGC_L_CTL1 */ +#define ACODEC_AGC_DECAY_TIME_SFT 4 +/* Normal mode (reg_agc_mode = 0) */ +#define ACODEC_AGC_DECAY_NORMAL_MSK (0xf << ACODEC_AGC_DECAY_TIME_SFT) +#define ACODEC_AGC_DECAY_NORMAL_512MS (0xa << ACODEC_AGC_DECAY_TIME_SFT) +#define ACODEC_AGC_DECAY_NORMAL_256MS (0x9 << ACODEC_AGC_DECAY_TIME_SFT) +#define ACODEC_AGC_DECAY_NORMAL_128MS (0x8 << ACODEC_AGC_DECAY_TIME_SFT) +#define ACODEC_AGC_DECAY_NORMAL_64MS (0x7 << ACODEC_AGC_DECAY_TIME_SFT) +#define ACODEC_AGC_DECAY_NORMAL_32MS (0x6 << ACODEC_AGC_DECAY_TIME_SFT) +#define ACODEC_AGC_DECAY_NORMAL_16MS (0x5 << ACODEC_AGC_DECAY_TIME_SFT) +#define ACODEC_AGC_DECAY_NORMAL_8MS (0x4 << ACODEC_AGC_DECAY_TIME_SFT) +#define ACODEC_AGC_DECAY_NORMAL_4MS (0x3 << ACODEC_AGC_DECAY_TIME_SFT) +#define ACODEC_AGC_DECAY_NORMAL_2MS (0x2 << ACODEC_AGC_DECAY_TIME_SFT) +#define ACODEC_AGC_DECAY_NORMAL_1MS (0x1 << ACODEC_AGC_DECAY_TIME_SFT) +#define ACODEC_AGC_DECAY_NORMAL_0MS (0x0 << ACODEC_AGC_DECAY_TIME_SFT) +/* Limiter mode (reg_agc_mode = 1) */ +#define ACODEC_AGC_DECAY_LIMITER_MSK (0xf << ACODEC_AGC_DECAY_TIME_SFT) +#define ACODEC_AGC_DECAY_LIMITER_128MS (0xa << ACODEC_AGC_DECAY_TIME_SFT) +#define ACODEC_AGC_DECAY_LIMITER_64MS (0x9 << ACODEC_AGC_DECAY_TIME_SFT) +#define ACODEC_AGC_DECAY_LIMITER_32MS (0x8 << ACODEC_AGC_DECAY_TIME_SFT) +#define ACODEC_AGC_DECAY_LIMITER_16MS (0x7 << ACODEC_AGC_DECAY_TIME_SFT) +#define ACODEC_AGC_DECAY_LIMITER_8MS (0x6 << ACODEC_AGC_DECAY_TIME_SFT) +#define ACODEC_AGC_DECAY_LIMITER_4MS (0x5 << ACODEC_AGC_DECAY_TIME_SFT) +#define ACODEC_AGC_DECAY_LIMITER_2MS (0x4 << ACODEC_AGC_DECAY_TIME_SFT) +#define ACODEC_AGC_DECAY_LIMITER_1MS (0x3 << ACODEC_AGC_DECAY_TIME_SFT) +#define ACODEC_AGC_DECAY_LIMITER_500US (0x2 << ACODEC_AGC_DECAY_TIME_SFT) +#define ACODEC_AGC_DECAY_LIMITER_250US (0x1 << ACODEC_AGC_DECAY_TIME_SFT) +#define ACODEC_AGC_DECAY_LIMITER_125US (0x0 << ACODEC_AGC_DECAY_TIME_SFT) +#define ACODEC_AGC_ATTACK_TIME_SFT 0 +/* Normal mode (reg_agc_mode = 0) */ +#define ACODEC_AGC_ATTACK_NORMAL_MSK (0xf << ACODEC_AGC_ATTACK_TIME_SFT) +#define ACODEC_AGC_ATTACK_NORMAL_128MS (0xa << ACODEC_AGC_ATTACK_TIME_SFT) +#define ACODEC_AGC_ATTACK_NORMAL_64MS (0x9 << ACODEC_AGC_ATTACK_TIME_SFT) +#define ACODEC_AGC_ATTACK_NORMAL_32MS (0x8 << ACODEC_AGC_ATTACK_TIME_SFT) +#define ACODEC_AGC_ATTACK_NORMAL_16MS (0x7 << ACODEC_AGC_ATTACK_TIME_SFT) +#define ACODEC_AGC_ATTACK_NORMAL_8MS (0x6 << ACODEC_AGC_ATTACK_TIME_SFT) +#define ACODEC_AGC_ATTACK_NORMAL_4MS (0x5 << ACODEC_AGC_ATTACK_TIME_SFT) +#define ACODEC_AGC_ATTACK_NORMAL_2MS (0x4 << ACODEC_AGC_ATTACK_TIME_SFT) +#define ACODEC_AGC_ATTACK_NORMAL_1MS (0x3 << ACODEC_AGC_ATTACK_TIME_SFT) +#define ACODEC_AGC_ATTACK_NORMAL_500US (0x2 << ACODEC_AGC_ATTACK_TIME_SFT) +#define ACODEC_AGC_ATTACK_NORMAL_250US (0x1 << ACODEC_AGC_ATTACK_TIME_SFT) +#define ACODEC_AGC_ATTACK_NORMAL_125US (0x0 << ACODEC_AGC_ATTACK_TIME_SFT) +/* Limiter mode (reg_agc_mode = 1) */ +#define ACODEC_AGC_ATTACK_LIMITER_MSK (0xf << ACODEC_AGC_ATTACK_TIME_SFT) +#define ACODEC_AGC_ATTACK_LIMITER_32MS (0xa << ACODEC_AGC_ATTACK_TIME_SFT) +#define ACODEC_AGC_ATTACK_LIMITER_16MS (0x9 << ACODEC_AGC_ATTACK_TIME_SFT) +#define ACODEC_AGC_ATTACK_LIMITER_8MS (0x8 << ACODEC_AGC_ATTACK_TIME_SFT) +#define ACODEC_AGC_ATTACK_LIMITER_4MS (0x7 << ACODEC_AGC_ATTACK_TIME_SFT) +#define ACODEC_AGC_ATTACK_LIMITER_2MS (0x6 << ACODEC_AGC_ATTACK_TIME_SFT) +#define ACODEC_AGC_ATTACK_LIMITER_1MS (0x5 << ACODEC_AGC_ATTACK_TIME_SFT) +#define ACODEC_AGC_ATTACK_LIMITER_500US (0x4 << ACODEC_AGC_ATTACK_TIME_SFT) +#define ACODEC_AGC_ATTACK_LIMITER_250US (0x3 << ACODEC_AGC_ATTACK_TIME_SFT) +#define ACODEC_AGC_ATTACK_LIMITER_125US (0x2 << ACODEC_AGC_ATTACK_TIME_SFT) +#define ACODEC_AGC_ATTACK_LIMITER_64US (0x1 << ACODEC_AGC_ATTACK_TIME_SFT) +#define ACODEC_AGC_ATTACK_LIMITER_32US (0x0 << ACODEC_AGC_ATTACK_TIME_SFT) + +/* ACODEC_ADC_PGA_AGC_L_CTL2 */ +#define ACODEC_AGC_MODE_LIMITER (0x1 << 7) +#define ACODEC_AGC_MODE_NORMAL (0x0 << 7) +#define ACODEC_AGC_ZERO_CRO_EN (0x1 << 6) +#define ACODEC_AGC_ZERO_CRO_DIS (0x0 << 6) +#define ACODEC_AGC_AMP_RECOVER_GAIN (0x1 << 5) +#define ACODEC_AGC_AMP_RECOVER_LVOL (0x0 << 5) +#define ACODEC_AGC_FAST_DEC_EN (0x1 << 4) +#define ACODEC_AGC_FAST_DEC_DIS (0x0 << 4) +#define ACODEC_AGC_NOISE_GATE_EN (0x1 << 3) +#define ACODEC_AGC_NOISE_GATE_DIS (0x0 << 3) +#define ACODEC_AGC_NOISE_GATE_THRESH_SFT 0 +#define ACODEC_AGC_NOISE_GATE_THRESH_MSK (0x7 << ACODEC_AGC_NOISE_GATE_THRESH_SFT) +#define ACODEC_AGC_NOISE_GATE_THRESH_N81DB (0x7 << ACODEC_AGC_NOISE_GATE_THRESH_SFT) +#define ACODEC_AGC_NOISE_GATE_THRESH_N75DB (0x6 << ACODEC_AGC_NOISE_GATE_THRESH_SFT) +#define ACODEC_AGC_NOISE_GATE_THRESH_N69DB (0x5 << ACODEC_AGC_NOISE_GATE_THRESH_SFT) +#define ACODEC_AGC_NOISE_GATE_THRESH_N63DB (0x4 << ACODEC_AGC_NOISE_GATE_THRESH_SFT) +#define ACODEC_AGC_NOISE_GATE_THRESH_N57DB (0x3 << ACODEC_AGC_NOISE_GATE_THRESH_SFT) +#define ACODEC_AGC_NOISE_GATE_THRESH_N51DB (0x2 << ACODEC_AGC_NOISE_GATE_THRESH_SFT) +#define ACODEC_AGC_NOISE_GATE_THRESH_N45DB (0x1 << ACODEC_AGC_NOISE_GATE_THRESH_SFT) +#define ACODEC_AGC_NOISE_GATE_THRESH_N39DB (0x0 << ACODEC_AGC_NOISE_GATE_THRESH_SFT) + +/* ACODEC_ADC_PGA_AGC_L_CTL3 */ +#define ACODEC_AGC_PGA_ZERO_CRO_EN (0x1 << 5) +#define ACODEC_AGC_PGA_ZERO_CRO_DIS (0x0 << 5) +#define ACODEC_AGC_PGA_GAIN_MAX 0x1f +#define ACODEC_AGC_PGA_GAIN_MIN 0 +#define ACODEC_AGC_PGA_GAIN_SFT 0 +#define ACODEC_AGC_PGA_GAIN_MSK (0x1f << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_PDB_28_5 (0x1f << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_PDB_27 (0x1e << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_PDB_25_5 (0x1d << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_PDB_24 (0x1c << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_PDB_22_5 (0x1b << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_PDB_21 (0x1a << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_PDB_19_5 (0x19 << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_PDB_18 (0x18 << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_PDB_16_5 (0x17 << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_PDB_15 (0x16 << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_PDB_13_5 (0x15 << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_PDB_12 (0x14 << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_PDB_10_5 (0x13 << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_PDB_9 (0x12 << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_PDB_7_5 (0x11 << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_PDB_6 (0x10 << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_PDB_4_5 (0x0f << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_PDB_3 (0x0e << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_PDB_1_5 (0x0d << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_0DB (0x0c << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_NDB_1_5 (0x0b << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_NDB_3 (0x0a << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_NDB_4_5 (0x09 << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_NDB_6 (0x08 << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_NDB_7_5 (0x07 << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_NDB_9 (0x06 << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_NDB_10_5 (0x05 << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_NDB_12 (0x04 << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_NDB_13_5 (0x03 << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_NDB_15 (0x02 << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_NDB_16_5 (0x01 << ACODEC_AGC_PGA_GAIN_SFT) +#define ACODEC_AGC_PGA_GAIN_NDB_18 (0x00 << ACODEC_AGC_PGA_GAIN_SFT) + +/* ACODEC_ADC_PGA_AGC_L_CTL4 */ +#define ACODEC_AGC_SLOW_CLK_EN (0x1 << 3) +#define ACODEC_AGC_SLOW_CLK_DIS (0x0 << 3) +#define ACODEC_AGC_APPROX_RATE_SFT 0 +#define ACODEC_AGC_APPROX_RATE_MSK (0x7 << ACODEC_AGC_APPROX_RATE_SFT) +#define ACODEC_AGC_APPROX_RATE_8K (0x7 << ACODEC_AGC_APPROX_RATE_SFT) +#define ACODEC_AGC_APPROX_RATE_12K (0x6 << ACODEC_AGC_APPROX_RATE_SFT) +#define ACODEC_AGC_APPROX_RATE_16K (0x5 << ACODEC_AGC_APPROX_RATE_SFT) +#define ACODEC_AGC_APPROX_RATE_24K (0x4 << ACODEC_AGC_APPROX_RATE_SFT) +#define ACODEC_AGC_APPROX_RATE_32K (0x3 << ACODEC_AGC_APPROX_RATE_SFT) +#define ACODEC_AGC_APPROX_RATE_44_1K (0x2 << ACODEC_AGC_APPROX_RATE_SFT) +#define ACODEC_AGC_APPROX_RATE_48K (0x1 << ACODEC_AGC_APPROX_RATE_SFT) +#define ACODEC_AGC_APPROX_RATE_96K (0x0 << ACODEC_AGC_APPROX_RATE_SFT) + +/* ACODEC_ADC_PGA_AGC_L_CTL5 */ +#define ACODEC_AGC_LO_8BITS_AGC_MAX_MSK 0xff + +/* ACODEC_ADC_PGA_AGC_L_CTL6 */ +#define ACODEC_AGC_HI_8BITS_AGC_MAX_MSK 0xff + +/* ACODEC_ADC_PGA_AGC_L_CTL7 */ +#define ACODEC_AGC_LO_8BITS_AGC_MIN_MSK 0xff + +/* ACODEC_ADC_PGA_AGC_L_CTL8 */ +#define ACODEC_AGC_HI_8BITS_AGC_MIN_MSK 0xff + +/* ACODEC_ADC_PGA_AGC_L_CTL9 */ +#define ACODEC_AGC_FUNC_SEL_MSK (0x1 << 6) +#define ACODEC_AGC_FUNC_SEL_EN (0x1 << 6) +#define ACODEC_AGC_FUNC_SEL_DIS (0x0 << 6) +#define ACODEC_AGC_MAX_GAIN_PGA_MAX 0x7 +#define ACODEC_AGC_MAX_GAIN_PGA_MIN 0 +#define ACODEC_AGC_MAX_GAIN_PGA_SFT 3 +#define ACODEC_AGC_MAX_GAIN_PGA_MSK (0x7 << ACODEC_AGC_MAX_GAIN_PGA_SFT) +#define ACODEC_AGC_MAX_GAIN_PGA_PDB_28_5 (0x7 << ACODEC_AGC_MAX_GAIN_PGA_SFT) +#define ACODEC_AGC_MAX_GAIN_PGA_PDB_22_5 (0x6 << ACODEC_AGC_MAX_GAIN_PGA_SFT) +#define ACODEC_AGC_MAX_GAIN_PGA_PDB_16_5 (0x5 << ACODEC_AGC_MAX_GAIN_PGA_SFT) +#define ACODEC_AGC_MAX_GAIN_PGA_PDB_10_5 (0x4 << ACODEC_AGC_MAX_GAIN_PGA_SFT) +#define ACODEC_AGC_MAX_GAIN_PGA_PDB_4_5 (0x3 << ACODEC_AGC_MAX_GAIN_PGA_SFT) +#define ACODEC_AGC_MAX_GAIN_PGA_NDB_1_5 (0x2 << ACODEC_AGC_MAX_GAIN_PGA_SFT) +#define ACODEC_AGC_MAX_GAIN_PGA_NDB_7_5 (0x1 << ACODEC_AGC_MAX_GAIN_PGA_SFT) +#define ACODEC_AGC_MAX_GAIN_PGA_NDB_13_5 (0x0 << ACODEC_AGC_MAX_GAIN_PGA_SFT) +#define ACODEC_AGC_MIN_GAIN_PGA_MAX 0x7 +#define ACODEC_AGC_MIN_GAIN_PGA_MIN 0 +#define ACODEC_AGC_MIN_GAIN_PGA_SFT 0 +#define ACODEC_AGC_MIN_GAIN_PGA_MSK (0x7 << ACODEC_AGC_MIN_GAIN_PGA_SFT) +#define ACODEC_AGC_MIN_GAIN_PGA_PDB_24 (0x7 << ACODEC_AGC_MIN_GAIN_PGA_SFT) +#define ACODEC_AGC_MIN_GAIN_PGA_PDB_18 (0x6 << ACODEC_AGC_MIN_GAIN_PGA_SFT) +#define ACODEC_AGC_MIN_GAIN_PGA_PDB_12 (0x5 << ACODEC_AGC_MIN_GAIN_PGA_SFT) +#define ACODEC_AGC_MIN_GAIN_PGA_PDB_6 (0x4 << ACODEC_AGC_MIN_GAIN_PGA_SFT) +#define ACODEC_AGC_MIN_GAIN_PGA_0DB (0x3 << ACODEC_AGC_MIN_GAIN_PGA_SFT) +#define ACODEC_AGC_MIN_GAIN_PGA_NDB_6 (0x2 << ACODEC_AGC_MIN_GAIN_PGA_SFT) +#define ACODEC_AGC_MIN_GAIN_PGA_NDB_12 (0x1 << ACODEC_AGC_MIN_GAIN_PGA_SFT) +#define ACODEC_AGC_MIN_GAIN_PGA_NDB_18 (0x0 << ACODEC_AGC_MIN_GAIN_PGA_SFT) + +#define ACODEC_HIFI 0x0 + +#endif /* __RV1106_CODEC_H__ */