From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Paolo Sabatino Date: Fri, 20 Dec 2024 11:48:31 +0100 Subject: revert rk3308 analog codec to vendor code --- arch/arm64/boot/dts/rockchip/rk3308.dtsi | 7 +- sound/soc/codecs/rk3308_codec.c | 5681 ++++++++-- sound/soc/codecs/rk3308_codec.h | 892 +- sound/soc/codecs/rk3308_codec_provider.h | 28 + 4 files changed, 5665 insertions(+), 943 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3308.dtsi b/arch/arm64/boot/dts/rockchip/rk3308.dtsi index 111111111111..222222222222 100644 --- a/arch/arm64/boot/dts/rockchip/rk3308.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3308.dtsi @@ -836,11 +836,14 @@ codec: codec@ff560000 { compatible = "rockchip,rk3308-codec"; reg = <0x0 0xff560000 0x0 0x10000>; rockchip,grf = <&grf>; - clock-names = "mclk_tx", "mclk_rx", "hclk"; + rockchip,detect-grf = <&detect_grf>; + clock-names = "mclk_tx", "mclk_rx", "acodec"; clocks = <&cru SCLK_I2S2_8CH_TX_OUT>, <&cru SCLK_I2S2_8CH_RX_OUT>, <&cru PCLK_ACODEC>; - reset-names = "codec"; + interrupts = <&gic 114 IRQ_TYPE_LEVEL_HIGH>, + <&gic 115 IRQ_TYPE_LEVEL_HIGH>; + reset-names = "acodec-reset"; resets = <&cru SRST_ACODEC_P>; #sound-dai-cells = <0>; status = "disabled"; diff --git a/sound/soc/codecs/rk3308_codec.c b/sound/soc/codecs/rk3308_codec.c index 111111111111..222222222222 100644 --- a/sound/soc/codecs/rk3308_codec.c +++ b/sound/soc/codecs/rk3308_codec.c @@ -1,9 +1,20 @@ -// SPDX-License-Identifier: GPL-2.0-only /* - * Rockchip RK3308 internal audio codec driver + * rk3308_codec.c -- RK3308 ALSA Soc Audio Driver * * Copyright (c) 2018, Fuzhou Rockchip Electronics Co., Ltd All rights reserved. - * Copyright (c) 2024, Vivax-Metrotech Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * */ #include @@ -14,961 +25,5151 @@ #include #include #include +#include #include +#include #include +#include #include -#include +// #include +#include #include +#include +#include +#include #include #include +#include #include #include #include "rk3308_codec.h" +#include "rk3308_codec_provider.h" +#if defined(CONFIG_DEBUG_FS) +#include +#include +#include +#endif + +#define CODEC_DRV_NAME "rk3308-acodec" + +#define ADC_GRP_SKIP_MAGIC 0x1001 #define ADC_LR_GROUP_MAX 4 +#define ADC_STABLE_MS 200 +#define DEBUG_POP_ALWAYS 0 +#define HPDET_POLL_MS 2000 +#define NOT_USED 255 +#define LOOPBACK_HANDLE_MS 100 +#define PA_DRV_MS 5 +#define GRF_SOC_CON1 0x304 #define GRF_CHIP_ID 0x800 +#define GRF_I2S2_8CH_SDI_SFT 0 +#define GRF_I2S3_4CH_SDI_SFT 8 +#define GRF_I2S1_2CH_SDI_SFT 12 + +#define GRF_I2S2_8CH_SDI_R_MSK(i, v) ((v >> (i * 2 + GRF_I2S2_8CH_SDI_SFT)) & 0x3) +#define GRF_I2S2_8CH_SDI_W_MSK(i) (0x3 << (i * 2 + GRF_I2S2_8CH_SDI_SFT + 16)) +#define GRF_I2S2_8CH_SDI(i, v) (((v & 0x3) << (i * 2 + GRF_I2S2_8CH_SDI_SFT)) |\ + GRF_I2S2_8CH_SDI_W_MSK(i)) + +#define GRF_I2S3_4CH_SDI_W_MSK(i) (0x3 << (i * 2 + GRF_I2S3_4CH_SDI_SFT + 16)) +#define GRF_I2S3_4CH_SDI(i, v) (((v & 0x3) << (i * 2 + GRF_I2S3_4CH_SDI_SFT)) |\ + GRF_I2S3_4CH_SDI_W_MSK(i)) + +#define GRF_I2S1_2CH_SDI_W_MSK (0x3 << (GRF_I2S1_2CH_SDI_SFT + 16)) +#define GRF_I2S1_2CH_SDI(v) (((v & 0x3) << GRF_I2S1_2CH_SDI_SFT) |\ + GRF_I2S1_2CH_SDI_W_MSK) + +#define DETECT_GRF_ACODEC_HPDET_COUNTER 0x0030 +#define DETECT_GRF_ACODEC_HPDET_CON 0x0034 +#define DETECT_GRF_ACODEC_HPDET_STATUS 0x0038 +#define DETECT_GRF_ACODEC_HPDET_STATUS_CLR 0x003c + +/* 200ms based on pclk is 100MHz */ +#define DEFAULT_HPDET_COUNT 20000000 +#define HPDET_NEG_IRQ_SFT 1 +#define HPDET_POS_IRQ_SFT 0 +#define HPDET_BOTH_NEG_POS ((1 << HPDET_NEG_IRQ_SFT) |\ + (1 << HPDET_POS_IRQ_SFT)) + +#define ACODEC_VERSION_A 0xa +#define ACODEC_VERSION_B 0xb + +enum { + ACODEC_TO_I2S2_8CH = 0, + ACODEC_TO_I2S3_4CH, + ACODEC_TO_I2S1_2CH, +}; + +enum { + ADC_GRP0_MICIN = 0, + ADC_GRP0_LINEIN +}; + +enum { + ADC_TYPE_NORMAL = 0, + ADC_TYPE_LOOPBACK, + ADC_TYPE_DBG, + ADC_TYPE_ALL, +}; + +enum { + DAC_LINEOUT = 0, + DAC_HPOUT = 1, + DAC_LINEOUT_HPOUT = 11, +}; enum { - ACODEC_VERSION_A = 'A', - ACODEC_VERSION_B, - ACODEC_VERSION_C, + EXT_MICBIAS_NONE = 0, + EXT_MICBIAS_FUNC1, /* enable external micbias via GPIO */ + EXT_MICBIAS_FUNC2, /* enable external micbias via regulator */ +}; + +enum { + PATH_IDLE = 0, + PATH_BUSY, +}; + +enum { + PM_NORMAL = 0, + PM_LLP_DOWN, /* light low power down */ + PM_LLP_UP, + PM_DLP_DOWN, /* deep low power down */ + PM_DLP_UP, + PM_DLP_DOWN2, + PM_DLP_UP2, }; struct rk3308_codec_priv { - const struct device *dev; + const struct device *plat_dev; + struct device dev; + struct reset_control *reset; struct regmap *regmap; struct regmap *grf; - struct reset_control *reset; - struct clk *hclk; + struct regmap *detect_grf; + struct clk *pclk; struct clk *mclk_rx; struct clk *mclk_tx; + struct gpio_desc *micbias_en_gpio; + struct gpio_desc *hp_ctl_gpio; + struct gpio_desc *spk_ctl_gpio; + struct gpio_desc *pa_drv_gpio; struct snd_soc_component *component; - unsigned char codec_ver; -}; + struct snd_soc_jack *hpdet_jack; + struct regulator *vcc_micbias; + u32 codec_ver; + + /* + * To select ADCs for groups: + * + * grp 0 -- select ADC1 / ADC2 + * grp 1 -- select ADC3 / ADC4 + * grp 2 -- select ADC5 / ADC6 + * grp 3 -- select ADC7 / ADC8 + */ + u32 used_adc_grps; + /* The ADC group which is used for loop back */ + u32 loopback_grp; + u32 cur_dbg_grp; + u32 en_always_grps[ADC_LR_GROUP_MAX]; + u32 en_always_grps_num; + u32 skip_grps[ADC_LR_GROUP_MAX]; + u32 i2s_sdis[ADC_LR_GROUP_MAX]; + u32 to_i2s_grps; + u32 delay_loopback_handle_ms; + u32 delay_start_play_ms; + u32 delay_pa_drv_ms; + u32 micbias_num; + u32 micbias_volt; + int which_i2s; + int irq; + int adc_grp0_using_linein; + int adc_zerocross; + /* 0: line out, 1: hp out, 11: lineout and hpout */ + int dac_output; + int dac_path_state; + + int ext_micbias; + int pm_state; + + /* AGC L/R Off/on */ + unsigned int agc_l[ADC_LR_GROUP_MAX]; + unsigned int agc_r[ADC_LR_GROUP_MAX]; -static struct clk_bulk_data rk3308_codec_clocks[] = { - { .id = "hclk" }, - { .id = "mclk_rx" }, - { .id = "mclk_tx" }, + /* AGC L/R Approximate Sample Rate */ + unsigned int agc_asr_l[ADC_LR_GROUP_MAX]; + unsigned int agc_asr_r[ADC_LR_GROUP_MAX]; + + /* ADC MIC Mute/Work */ + unsigned int mic_mute_l[ADC_LR_GROUP_MAX]; + unsigned int mic_mute_r[ADC_LR_GROUP_MAX]; + + /* For the high pass filter */ + unsigned int hpf_cutoff[ADC_LR_GROUP_MAX]; + + /* Only hpout do fade-in and fade-out */ + unsigned int hpout_l_dgain; + unsigned int hpout_r_dgain; + + bool adc_grps_endisable[ADC_LR_GROUP_MAX]; + bool dac_endisable; + bool enable_all_adcs; + bool enable_micbias; + bool micbias1; + bool micbias2; + bool hp_jack_reversed; + bool hp_plugged; + bool loopback_dacs_enabled; + bool no_deep_low_power; + bool no_hp_det; + struct delayed_work hpdet_work; + struct delayed_work loopback_work; + +#if defined(CONFIG_DEBUG_FS) + struct dentry *dbg_codec; +#endif }; -static const DECLARE_TLV_DB_SCALE(rk3308_codec_adc_alc_gain_tlv, -1800, 150, 0); -static const DECLARE_TLV_DB_SCALE(rk3308_codec_dac_hpout_gain_tlv, -3900, 150, 0); -static const DECLARE_TLV_DB_SCALE(rk3308_codec_dac_hpmix_gain_tlv, -600, 600, 0); +static const DECLARE_TLV_DB_SCALE(rk3308_codec_alc_agc_grp_gain_tlv, + -1800, 150, 2850); +static const DECLARE_TLV_DB_SCALE(rk3308_codec_alc_agc_grp_max_gain_tlv, + -1350, 600, 2850); +static const DECLARE_TLV_DB_SCALE(rk3308_codec_alc_agc_grp_min_gain_tlv, + -1800, 600, 2400); +static const DECLARE_TLV_DB_SCALE(rk3308_codec_adc_alc_gain_tlv, + -1800, 150, 2850); +static const DECLARE_TLV_DB_SCALE(rk3308_codec_dac_lineout_gain_tlv, + -600, 150, 0); +static const DECLARE_TLV_DB_SCALE(rk3308_codec_dac_hpout_gain_tlv, + -3900, 150, 600); +static const DECLARE_TLV_DB_SCALE(rk3308_codec_dac_hpmix_gain_tlv, + -600, 600, 0); + +static const DECLARE_TLV_DB_RANGE(rk3308_codec_adc_mic_gain_tlv_a, + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 3, 3, TLV_DB_SCALE_ITEM(2000, 0, 0), +); -static const DECLARE_TLV_DB_RANGE(rk3308_codec_dac_lineout_gain_tlv, - 0, 0, TLV_DB_SCALE_ITEM(-600, 0, 0), - 1, 1, TLV_DB_SCALE_ITEM(-300, 0, 0), - 2, 2, TLV_DB_SCALE_ITEM(-150, 0, 0), - 3, 3, TLV_DB_SCALE_ITEM(0, 0, 0), +static const DECLARE_TLV_DB_RANGE(rk3308_codec_adc_mic_gain_tlv_b, + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 1, 1, TLV_DB_SCALE_ITEM(660, 0, 0), + 2, 2, TLV_DB_SCALE_ITEM(1300, 0, 0), + 3, 3, TLV_DB_SCALE_ITEM(2000, 0, 0), ); -static const char * const rk3308_codec_hpf_cutoff_text[] = { - "20 Hz", "245 Hz", "612 Hz" +static bool handle_loopback(struct rk3308_codec_priv *rk3308); + +static int check_micbias(int micbias); + +static int rk3308_codec_micbias_enable(struct rk3308_codec_priv *rk3308, + int micbias); +static int rk3308_codec_micbias_disable(struct rk3308_codec_priv *rk3308); + +static int rk3308_codec_hpout_l_get_tlv(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rk3308_codec_hpout_l_put_tlv(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rk3308_codec_hpout_r_get_tlv(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rk3308_codec_hpout_r_put_tlv(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rk3308_codec_hpf_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rk3308_codec_hpf_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rk3308_codec_agc_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rk3308_codec_agc_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rk3308_codec_agc_asr_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rk3308_codec_agc_asr_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rk3308_codec_mic_mute_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rk3308_codec_mic_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rk3308_codec_mic_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rk3308_codec_mic_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rk3308_codec_micbias_volts_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rk3308_codec_micbias_volts_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rk3308_codec_main_micbias_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rk3308_codec_main_micbias_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +static const char *offon_text[2] = { + [0] = "Off", + [1] = "On", +}; + +static const char *mute_text[2] = { + [0] = "Work", + [1] = "Mute", +}; + +/* ADC MICBIAS Volt */ +#define MICBIAS_VOLT_NUM 8 + +#define MICBIAS_VREFx0_5 0 +#define MICBIAS_VREFx0_55 1 +#define MICBIAS_VREFx0_6 2 +#define MICBIAS_VREFx0_65 3 +#define MICBIAS_VREFx0_7 4 +#define MICBIAS_VREFx0_75 5 +#define MICBIAS_VREFx0_8 6 +#define MICBIAS_VREFx0_85 7 + +static const char *micbias_volts_enum_array[MICBIAS_VOLT_NUM] = { + [MICBIAS_VREFx0_5] = "VREFx0_5", + [MICBIAS_VREFx0_55] = "VREFx0_55", + [MICBIAS_VREFx0_6] = "VREFx0_6", + [MICBIAS_VREFx0_65] = "VREFx0_65", + [MICBIAS_VREFx0_7] = "VREFx0_7", + [MICBIAS_VREFx0_75] = "VREFx0_75", + [MICBIAS_VREFx0_8] = "VREFx0_8", + [MICBIAS_VREFx0_85] = "VREFx0_85", +}; + +static const struct soc_enum rk3308_micbias_volts_enum_array[] = { + SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(micbias_volts_enum_array), micbias_volts_enum_array), +}; + +/* ADC MICBIAS1 and MICBIAS2 Main Switch */ +static const struct soc_enum rk3308_main_micbias_enum_array[] = { + SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(offon_text), offon_text), +}; + +static const struct soc_enum rk3308_hpf_enum_array[] = { + SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(offon_text), offon_text), + SOC_ENUM_SINGLE(1, 0, ARRAY_SIZE(offon_text), offon_text), + SOC_ENUM_SINGLE(2, 0, ARRAY_SIZE(offon_text), offon_text), + SOC_ENUM_SINGLE(3, 0, ARRAY_SIZE(offon_text), offon_text), +}; + +/* ALC AGC Switch */ +static const struct soc_enum rk3308_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), + SOC_ENUM_SINGLE(1, 0, ARRAY_SIZE(offon_text), offon_text), + SOC_ENUM_SINGLE(1, 1, ARRAY_SIZE(offon_text), offon_text), + SOC_ENUM_SINGLE(2, 0, ARRAY_SIZE(offon_text), offon_text), + SOC_ENUM_SINGLE(2, 1, ARRAY_SIZE(offon_text), offon_text), + SOC_ENUM_SINGLE(3, 0, ARRAY_SIZE(offon_text), offon_text), + SOC_ENUM_SINGLE(3, 1, ARRAY_SIZE(offon_text), offon_text), +}; + +/* ADC MIC Mute/Work Switch */ +static const struct soc_enum rk3308_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), + SOC_ENUM_SINGLE(1, 0, ARRAY_SIZE(mute_text), mute_text), + SOC_ENUM_SINGLE(1, 1, ARRAY_SIZE(mute_text), mute_text), + SOC_ENUM_SINGLE(2, 0, ARRAY_SIZE(mute_text), mute_text), + SOC_ENUM_SINGLE(2, 1, ARRAY_SIZE(mute_text), mute_text), + SOC_ENUM_SINGLE(3, 0, ARRAY_SIZE(mute_text), mute_text), + SOC_ENUM_SINGLE(3, 1, ARRAY_SIZE(mute_text), mute_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 rk3308_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), + SOC_ENUM_SINGLE(1, 0, ARRAY_SIZE(agc_asr_text), agc_asr_text), + SOC_ENUM_SINGLE(1, 1, ARRAY_SIZE(agc_asr_text), agc_asr_text), + SOC_ENUM_SINGLE(2, 0, ARRAY_SIZE(agc_asr_text), agc_asr_text), + SOC_ENUM_SINGLE(2, 1, ARRAY_SIZE(agc_asr_text), agc_asr_text), + SOC_ENUM_SINGLE(3, 0, ARRAY_SIZE(agc_asr_text), agc_asr_text), + SOC_ENUM_SINGLE(3, 1, ARRAY_SIZE(agc_asr_text), agc_asr_text), +}; + +static const struct snd_kcontrol_new mic_gains_a[] = { + /* ADC MIC */ + SOC_SINGLE_EXT_TLV("ADC MIC Group 0 Left Volume", + RK3308_ADC_ANA_CON01(0), + RK3308_ADC_CH1_MIC_GAIN_SFT, + RK3308_ADC_CH1_MIC_GAIN_MAX, + 0, + rk3308_codec_mic_gain_get, + rk3308_codec_mic_gain_put, + rk3308_codec_adc_mic_gain_tlv_a), + SOC_SINGLE_EXT_TLV("ADC MIC Group 0 Right Volume", + RK3308_ADC_ANA_CON01(0), + RK3308_ADC_CH2_MIC_GAIN_SFT, + RK3308_ADC_CH2_MIC_GAIN_MAX, + 0, + rk3308_codec_mic_gain_get, + rk3308_codec_mic_gain_put, + rk3308_codec_adc_mic_gain_tlv_a), + SOC_SINGLE_EXT_TLV("ADC MIC Group 1 Left Volume", + RK3308_ADC_ANA_CON01(1), + RK3308_ADC_CH1_MIC_GAIN_SFT, + RK3308_ADC_CH1_MIC_GAIN_MAX, + 0, + rk3308_codec_mic_gain_get, + rk3308_codec_mic_gain_put, + rk3308_codec_adc_mic_gain_tlv_a), + SOC_SINGLE_EXT_TLV("ADC MIC Group 1 Right Volume", + RK3308_ADC_ANA_CON01(1), + RK3308_ADC_CH2_MIC_GAIN_SFT, + RK3308_ADC_CH2_MIC_GAIN_MAX, + 0, + rk3308_codec_mic_gain_get, + rk3308_codec_mic_gain_put, + rk3308_codec_adc_mic_gain_tlv_a), + SOC_SINGLE_EXT_TLV("ADC MIC Group 2 Left Volume", + RK3308_ADC_ANA_CON01(2), + RK3308_ADC_CH1_MIC_GAIN_SFT, + RK3308_ADC_CH1_MIC_GAIN_MAX, + 0, + rk3308_codec_mic_gain_get, + rk3308_codec_mic_gain_put, + rk3308_codec_adc_mic_gain_tlv_a), + SOC_SINGLE_EXT_TLV("ADC MIC Group 2 Right Volume", + RK3308_ADC_ANA_CON01(2), + RK3308_ADC_CH2_MIC_GAIN_SFT, + RK3308_ADC_CH2_MIC_GAIN_MAX, + 0, + rk3308_codec_mic_gain_get, + rk3308_codec_mic_gain_put, + rk3308_codec_adc_mic_gain_tlv_a), + SOC_SINGLE_EXT_TLV("ADC MIC Group 3 Left Volume", + RK3308_ADC_ANA_CON01(3), + RK3308_ADC_CH1_MIC_GAIN_SFT, + RK3308_ADC_CH1_MIC_GAIN_MAX, + 0, + rk3308_codec_mic_gain_get, + rk3308_codec_mic_gain_put, + rk3308_codec_adc_mic_gain_tlv_a), + SOC_SINGLE_EXT_TLV("ADC MIC Group 3 Right Volume", + RK3308_ADC_ANA_CON01(3), + RK3308_ADC_CH2_MIC_GAIN_SFT, + RK3308_ADC_CH2_MIC_GAIN_MAX, + 0, + rk3308_codec_mic_gain_get, + rk3308_codec_mic_gain_put, + rk3308_codec_adc_mic_gain_tlv_a), +}; + +static const struct snd_kcontrol_new mic_gains_b[] = { + /* ADC MIC */ + SOC_SINGLE_EXT_TLV("ADC MIC Group 0 Left Volume", + RK3308_ADC_ANA_CON01(0), + RK3308_ADC_CH1_MIC_GAIN_SFT, + RK3308_ADC_CH1_MIC_GAIN_MAX, + 0, + rk3308_codec_mic_gain_get, + rk3308_codec_mic_gain_put, + rk3308_codec_adc_mic_gain_tlv_b), + SOC_SINGLE_EXT_TLV("ADC MIC Group 0 Right Volume", + RK3308_ADC_ANA_CON01(0), + RK3308_ADC_CH2_MIC_GAIN_SFT, + RK3308_ADC_CH2_MIC_GAIN_MAX, + 0, + rk3308_codec_mic_gain_get, + rk3308_codec_mic_gain_put, + rk3308_codec_adc_mic_gain_tlv_b), + SOC_SINGLE_EXT_TLV("ADC MIC Group 1 Left Volume", + RK3308_ADC_ANA_CON01(1), + RK3308_ADC_CH1_MIC_GAIN_SFT, + RK3308_ADC_CH1_MIC_GAIN_MAX, + 0, + rk3308_codec_mic_gain_get, + rk3308_codec_mic_gain_put, + rk3308_codec_adc_mic_gain_tlv_b), + SOC_SINGLE_EXT_TLV("ADC MIC Group 1 Right Volume", + RK3308_ADC_ANA_CON01(1), + RK3308_ADC_CH2_MIC_GAIN_SFT, + RK3308_ADC_CH2_MIC_GAIN_MAX, + 0, + rk3308_codec_mic_gain_get, + rk3308_codec_mic_gain_put, + rk3308_codec_adc_mic_gain_tlv_b), + SOC_SINGLE_EXT_TLV("ADC MIC Group 2 Left Volume", + RK3308_ADC_ANA_CON01(2), + RK3308_ADC_CH1_MIC_GAIN_SFT, + RK3308_ADC_CH1_MIC_GAIN_MAX, + 0, + rk3308_codec_mic_gain_get, + rk3308_codec_mic_gain_put, + rk3308_codec_adc_mic_gain_tlv_b), + SOC_SINGLE_EXT_TLV("ADC MIC Group 2 Right Volume", + RK3308_ADC_ANA_CON01(2), + RK3308_ADC_CH2_MIC_GAIN_SFT, + RK3308_ADC_CH2_MIC_GAIN_MAX, + 0, + rk3308_codec_mic_gain_get, + rk3308_codec_mic_gain_put, + rk3308_codec_adc_mic_gain_tlv_b), + SOC_SINGLE_EXT_TLV("ADC MIC Group 3 Left Volume", + RK3308_ADC_ANA_CON01(3), + RK3308_ADC_CH1_MIC_GAIN_SFT, + RK3308_ADC_CH1_MIC_GAIN_MAX, + 0, + rk3308_codec_mic_gain_get, + rk3308_codec_mic_gain_put, + rk3308_codec_adc_mic_gain_tlv_b), + SOC_SINGLE_EXT_TLV("ADC MIC Group 3 Right Volume", + RK3308_ADC_ANA_CON01(3), + RK3308_ADC_CH2_MIC_GAIN_SFT, + RK3308_ADC_CH2_MIC_GAIN_MAX, + 0, + rk3308_codec_mic_gain_get, + rk3308_codec_mic_gain_put, + rk3308_codec_adc_mic_gain_tlv_b), }; -static SOC_ENUM_SINGLE_DECL(rk3308_codec_hpf_cutoff_enum12, RK3308_ADC_DIG_CON04(0), 0, - rk3308_codec_hpf_cutoff_text); -static SOC_ENUM_SINGLE_DECL(rk3308_codec_hpf_cutoff_enum34, RK3308_ADC_DIG_CON04(1), 0, - rk3308_codec_hpf_cutoff_text); -static SOC_ENUM_SINGLE_DECL(rk3308_codec_hpf_cutoff_enum56, RK3308_ADC_DIG_CON04(2), 0, - rk3308_codec_hpf_cutoff_text); -static SOC_ENUM_SINGLE_DECL(rk3308_codec_hpf_cutoff_enum78, RK3308_ADC_DIG_CON04(3), 0, - rk3308_codec_hpf_cutoff_text); - -static const struct snd_kcontrol_new rk3308_codec_controls[] = { - /* Despite the register names, these set the gain when AGC is OFF */ - SOC_SINGLE_RANGE_TLV("MIC1 Capture Volume", +static const struct snd_kcontrol_new rk3308_codec_dapm_controls[] = { + /* ALC AGC Group */ + SOC_SINGLE_RANGE_TLV("ALC AGC Group 0 Left Volume", + RK3308_ALC_L_DIG_CON03(0), + RK3308_AGC_PGA_GAIN_SFT, + RK3308_AGC_PGA_GAIN_MIN, + RK3308_AGC_PGA_GAIN_MAX, + 0, rk3308_codec_alc_agc_grp_gain_tlv), + SOC_SINGLE_RANGE_TLV("ALC AGC Group 0 Right Volume", + RK3308_ALC_R_DIG_CON03(0), + RK3308_AGC_PGA_GAIN_SFT, + RK3308_AGC_PGA_GAIN_MIN, + RK3308_AGC_PGA_GAIN_MAX, + 0, rk3308_codec_alc_agc_grp_gain_tlv), + + SOC_SINGLE_RANGE_TLV("ALC AGC Group 1 Left Volume", + RK3308_ALC_L_DIG_CON03(1), + RK3308_AGC_PGA_GAIN_SFT, + RK3308_AGC_PGA_GAIN_MIN, + RK3308_AGC_PGA_GAIN_MAX, + 0, rk3308_codec_alc_agc_grp_gain_tlv), + SOC_SINGLE_RANGE_TLV("ALC AGC Group 1 Right Volume", + RK3308_ALC_R_DIG_CON03(1), + RK3308_AGC_PGA_GAIN_SFT, + RK3308_AGC_PGA_GAIN_MIN, + RK3308_AGC_PGA_GAIN_MAX, + 0, rk3308_codec_alc_agc_grp_gain_tlv), + + SOC_SINGLE_RANGE_TLV("ALC AGC Group 2 Left Volume", + RK3308_ALC_L_DIG_CON03(2), + RK3308_AGC_PGA_GAIN_SFT, + RK3308_AGC_PGA_GAIN_MIN, + RK3308_AGC_PGA_GAIN_MAX, + 0, rk3308_codec_alc_agc_grp_gain_tlv), + SOC_SINGLE_RANGE_TLV("ALC AGC Group 2 Right Volume", + RK3308_ALC_R_DIG_CON03(2), + RK3308_AGC_PGA_GAIN_SFT, + RK3308_AGC_PGA_GAIN_MIN, + RK3308_AGC_PGA_GAIN_MAX, + 0, rk3308_codec_alc_agc_grp_gain_tlv), + + SOC_SINGLE_RANGE_TLV("ALC AGC Group 3 Left Volume", + RK3308_ALC_L_DIG_CON03(3), + RK3308_AGC_PGA_GAIN_SFT, + RK3308_AGC_PGA_GAIN_MIN, + RK3308_AGC_PGA_GAIN_MAX, + 0, rk3308_codec_alc_agc_grp_gain_tlv), + SOC_SINGLE_RANGE_TLV("ALC AGC Group 3 Right Volume", + RK3308_ALC_R_DIG_CON03(3), + RK3308_AGC_PGA_GAIN_SFT, + RK3308_AGC_PGA_GAIN_MIN, + RK3308_AGC_PGA_GAIN_MAX, + 0, rk3308_codec_alc_agc_grp_gain_tlv), + + /* ALC AGC MAX */ + SOC_SINGLE_RANGE_TLV("ALC AGC Group 0 Left Max Volume", + RK3308_ALC_L_DIG_CON09(0), + RK3308_AGC_MAX_GAIN_PGA_SFT, + RK3308_AGC_MAX_GAIN_PGA_MIN, + RK3308_AGC_MAX_GAIN_PGA_MAX, + 0, rk3308_codec_alc_agc_grp_max_gain_tlv), + SOC_SINGLE_RANGE_TLV("ALC AGC Group 0 Right Max Volume", + RK3308_ALC_R_DIG_CON09(0), + RK3308_AGC_MAX_GAIN_PGA_SFT, + RK3308_AGC_MAX_GAIN_PGA_MIN, + RK3308_AGC_MAX_GAIN_PGA_MAX, + 0, rk3308_codec_alc_agc_grp_max_gain_tlv), + + SOC_SINGLE_RANGE_TLV("ALC AGC Group 1 Left Max Volume", + RK3308_ALC_L_DIG_CON09(1), + RK3308_AGC_MAX_GAIN_PGA_SFT, + RK3308_AGC_MAX_GAIN_PGA_MIN, + RK3308_AGC_MAX_GAIN_PGA_MAX, + 0, rk3308_codec_alc_agc_grp_max_gain_tlv), + SOC_SINGLE_RANGE_TLV("ALC AGC Group 1 Right Max Volume", + RK3308_ALC_R_DIG_CON09(1), + RK3308_AGC_MAX_GAIN_PGA_SFT, + RK3308_AGC_MAX_GAIN_PGA_MIN, + RK3308_AGC_MAX_GAIN_PGA_MAX, + 0, rk3308_codec_alc_agc_grp_max_gain_tlv), + + SOC_SINGLE_RANGE_TLV("ALC AGC Group 2 Left Max Volume", + RK3308_ALC_L_DIG_CON09(2), + RK3308_AGC_MAX_GAIN_PGA_SFT, + RK3308_AGC_MAX_GAIN_PGA_MIN, + RK3308_AGC_MAX_GAIN_PGA_MAX, + 0, rk3308_codec_alc_agc_grp_max_gain_tlv), + SOC_SINGLE_RANGE_TLV("ALC AGC Group 2 Right Max Volume", + RK3308_ALC_R_DIG_CON09(2), + RK3308_AGC_MAX_GAIN_PGA_SFT, + RK3308_AGC_MAX_GAIN_PGA_MIN, + RK3308_AGC_MAX_GAIN_PGA_MAX, + 0, rk3308_codec_alc_agc_grp_max_gain_tlv), + + SOC_SINGLE_RANGE_TLV("ALC AGC Group 3 Left Max Volume", + RK3308_ALC_L_DIG_CON09(3), + RK3308_AGC_MAX_GAIN_PGA_SFT, + RK3308_AGC_MAX_GAIN_PGA_MIN, + RK3308_AGC_MAX_GAIN_PGA_MAX, + 0, rk3308_codec_alc_agc_grp_max_gain_tlv), + SOC_SINGLE_RANGE_TLV("ALC AGC Group 3 Right Max Volume", + RK3308_ALC_R_DIG_CON09(3), + RK3308_AGC_MAX_GAIN_PGA_SFT, + RK3308_AGC_MAX_GAIN_PGA_MIN, + RK3308_AGC_MAX_GAIN_PGA_MAX, + 0, rk3308_codec_alc_agc_grp_max_gain_tlv), + + /* ALC AGC MIN */ + SOC_SINGLE_RANGE_TLV("ALC AGC Group 0 Left Min Volume", + RK3308_ALC_L_DIG_CON09(0), + RK3308_AGC_MIN_GAIN_PGA_SFT, + RK3308_AGC_MIN_GAIN_PGA_MIN, + RK3308_AGC_MIN_GAIN_PGA_MAX, + 0, rk3308_codec_alc_agc_grp_min_gain_tlv), + SOC_SINGLE_RANGE_TLV("ALC AGC Group 0 Right Min Volume", + RK3308_ALC_R_DIG_CON09(0), + RK3308_AGC_MIN_GAIN_PGA_SFT, + RK3308_AGC_MIN_GAIN_PGA_MIN, + RK3308_AGC_MIN_GAIN_PGA_MAX, + 0, rk3308_codec_alc_agc_grp_min_gain_tlv), + + SOC_SINGLE_RANGE_TLV("ALC AGC Group 1 Left Min Volume", + RK3308_ALC_L_DIG_CON09(1), + RK3308_AGC_MIN_GAIN_PGA_SFT, + RK3308_AGC_MIN_GAIN_PGA_MIN, + RK3308_AGC_MIN_GAIN_PGA_MAX, + 0, rk3308_codec_alc_agc_grp_min_gain_tlv), + SOC_SINGLE_RANGE_TLV("ALC AGC Group 1 Right Min Volume", + RK3308_ALC_R_DIG_CON09(1), + RK3308_AGC_MIN_GAIN_PGA_SFT, + RK3308_AGC_MIN_GAIN_PGA_MIN, + RK3308_AGC_MIN_GAIN_PGA_MAX, + 0, rk3308_codec_alc_agc_grp_min_gain_tlv), + + SOC_SINGLE_RANGE_TLV("ALC AGC Group 2 Left Min Volume", + RK3308_ALC_L_DIG_CON09(2), + RK3308_AGC_MIN_GAIN_PGA_SFT, + RK3308_AGC_MIN_GAIN_PGA_MIN, + RK3308_AGC_MIN_GAIN_PGA_MAX, + 0, rk3308_codec_alc_agc_grp_min_gain_tlv), + SOC_SINGLE_RANGE_TLV("ALC AGC Group 2 Right Min Volume", + RK3308_ALC_R_DIG_CON09(2), + RK3308_AGC_MIN_GAIN_PGA_SFT, + RK3308_AGC_MIN_GAIN_PGA_MIN, + RK3308_AGC_MIN_GAIN_PGA_MAX, + 0, rk3308_codec_alc_agc_grp_min_gain_tlv), + + SOC_SINGLE_RANGE_TLV("ALC AGC Group 3 Left Min Volume", + RK3308_ALC_L_DIG_CON09(3), + RK3308_AGC_MIN_GAIN_PGA_SFT, + RK3308_AGC_MIN_GAIN_PGA_MIN, + RK3308_AGC_MIN_GAIN_PGA_MAX, + 0, rk3308_codec_alc_agc_grp_min_gain_tlv), + SOC_SINGLE_RANGE_TLV("ALC AGC Group 3 Right Min Volume", + RK3308_ALC_R_DIG_CON09(3), + RK3308_AGC_MIN_GAIN_PGA_SFT, + RK3308_AGC_MIN_GAIN_PGA_MIN, + RK3308_AGC_MIN_GAIN_PGA_MAX, + 0, rk3308_codec_alc_agc_grp_min_gain_tlv), + + /* ALC AGC Switch */ + SOC_ENUM_EXT("ALC AGC Group 0 Left Switch", rk3308_agc_enum_array[0], + rk3308_codec_agc_get, rk3308_codec_agc_put), + SOC_ENUM_EXT("ALC AGC Group 0 Right Switch", rk3308_agc_enum_array[1], + rk3308_codec_agc_get, rk3308_codec_agc_put), + SOC_ENUM_EXT("ALC AGC Group 1 Left Switch", rk3308_agc_enum_array[2], + rk3308_codec_agc_get, rk3308_codec_agc_put), + SOC_ENUM_EXT("ALC AGC Group 1 Right Switch", rk3308_agc_enum_array[3], + rk3308_codec_agc_get, rk3308_codec_agc_put), + SOC_ENUM_EXT("ALC AGC Group 2 Left Switch", rk3308_agc_enum_array[4], + rk3308_codec_agc_get, rk3308_codec_agc_put), + SOC_ENUM_EXT("ALC AGC Group 2 Right Switch", rk3308_agc_enum_array[5], + rk3308_codec_agc_get, rk3308_codec_agc_put), + SOC_ENUM_EXT("ALC AGC Group 3 Left Switch", rk3308_agc_enum_array[6], + rk3308_codec_agc_get, rk3308_codec_agc_put), + SOC_ENUM_EXT("ALC AGC Group 3 Right Switch", rk3308_agc_enum_array[7], + rk3308_codec_agc_get, rk3308_codec_agc_put), + + /* ALC AGC Approximate Sample Rate */ + SOC_ENUM_EXT("AGC Group 0 Left Approximate Sample Rate", rk3308_agc_asr_enum_array[0], + rk3308_codec_agc_asr_get, rk3308_codec_agc_asr_put), + SOC_ENUM_EXT("AGC Group 0 Right Approximate Sample Rate", rk3308_agc_asr_enum_array[1], + rk3308_codec_agc_asr_get, rk3308_codec_agc_asr_put), + SOC_ENUM_EXT("AGC Group 1 Left Approximate Sample Rate", rk3308_agc_asr_enum_array[2], + rk3308_codec_agc_asr_get, rk3308_codec_agc_asr_put), + SOC_ENUM_EXT("AGC Group 1 Right Approximate Sample Rate", rk3308_agc_asr_enum_array[3], + rk3308_codec_agc_asr_get, rk3308_codec_agc_asr_put), + SOC_ENUM_EXT("AGC Group 2 Left Approximate Sample Rate", rk3308_agc_asr_enum_array[4], + rk3308_codec_agc_asr_get, rk3308_codec_agc_asr_put), + SOC_ENUM_EXT("AGC Group 2 Right Approximate Sample Rate", rk3308_agc_asr_enum_array[5], + rk3308_codec_agc_asr_get, rk3308_codec_agc_asr_put), + SOC_ENUM_EXT("AGC Group 3 Left Approximate Sample Rate", rk3308_agc_asr_enum_array[6], + rk3308_codec_agc_asr_get, rk3308_codec_agc_asr_put), + SOC_ENUM_EXT("AGC Group 3 Right Approximate Sample Rate", rk3308_agc_asr_enum_array[7], + rk3308_codec_agc_asr_get, rk3308_codec_agc_asr_put), + + /* ADC MICBIAS Voltage */ + SOC_ENUM_EXT("ADC MICBIAS Voltage", rk3308_micbias_volts_enum_array[0], + rk3308_codec_micbias_volts_get, rk3308_codec_micbias_volts_put), + + /* ADC Main MICBIAS Switch */ + SOC_ENUM_EXT("ADC Main MICBIAS", rk3308_main_micbias_enum_array[0], + rk3308_codec_main_micbias_get, rk3308_codec_main_micbias_put), + + /* ADC MICBIAS1 and MICBIAS2 Switch */ + SOC_SINGLE("ADC MICBIAS1", RK3308_ADC_ANA_CON07(1), + RK3308_ADC_MIC_BIAS_BUF_SFT, 1, 0), + SOC_SINGLE("ADC MICBIAS2", RK3308_ADC_ANA_CON07(2), + RK3308_ADC_MIC_BIAS_BUF_SFT, 1, 0), + + /* ADC MIC Mute/Work Switch */ + SOC_ENUM_EXT("ADC MIC Group 0 Left Switch", rk3308_mic_mute_enum_array[0], + rk3308_codec_mic_mute_get, rk3308_codec_mic_mute_put), + SOC_ENUM_EXT("ADC MIC Group 0 Right Switch", rk3308_mic_mute_enum_array[1], + rk3308_codec_mic_mute_get, rk3308_codec_mic_mute_put), + SOC_ENUM_EXT("ADC MIC Group 1 Left Switch", rk3308_mic_mute_enum_array[2], + rk3308_codec_mic_mute_get, rk3308_codec_mic_mute_put), + SOC_ENUM_EXT("ADC MIC Group 1 Right Switch", rk3308_mic_mute_enum_array[3], + rk3308_codec_mic_mute_get, rk3308_codec_mic_mute_put), + SOC_ENUM_EXT("ADC MIC Group 2 Left Switch", rk3308_mic_mute_enum_array[4], + rk3308_codec_mic_mute_get, rk3308_codec_mic_mute_put), + SOC_ENUM_EXT("ADC MIC Group 2 Right Switch", rk3308_mic_mute_enum_array[5], + rk3308_codec_mic_mute_get, rk3308_codec_mic_mute_put), + SOC_ENUM_EXT("ADC MIC Group 3 Left Switch", rk3308_mic_mute_enum_array[6], + rk3308_codec_mic_mute_get, rk3308_codec_mic_mute_put), + SOC_ENUM_EXT("ADC MIC Group 3 Right Switch", rk3308_mic_mute_enum_array[7], + rk3308_codec_mic_mute_get, rk3308_codec_mic_mute_put), + + /* ADC ALC */ + SOC_SINGLE_RANGE_TLV("ADC ALC Group 0 Left Volume", RK3308_ADC_ANA_CON03(0), RK3308_ADC_CH1_ALC_GAIN_SFT, RK3308_ADC_CH1_ALC_GAIN_MIN, RK3308_ADC_CH1_ALC_GAIN_MAX, 0, rk3308_codec_adc_alc_gain_tlv), - SOC_SINGLE_RANGE_TLV("MIC2 Capture Volume", + SOC_SINGLE_RANGE_TLV("ADC ALC Group 0 Right Volume", RK3308_ADC_ANA_CON04(0), RK3308_ADC_CH2_ALC_GAIN_SFT, RK3308_ADC_CH2_ALC_GAIN_MIN, RK3308_ADC_CH2_ALC_GAIN_MAX, 0, rk3308_codec_adc_alc_gain_tlv), - SOC_SINGLE_RANGE_TLV("MIC3 Capture Volume", + SOC_SINGLE_RANGE_TLV("ADC ALC Group 1 Left Volume", RK3308_ADC_ANA_CON03(1), RK3308_ADC_CH1_ALC_GAIN_SFT, RK3308_ADC_CH1_ALC_GAIN_MIN, RK3308_ADC_CH1_ALC_GAIN_MAX, 0, rk3308_codec_adc_alc_gain_tlv), - SOC_SINGLE_RANGE_TLV("MIC4 Capture Volume", + SOC_SINGLE_RANGE_TLV("ADC ALC Group 1 Right Volume", RK3308_ADC_ANA_CON04(1), RK3308_ADC_CH2_ALC_GAIN_SFT, RK3308_ADC_CH2_ALC_GAIN_MIN, RK3308_ADC_CH2_ALC_GAIN_MAX, 0, rk3308_codec_adc_alc_gain_tlv), - SOC_SINGLE_RANGE_TLV("MIC5 Capture Volume", + SOC_SINGLE_RANGE_TLV("ADC ALC Group 2 Left Volume", RK3308_ADC_ANA_CON03(2), RK3308_ADC_CH1_ALC_GAIN_SFT, RK3308_ADC_CH1_ALC_GAIN_MIN, RK3308_ADC_CH1_ALC_GAIN_MAX, 0, rk3308_codec_adc_alc_gain_tlv), - SOC_SINGLE_RANGE_TLV("MIC6 Capture Volume", + SOC_SINGLE_RANGE_TLV("ADC ALC Group 2 Right Volume", RK3308_ADC_ANA_CON04(2), RK3308_ADC_CH2_ALC_GAIN_SFT, RK3308_ADC_CH2_ALC_GAIN_MIN, RK3308_ADC_CH2_ALC_GAIN_MAX, 0, rk3308_codec_adc_alc_gain_tlv), - SOC_SINGLE_RANGE_TLV("MIC7 Capture Volume", + SOC_SINGLE_RANGE_TLV("ADC ALC Group 3 Left Volume", RK3308_ADC_ANA_CON03(3), RK3308_ADC_CH1_ALC_GAIN_SFT, RK3308_ADC_CH1_ALC_GAIN_MIN, RK3308_ADC_CH1_ALC_GAIN_MAX, 0, rk3308_codec_adc_alc_gain_tlv), - SOC_SINGLE_RANGE_TLV("MIC8 Capture Volume", + SOC_SINGLE_RANGE_TLV("ADC ALC Group 3 Right Volume", RK3308_ADC_ANA_CON04(3), RK3308_ADC_CH2_ALC_GAIN_SFT, RK3308_ADC_CH2_ALC_GAIN_MIN, RK3308_ADC_CH2_ALC_GAIN_MAX, 0, rk3308_codec_adc_alc_gain_tlv), - SOC_SINGLE("MIC1 Capture Switch", RK3308_ADC_ANA_CON00(0), 3, 1, 0), - SOC_SINGLE("MIC2 Capture Switch", RK3308_ADC_ANA_CON00(0), 7, 1, 0), - SOC_SINGLE("MIC3 Capture Switch", RK3308_ADC_ANA_CON00(1), 3, 1, 0), - SOC_SINGLE("MIC4 Capture Switch", RK3308_ADC_ANA_CON00(1), 7, 1, 0), - SOC_SINGLE("MIC5 Capture Switch", RK3308_ADC_ANA_CON00(2), 3, 1, 0), - SOC_SINGLE("MIC6 Capture Switch", RK3308_ADC_ANA_CON00(2), 7, 1, 0), - SOC_SINGLE("MIC7 Capture Switch", RK3308_ADC_ANA_CON00(3), 3, 1, 0), - SOC_SINGLE("MIC8 Capture Switch", RK3308_ADC_ANA_CON00(3), 7, 1, 0), - - SOC_SINGLE("MIC12 HPF Capture Switch", RK3308_ADC_DIG_CON04(0), 2, 1, 1), - SOC_SINGLE("MIC34 HPF Capture Switch", RK3308_ADC_DIG_CON04(1), 2, 1, 1), - SOC_SINGLE("MIC56 HPF Capture Switch", RK3308_ADC_DIG_CON04(2), 2, 1, 1), - SOC_SINGLE("MIC78 HPF Capture Switch", RK3308_ADC_DIG_CON04(3), 2, 1, 1), - - SOC_ENUM("MIC12 HPF Cutoff", rk3308_codec_hpf_cutoff_enum12), - SOC_ENUM("MIC34 HPF Cutoff", rk3308_codec_hpf_cutoff_enum34), - SOC_ENUM("MIC56 HPF Cutoff", rk3308_codec_hpf_cutoff_enum56), - SOC_ENUM("MIC78 HPF Cutoff", rk3308_codec_hpf_cutoff_enum78), - - SOC_DOUBLE_TLV("Line Out Playback Volume", + /* ADC High Pass Filter */ + SOC_ENUM_EXT("ADC Group 0 HPF Cut-off", rk3308_hpf_enum_array[0], + rk3308_codec_hpf_get, rk3308_codec_hpf_put), + SOC_ENUM_EXT("ADC Group 1 HPF Cut-off", rk3308_hpf_enum_array[1], + rk3308_codec_hpf_get, rk3308_codec_hpf_put), + SOC_ENUM_EXT("ADC Group 2 HPF Cut-off", rk3308_hpf_enum_array[2], + rk3308_codec_hpf_get, rk3308_codec_hpf_put), + SOC_ENUM_EXT("ADC Group 3 HPF Cut-off", rk3308_hpf_enum_array[3], + rk3308_codec_hpf_get, rk3308_codec_hpf_put), + + /* DAC LINEOUT */ + SOC_SINGLE_TLV("DAC LINEOUT Left Volume", RK3308_DAC_ANA_CON04, RK3308_DAC_L_LINEOUT_GAIN_SFT, + RK3308_DAC_L_LINEOUT_GAIN_MAX, + 0, rk3308_codec_dac_lineout_gain_tlv), + SOC_SINGLE_TLV("DAC LINEOUT Right Volume", + RK3308_DAC_ANA_CON04, RK3308_DAC_R_LINEOUT_GAIN_SFT, - RK3308_DAC_x_LINEOUT_GAIN_MAX, + RK3308_DAC_R_LINEOUT_GAIN_MAX, 0, rk3308_codec_dac_lineout_gain_tlv), - SOC_DOUBLE("Line Out Playback Switch", - RK3308_DAC_ANA_CON04, - RK3308_DAC_L_LINEOUT_MUTE_SFT, - RK3308_DAC_R_LINEOUT_MUTE_SFT, 1, 0), - SOC_DOUBLE_R_TLV("Headphone Playback Volume", - RK3308_DAC_ANA_CON05, - RK3308_DAC_ANA_CON06, - RK3308_DAC_x_HPOUT_GAIN_SFT, - RK3308_DAC_x_HPOUT_GAIN_MAX, - 0, rk3308_codec_dac_hpout_gain_tlv), - SOC_DOUBLE("Headphone Playback Switch", - RK3308_DAC_ANA_CON03, - RK3308_DAC_L_HPOUT_MUTE_SFT, - RK3308_DAC_R_HPOUT_MUTE_SFT, 1, 0), - SOC_DOUBLE_RANGE_TLV("DAC HPMIX Playback Volume", + + /* DAC HPOUT */ + SOC_SINGLE_EXT_TLV("DAC HPOUT Left Volume", + RK3308_DAC_ANA_CON05, + RK3308_DAC_L_HPOUT_GAIN_SFT, + RK3308_DAC_L_HPOUT_GAIN_MAX, + 0, + rk3308_codec_hpout_l_get_tlv, + rk3308_codec_hpout_l_put_tlv, + rk3308_codec_dac_hpout_gain_tlv), + SOC_SINGLE_EXT_TLV("DAC HPOUT Right Volume", + RK3308_DAC_ANA_CON06, + RK3308_DAC_R_HPOUT_GAIN_SFT, + RK3308_DAC_R_HPOUT_GAIN_MAX, + 0, + rk3308_codec_hpout_r_get_tlv, + rk3308_codec_hpout_r_put_tlv, + rk3308_codec_dac_hpout_gain_tlv), + + /* DAC HPMIX */ + SOC_SINGLE_RANGE_TLV("DAC HPMIX Left Volume", RK3308_DAC_ANA_CON12, RK3308_DAC_L_HPMIX_GAIN_SFT, + RK3308_DAC_L_HPMIX_GAIN_MIN, + RK3308_DAC_L_HPMIX_GAIN_MAX, + 0, rk3308_codec_dac_hpmix_gain_tlv), + SOC_SINGLE_RANGE_TLV("DAC HPMIX Right Volume", + RK3308_DAC_ANA_CON12, RK3308_DAC_R_HPMIX_GAIN_SFT, - 1, 2, 0, rk3308_codec_dac_hpmix_gain_tlv), + RK3308_DAC_R_HPMIX_GAIN_MIN, + RK3308_DAC_R_HPMIX_GAIN_MAX, + 0, rk3308_codec_dac_hpmix_gain_tlv), }; -static int rk3308_codec_pop_sound_set(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event) +static int rk3308_codec_agc_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); - unsigned int val = (event == SND_SOC_DAPM_POST_PMU) ? - RK3308_DAC_HPOUT_POP_SOUND_x_WORK : - RK3308_DAC_HPOUT_POP_SOUND_x_INIT; - unsigned int mask = RK3308_DAC_HPOUT_POP_SOUND_x_MSK; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01, - mask << w->shift, val << w->shift); - - return 0; -} - -static const struct snd_soc_dapm_widget rk3308_codec_dapm_widgets[] = { - SND_SOC_DAPM_INPUT("MIC1"), - SND_SOC_DAPM_INPUT("MIC2"), - SND_SOC_DAPM_INPUT("MIC3"), - SND_SOC_DAPM_INPUT("MIC4"), - SND_SOC_DAPM_INPUT("MIC5"), - SND_SOC_DAPM_INPUT("MIC6"), - SND_SOC_DAPM_INPUT("MIC7"), - SND_SOC_DAPM_INPUT("MIC8"), - - SND_SOC_DAPM_SUPPLY("ADC_CURRENT_EN12", RK3308_ADC_ANA_CON06(0), 0, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADC_CURRENT_EN34", RK3308_ADC_ANA_CON06(1), 0, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADC_CURRENT_EN56", RK3308_ADC_ANA_CON06(2), 0, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADC_CURRENT_EN78", RK3308_ADC_ANA_CON06(3), 0, 0, NULL, 0), - - SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC1_EN", RK3308_ADC_ANA_CON00(0), 1, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC2_EN", RK3308_ADC_ANA_CON00(0), 5, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC3_EN", RK3308_ADC_ANA_CON00(1), 1, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC4_EN", RK3308_ADC_ANA_CON00(1), 5, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC5_EN", RK3308_ADC_ANA_CON00(2), 1, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC6_EN", RK3308_ADC_ANA_CON00(2), 5, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC7_EN", RK3308_ADC_ANA_CON00(3), 1, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC8_EN", RK3308_ADC_ANA_CON00(3), 5, 1, 1, 0), - - SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC1_WORK", RK3308_ADC_ANA_CON00(0), 2, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC2_WORK", RK3308_ADC_ANA_CON00(0), 6, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC3_WORK", RK3308_ADC_ANA_CON00(1), 2, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC4_WORK", RK3308_ADC_ANA_CON00(1), 6, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC5_WORK", RK3308_ADC_ANA_CON00(2), 2, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC6_WORK", RK3308_ADC_ANA_CON00(2), 6, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC7_WORK", RK3308_ADC_ANA_CON00(3), 2, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC8_WORK", RK3308_ADC_ANA_CON00(3), 6, 1, 1, 0), - - /* - * In theory MIC1 and MIC2 can switch to LINE IN, but this is not - * supported so all we can do is enabling the MIC input. - */ - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "CH1_IN_SEL", RK3308_ADC_ANA_CON07(0), 4, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "CH2_IN_SEL", RK3308_ADC_ANA_CON07(0), 6, 1, 1, 0), - - SND_SOC_DAPM_SUPPLY("ADC1_BUF_REF_EN", RK3308_ADC_ANA_CON00(0), 0, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADC2_BUF_REF_EN", RK3308_ADC_ANA_CON00(0), 4, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADC3_BUF_REF_EN", RK3308_ADC_ANA_CON00(1), 0, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADC4_BUF_REF_EN", RK3308_ADC_ANA_CON00(1), 4, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADC5_BUF_REF_EN", RK3308_ADC_ANA_CON00(2), 0, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADC6_BUF_REF_EN", RK3308_ADC_ANA_CON00(2), 4, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADC7_BUF_REF_EN", RK3308_ADC_ANA_CON00(3), 0, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADC8_BUF_REF_EN", RK3308_ADC_ANA_CON00(3), 4, 0, NULL, 0), - - SND_SOC_DAPM_SUPPLY("ADC_MCLK_GATE", RK3308_GLB_CON, 5, 1, NULL, 0), - - SND_SOC_DAPM_SUPPLY("ADC1_CLK_EN", RK3308_ADC_ANA_CON05(0), 0, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADC2_CLK_EN", RK3308_ADC_ANA_CON05(0), 4, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADC3_CLK_EN", RK3308_ADC_ANA_CON05(1), 0, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADC4_CLK_EN", RK3308_ADC_ANA_CON05(1), 4, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADC5_CLK_EN", RK3308_ADC_ANA_CON05(2), 0, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADC6_CLK_EN", RK3308_ADC_ANA_CON05(2), 4, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADC7_CLK_EN", RK3308_ADC_ANA_CON05(3), 0, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADC8_CLK_EN", RK3308_ADC_ANA_CON05(3), 4, 0, NULL, 0), - - /* The "ALC" name from the TRM is misleading, these are needed even without ALC/AGC */ - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC1_EN", RK3308_ADC_ANA_CON02(0), 0, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC2_EN", RK3308_ADC_ANA_CON02(0), 4, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC3_EN", RK3308_ADC_ANA_CON02(1), 0, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC4_EN", RK3308_ADC_ANA_CON02(1), 4, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC5_EN", RK3308_ADC_ANA_CON02(2), 0, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC6_EN", RK3308_ADC_ANA_CON02(2), 4, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC7_EN", RK3308_ADC_ANA_CON02(3), 0, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC8_EN", RK3308_ADC_ANA_CON02(3), 4, 1, 1, 0), - - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC1_EN", RK3308_ADC_ANA_CON05(0), 1, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC2_EN", RK3308_ADC_ANA_CON05(0), 5, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC3_EN", RK3308_ADC_ANA_CON05(1), 1, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC4_EN", RK3308_ADC_ANA_CON05(1), 5, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC5_EN", RK3308_ADC_ANA_CON05(2), 1, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC6_EN", RK3308_ADC_ANA_CON05(2), 5, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC7_EN", RK3308_ADC_ANA_CON05(3), 1, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC8_EN", RK3308_ADC_ANA_CON05(3), 5, 1, 1, 0), - - SND_SOC_DAPM_ADC("ADC1_WORK", "Capture", RK3308_ADC_ANA_CON05(0), 2, 0), - SND_SOC_DAPM_ADC("ADC2_WORK", "Capture", RK3308_ADC_ANA_CON05(0), 6, 0), - SND_SOC_DAPM_ADC("ADC3_WORK", "Capture", RK3308_ADC_ANA_CON05(1), 2, 0), - SND_SOC_DAPM_ADC("ADC4_WORK", "Capture", RK3308_ADC_ANA_CON05(1), 6, 0), - SND_SOC_DAPM_ADC("ADC5_WORK", "Capture", RK3308_ADC_ANA_CON05(2), 2, 0), - SND_SOC_DAPM_ADC("ADC6_WORK", "Capture", RK3308_ADC_ANA_CON05(2), 6, 0), - SND_SOC_DAPM_ADC("ADC7_WORK", "Capture", RK3308_ADC_ANA_CON05(3), 2, 0), - SND_SOC_DAPM_ADC("ADC8_WORK", "Capture", RK3308_ADC_ANA_CON05(3), 6, 0), - - /* The "ALC" name from the TRM is misleading, these are needed even without ALC/AGC */ - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC1_WORK", RK3308_ADC_ANA_CON02(0), 1, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC2_WORK", RK3308_ADC_ANA_CON02(0), 5, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC3_WORK", RK3308_ADC_ANA_CON02(1), 1, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC4_WORK", RK3308_ADC_ANA_CON02(1), 5, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC5_WORK", RK3308_ADC_ANA_CON02(2), 1, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC6_WORK", RK3308_ADC_ANA_CON02(2), 5, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC7_WORK", RK3308_ADC_ANA_CON02(3), 1, 1, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC8_WORK", RK3308_ADC_ANA_CON02(3), 5, 1, 1, 0), - - SND_SOC_DAPM_SUPPLY("MICBIAS Current", RK3308_ADC_ANA_CON08(0), 4, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("MICBIAS1", RK3308_ADC_ANA_CON07(1), 3, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("MICBIAS2", RK3308_ADC_ANA_CON07(2), 3, 0, NULL, 0), - - SND_SOC_DAPM_OUT_DRV("DAC_L_HPMIX_EN", RK3308_DAC_ANA_CON13, 0, 0, NULL, 0), - SND_SOC_DAPM_OUT_DRV("DAC_R_HPMIX_EN", RK3308_DAC_ANA_CON13, 4, 0, NULL, 0), - SND_SOC_DAPM_OUT_DRV("DAC_L_HPMIX_WORK", RK3308_DAC_ANA_CON13, 1, 0, NULL, 0), - SND_SOC_DAPM_OUT_DRV("DAC_R_HPMIX_WORK", RK3308_DAC_ANA_CON13, 5, 0, NULL, 0), - /* HPMIX is not actually acting as a mixer as the only supported input is I2S */ - SND_SOC_DAPM_OUT_DRV("DAC_L_HPMIX_SEL", RK3308_DAC_ANA_CON12, 2, 0, NULL, 0), - SND_SOC_DAPM_OUT_DRV("DAC_R_HPMIX_SEL", RK3308_DAC_ANA_CON12, 6, 0, NULL, 0), - SND_SOC_DAPM_MIXER("DAC HPMIX Left", RK3308_DAC_ANA_CON13, 2, 0, NULL, 0), - SND_SOC_DAPM_MIXER("DAC HPMIX Right", RK3308_DAC_ANA_CON13, 6, 0, NULL, 0), - - SND_SOC_DAPM_SUPPLY("DAC_MCLK_GATE", RK3308_GLB_CON, 4, 1, NULL, 0), - - SND_SOC_DAPM_SUPPLY("DAC_CURRENT_EN", RK3308_DAC_ANA_CON00, 0, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("DAC_L_REF_EN", RK3308_DAC_ANA_CON02, 0, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("DAC_R_REF_EN", RK3308_DAC_ANA_CON02, 4, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("DAC_L_CLK_EN", RK3308_DAC_ANA_CON02, 1, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("DAC_R_CLK_EN", RK3308_DAC_ANA_CON02, 5, 0, NULL, 0), - SND_SOC_DAPM_DAC("DAC_L_DAC_WORK", NULL, RK3308_DAC_ANA_CON02, 3, 0), - SND_SOC_DAPM_DAC("DAC_R_DAC_WORK", NULL, RK3308_DAC_ANA_CON02, 7, 0), - - SND_SOC_DAPM_SUPPLY("DAC_BUF_REF_L", RK3308_DAC_ANA_CON01, 2, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("DAC_BUF_REF_R", RK3308_DAC_ANA_CON01, 6, 0, NULL, 0), - SND_SOC_DAPM_OUT_DRV_E("HPOUT_POP_SOUND_L", SND_SOC_NOPM, 0, 0, NULL, 0, - rk3308_codec_pop_sound_set, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), - SND_SOC_DAPM_OUT_DRV_E("HPOUT_POP_SOUND_R", SND_SOC_NOPM, 4, 0, NULL, 0, - rk3308_codec_pop_sound_set, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), - SND_SOC_DAPM_OUT_DRV("L_HPOUT_EN", RK3308_DAC_ANA_CON03, 1, 0, NULL, 0), - SND_SOC_DAPM_OUT_DRV("R_HPOUT_EN", RK3308_DAC_ANA_CON03, 5, 0, NULL, 0), - SND_SOC_DAPM_OUT_DRV("L_HPOUT_WORK", RK3308_DAC_ANA_CON03, 2, 0, NULL, 0), - SND_SOC_DAPM_OUT_DRV("R_HPOUT_WORK", RK3308_DAC_ANA_CON03, 6, 0, NULL, 0), - SND_SOC_DAPM_OUTPUT("HPOUT_L"), - SND_SOC_DAPM_OUTPUT("HPOUT_R"), - - SND_SOC_DAPM_OUT_DRV("L_LINEOUT_EN", RK3308_DAC_ANA_CON04, 0, 0, NULL, 0), - SND_SOC_DAPM_OUT_DRV("R_LINEOUT_EN", RK3308_DAC_ANA_CON04, 4, 0, NULL, 0), - SND_SOC_DAPM_OUTPUT("LINEOUT_L"), - SND_SOC_DAPM_OUTPUT("LINEOUT_R"), -}; + if (e->reg < 0 || e->reg > ADC_LR_GROUP_MAX - 1) { + dev_err(rk3308->plat_dev, + "%s: Invalid ADC grp: %d\n", __func__, e->reg); + return -EINVAL; + } -static const struct snd_soc_dapm_route rk3308_codec_dapm_routes[] = { - { "MICBIAS1", NULL, "MICBIAS Current" }, - { "MICBIAS2", NULL, "MICBIAS Current" }, - - { "MIC1_EN", NULL, "MIC1" }, - { "MIC2_EN", NULL, "MIC2" }, - { "MIC3_EN", NULL, "MIC3" }, - { "MIC4_EN", NULL, "MIC4" }, - { "MIC5_EN", NULL, "MIC5" }, - { "MIC6_EN", NULL, "MIC6" }, - { "MIC7_EN", NULL, "MIC7" }, - { "MIC8_EN", NULL, "MIC8" }, - - { "MIC1_WORK", NULL, "MIC1_EN" }, - { "MIC2_WORK", NULL, "MIC2_EN" }, - { "MIC3_WORK", NULL, "MIC3_EN" }, - { "MIC4_WORK", NULL, "MIC4_EN" }, - { "MIC5_WORK", NULL, "MIC5_EN" }, - { "MIC6_WORK", NULL, "MIC6_EN" }, - { "MIC7_WORK", NULL, "MIC7_EN" }, - { "MIC8_WORK", NULL, "MIC8_EN" }, - - { "CH1_IN_SEL", NULL, "MIC1_WORK" }, - { "CH2_IN_SEL", NULL, "MIC2_WORK" }, - - { "ALC1_EN", NULL, "CH1_IN_SEL" }, - { "ALC2_EN", NULL, "CH2_IN_SEL" }, - { "ALC3_EN", NULL, "MIC3_WORK" }, - { "ALC4_EN", NULL, "MIC4_WORK" }, - { "ALC5_EN", NULL, "MIC5_WORK" }, - { "ALC6_EN", NULL, "MIC6_WORK" }, - { "ALC7_EN", NULL, "MIC7_WORK" }, - { "ALC8_EN", NULL, "MIC8_WORK" }, - - { "ADC1_EN", NULL, "ALC1_EN" }, - { "ADC2_EN", NULL, "ALC2_EN" }, - { "ADC3_EN", NULL, "ALC3_EN" }, - { "ADC4_EN", NULL, "ALC4_EN" }, - { "ADC5_EN", NULL, "ALC5_EN" }, - { "ADC6_EN", NULL, "ALC6_EN" }, - { "ADC7_EN", NULL, "ALC7_EN" }, - { "ADC8_EN", NULL, "ALC8_EN" }, - - { "ADC1_WORK", NULL, "ADC1_EN" }, - { "ADC2_WORK", NULL, "ADC2_EN" }, - { "ADC3_WORK", NULL, "ADC3_EN" }, - { "ADC4_WORK", NULL, "ADC4_EN" }, - { "ADC5_WORK", NULL, "ADC5_EN" }, - { "ADC6_WORK", NULL, "ADC6_EN" }, - { "ADC7_WORK", NULL, "ADC7_EN" }, - { "ADC8_WORK", NULL, "ADC8_EN" }, - - { "ADC1_BUF_REF_EN", NULL, "ADC_CURRENT_EN12" }, - { "ADC2_BUF_REF_EN", NULL, "ADC_CURRENT_EN12" }, - { "ADC3_BUF_REF_EN", NULL, "ADC_CURRENT_EN34" }, - { "ADC4_BUF_REF_EN", NULL, "ADC_CURRENT_EN34" }, - { "ADC5_BUF_REF_EN", NULL, "ADC_CURRENT_EN56" }, - { "ADC6_BUF_REF_EN", NULL, "ADC_CURRENT_EN56" }, - { "ADC7_BUF_REF_EN", NULL, "ADC_CURRENT_EN78" }, - { "ADC8_BUF_REF_EN", NULL, "ADC_CURRENT_EN78" }, - - { "ADC1_WORK", NULL, "ADC1_BUF_REF_EN" }, - { "ADC2_WORK", NULL, "ADC2_BUF_REF_EN" }, - { "ADC3_WORK", NULL, "ADC3_BUF_REF_EN" }, - { "ADC4_WORK", NULL, "ADC4_BUF_REF_EN" }, - { "ADC5_WORK", NULL, "ADC5_BUF_REF_EN" }, - { "ADC6_WORK", NULL, "ADC6_BUF_REF_EN" }, - { "ADC7_WORK", NULL, "ADC7_BUF_REF_EN" }, - { "ADC8_WORK", NULL, "ADC8_BUF_REF_EN" }, - - { "ADC1_CLK_EN", NULL, "ADC_MCLK_GATE" }, - { "ADC2_CLK_EN", NULL, "ADC_MCLK_GATE" }, - { "ADC3_CLK_EN", NULL, "ADC_MCLK_GATE" }, - { "ADC4_CLK_EN", NULL, "ADC_MCLK_GATE" }, - { "ADC5_CLK_EN", NULL, "ADC_MCLK_GATE" }, - { "ADC6_CLK_EN", NULL, "ADC_MCLK_GATE" }, - { "ADC7_CLK_EN", NULL, "ADC_MCLK_GATE" }, - { "ADC8_CLK_EN", NULL, "ADC_MCLK_GATE" }, - - { "ADC1_WORK", NULL, "ADC1_CLK_EN" }, - { "ADC2_WORK", NULL, "ADC2_CLK_EN" }, - { "ADC3_WORK", NULL, "ADC3_CLK_EN" }, - { "ADC4_WORK", NULL, "ADC4_CLK_EN" }, - { "ADC5_WORK", NULL, "ADC5_CLK_EN" }, - { "ADC6_WORK", NULL, "ADC6_CLK_EN" }, - { "ADC7_WORK", NULL, "ADC7_CLK_EN" }, - { "ADC8_WORK", NULL, "ADC8_CLK_EN" }, - - { "ALC1_WORK", NULL, "ADC1_WORK" }, - { "ALC2_WORK", NULL, "ADC2_WORK" }, - { "ALC3_WORK", NULL, "ADC3_WORK" }, - { "ALC4_WORK", NULL, "ADC4_WORK" }, - { "ALC5_WORK", NULL, "ADC5_WORK" }, - { "ALC6_WORK", NULL, "ADC6_WORK" }, - { "ALC7_WORK", NULL, "ADC7_WORK" }, - { "ALC8_WORK", NULL, "ADC8_WORK" }, - - { "HiFi Capture", NULL, "ALC1_WORK" }, - { "HiFi Capture", NULL, "ALC2_WORK" }, - { "HiFi Capture", NULL, "ALC3_WORK" }, - { "HiFi Capture", NULL, "ALC4_WORK" }, - { "HiFi Capture", NULL, "ALC5_WORK" }, - { "HiFi Capture", NULL, "ALC6_WORK" }, - { "HiFi Capture", NULL, "ALC7_WORK" }, - { "HiFi Capture", NULL, "ALC8_WORK" }, - - { "DAC_L_HPMIX_EN", NULL, "HiFi Playback" }, - { "DAC_R_HPMIX_EN", NULL, "HiFi Playback" }, - { "DAC_L_HPMIX_WORK", NULL, "DAC_L_HPMIX_EN" }, - { "DAC_R_HPMIX_WORK", NULL, "DAC_R_HPMIX_EN" }, - { "DAC HPMIX Left", NULL, "DAC_L_HPMIX_WORK" }, - { "DAC HPMIX Right", NULL, "DAC_R_HPMIX_WORK" }, - - { "DAC_L_DAC_WORK", NULL, "DAC HPMIX Left" }, - { "DAC_R_DAC_WORK", NULL, "DAC HPMIX Right" }, - - { "DAC_L_REF_EN", NULL, "DAC_CURRENT_EN" }, - { "DAC_R_REF_EN", NULL, "DAC_CURRENT_EN" }, - { "DAC_L_CLK_EN", NULL, "DAC_L_REF_EN" }, - { "DAC_R_CLK_EN", NULL, "DAC_R_REF_EN" }, - { "DAC_L_CLK_EN", NULL, "DAC_MCLK_GATE" }, - { "DAC_R_CLK_EN", NULL, "DAC_MCLK_GATE" }, - { "DAC_L_DAC_WORK", NULL, "DAC_L_CLK_EN" }, - { "DAC_R_DAC_WORK", NULL, "DAC_R_CLK_EN" }, - { "DAC_L_HPMIX_SEL", NULL, "DAC_L_DAC_WORK" }, - { "DAC_R_HPMIX_SEL", NULL, "DAC_R_DAC_WORK" }, - - { "HPOUT_L", NULL, "DAC_BUF_REF_L" }, - { "HPOUT_R", NULL, "DAC_BUF_REF_R" }, - { "L_HPOUT_EN", NULL, "DAC_L_HPMIX_SEL" }, - { "R_HPOUT_EN", NULL, "DAC_R_HPMIX_SEL" }, - { "L_HPOUT_WORK", NULL, "L_HPOUT_EN" }, - { "R_HPOUT_WORK", NULL, "R_HPOUT_EN" }, - { "HPOUT_POP_SOUND_L", NULL, "L_HPOUT_WORK" }, - { "HPOUT_POP_SOUND_R", NULL, "R_HPOUT_WORK" }, - { "HPOUT_L", NULL, "HPOUT_POP_SOUND_L" }, - { "HPOUT_R", NULL, "HPOUT_POP_SOUND_R" }, - - { "L_LINEOUT_EN", NULL, "DAC_L_HPMIX_SEL" }, - { "R_LINEOUT_EN", NULL, "DAC_R_HPMIX_SEL" }, - { "LINEOUT_L", NULL, "L_LINEOUT_EN" }, - { "LINEOUT_R", NULL, "R_LINEOUT_EN" }, -}; + if (e->shift_l) + ucontrol->value.integer.value[0] = rk3308->agc_r[e->reg]; + else + ucontrol->value.integer.value[0] = rk3308->agc_l[e->reg]; + + return 0; +} -static int rk3308_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) +static int rk3308_codec_agc_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component = codec_dai->component; + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); - const unsigned int inv_bits = fmt & SND_SOC_DAIFMT_INV_MASK; - const bool inv_bitclk = - (inv_bits & SND_SOC_DAIFMT_IB_IF) || - (inv_bits & SND_SOC_DAIFMT_IB_NF); - const bool inv_frmclk = - (inv_bits & SND_SOC_DAIFMT_IB_IF) || - (inv_bits & SND_SOC_DAIFMT_NB_IF); - const unsigned int dac_master_bits = rk3308->codec_ver < ACODEC_VERSION_C ? - RK3308_DAC_IO_MODE_MASTER | RK3308_DAC_MODE_MASTER : - RK3308BS_DAC_IO_MODE_MASTER | RK3308BS_DAC_MODE_MASTER; - unsigned int adc_aif1 = 0, adc_aif2 = 0, dac_aif1 = 0, dac_aif2 = 0; - bool is_master = false; - int grp; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int value = ucontrol->value.integer.value[0]; + int grp = e->reg; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: - break; - case SND_SOC_DAIFMT_CBP_CFP: - adc_aif2 |= RK3308_ADC_IO_MODE_MASTER; - adc_aif2 |= RK3308_ADC_MODE_MASTER; - dac_aif2 |= dac_master_bits; - is_master = true; - break; - default: + if (e->reg < 0 || e->reg > ADC_LR_GROUP_MAX - 1) { + dev_err(rk3308->plat_dev, + "%s: Invalid ADC grp: %d\n", __func__, e->reg); return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_DSP_A: - adc_aif1 |= RK3308_ADC_I2S_MODE_PCM; - dac_aif1 |= RK3308_DAC_I2S_MODE_PCM; - break; - case SND_SOC_DAIFMT_I2S: - adc_aif1 |= RK3308_ADC_I2S_MODE_I2S; - dac_aif1 |= RK3308_DAC_I2S_MODE_I2S; - break; - case SND_SOC_DAIFMT_RIGHT_J: - adc_aif1 |= RK3308_ADC_I2S_MODE_RJ; - dac_aif1 |= RK3308_DAC_I2S_MODE_RJ; - break; - case SND_SOC_DAIFMT_LEFT_J: - adc_aif1 |= RK3308_ADC_I2S_MODE_LJ; - dac_aif1 |= RK3308_DAC_I2S_MODE_LJ; - break; - default: - return -EINVAL; - } + if (value) { + /* ALC AGC On */ + if (e->shift_l) { + /* ALC AGC Right On */ + regmap_update_bits(rk3308->regmap, RK3308_ALC_R_DIG_CON09(grp), + RK3308_AGC_FUNC_SEL_MSK, + RK3308_AGC_FUNC_SEL_EN); + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON11(grp), + RK3308_ADC_ALCR_CON_GAIN_PGAR_MSK, + RK3308_ADC_ALCR_CON_GAIN_PGAR_EN); - if (inv_bitclk) { - adc_aif2 |= RK3308_ADC_I2S_BIT_CLK_POL_REVERSAL; - dac_aif2 |= RK3308_DAC_I2S_BIT_CLK_POL_REVERSAL; - } + rk3308->agc_r[e->reg] = 1; + } else { + /* ALC AGC Left On */ + regmap_update_bits(rk3308->regmap, RK3308_ALC_L_DIG_CON09(grp), + RK3308_AGC_FUNC_SEL_MSK, + RK3308_AGC_FUNC_SEL_EN); + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON11(grp), + RK3308_ADC_ALCL_CON_GAIN_PGAL_MSK, + RK3308_ADC_ALCL_CON_GAIN_PGAL_EN); - if (inv_frmclk) { - adc_aif1 |= RK3308_ADC_I2S_LRC_POL_REVERSAL; - dac_aif1 |= RK3308_DAC_I2S_LRC_POL_REVERSAL; - } + rk3308->agc_l[e->reg] = 1; + } + } else { + /* ALC AGC Off */ + if (e->shift_l) { + /* ALC AGC Right Off */ + regmap_update_bits(rk3308->regmap, RK3308_ALC_R_DIG_CON09(grp), + RK3308_AGC_FUNC_SEL_MSK, + RK3308_AGC_FUNC_SEL_DIS); + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON11(grp), + RK3308_ADC_ALCR_CON_GAIN_PGAR_MSK, + RK3308_ADC_ALCR_CON_GAIN_PGAR_DIS); - /* - * Hold ADC Digital registers start at master mode - * - * There are 8 ADCs which use the same internal SCLK and LRCK for - * master mode. We need to make sure that they are in effect at the - * same time, otherwise they will cause abnormal clocks. - */ - if (is_master) - regmap_clear_bits(rk3308->regmap, RK3308_GLB_CON, RK3308_ADC_DIG_WORK); + rk3308->agc_r[e->reg] = 0; + } else { + /* ALC AGC Left Off */ + regmap_update_bits(rk3308->regmap, RK3308_ALC_L_DIG_CON09(grp), + RK3308_AGC_FUNC_SEL_MSK, + RK3308_AGC_FUNC_SEL_DIS); + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON11(grp), + RK3308_ADC_ALCL_CON_GAIN_PGAL_MSK, + RK3308_ADC_ALCL_CON_GAIN_PGAL_DIS); - for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) { - regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON01(grp), - RK3308_ADC_I2S_LRC_POL_REVERSAL | - RK3308_ADC_I2S_MODE_MSK, - adc_aif1); - regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON02(grp), - RK3308_ADC_IO_MODE_MASTER | - RK3308_ADC_MODE_MASTER | - RK3308_ADC_I2S_BIT_CLK_POL_REVERSAL, - adc_aif2); + rk3308->agc_l[e->reg] = 0; + } } - /* Hold ADC Digital registers end at master mode */ - if (is_master) - regmap_set_bits(rk3308->regmap, RK3308_GLB_CON, RK3308_ADC_DIG_WORK); - - regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON01, - RK3308_DAC_I2S_LRC_POL_REVERSAL | - RK3308_DAC_I2S_MODE_MSK, - dac_aif1); - regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON02, - dac_master_bits | RK3308_DAC_I2S_BIT_CLK_POL_REVERSAL, - dac_aif2); - return 0; } -static int rk3308_codec_dac_dig_config(struct rk3308_codec_priv *rk3308, - struct snd_pcm_hw_params *params) +static int rk3308_codec_agc_asr_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - unsigned int dac_aif1 = 0; + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int value; + int grp = e->reg; - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_16BITS; - break; - case SNDRV_PCM_FORMAT_S20_3LE: - dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_20BITS; - break; - case SNDRV_PCM_FORMAT_S24_LE: - dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_24BITS; - break; - case SNDRV_PCM_FORMAT_S32_LE: - dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_32BITS; - break; - default: + if (e->reg < 0 || e->reg > ADC_LR_GROUP_MAX - 1) { + dev_err(rk3308->plat_dev, + "%s: Invalid ADC grp: %d\n", __func__, e->reg); return -EINVAL; } - regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON01, - RK3308_DAC_I2S_VALID_LEN_MSK, dac_aif1); - regmap_set_bits(rk3308->regmap, RK3308_DAC_DIG_CON02, RK3308_DAC_I2S_WORK); + if (e->shift_l) { + regmap_read(rk3308->regmap, RK3308_ALC_R_DIG_CON04(grp), &value); + rk3308->agc_asr_r[e->reg] = value >> RK3308_AGC_APPROX_RATE_SFT; + ucontrol->value.integer.value[0] = rk3308->agc_asr_r[e->reg]; + } else { + regmap_read(rk3308->regmap, RK3308_ALC_L_DIG_CON04(grp), &value); + rk3308->agc_asr_l[e->reg] = value >> RK3308_AGC_APPROX_RATE_SFT; + ucontrol->value.integer.value[0] = rk3308->agc_asr_l[e->reg]; + } return 0; } -static int rk3308_codec_adc_dig_config(struct rk3308_codec_priv *rk3308, - struct snd_pcm_hw_params *params) +static int rk3308_codec_agc_asr_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - unsigned int adc_aif1 = 0; - /* - * grp 0 = ADC1 and ADC2 - * grp 1 = ADC3 and ADC4 - * grp 2 = ADC5 and ADC6 - * grp 3 = ADC7 and ADC8 - */ - u32 used_adc_grps; - int grp; + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int value; + int grp = e->reg; - switch (params_channels(params)) { - case 1: - adc_aif1 |= RK3308_ADC_I2S_MONO; - used_adc_grps = 1; - break; - case 2: - case 4: - case 6: - case 8: - used_adc_grps = params_channels(params) / 2; - break; - default: - dev_err(rk3308->dev, "Invalid channel number %d\n", params_channels(params)); + if (e->reg < 0 || e->reg > ADC_LR_GROUP_MAX - 1) { + dev_err(rk3308->plat_dev, + "%s: Invalid ADC grp: %d\n", __func__, e->reg); return -EINVAL; } - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_16BITS; - break; - case SNDRV_PCM_FORMAT_S20_3LE: - adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_20BITS; - break; - case SNDRV_PCM_FORMAT_S24_LE: - adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_24BITS; - break; - case SNDRV_PCM_FORMAT_S32_LE: - adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_32BITS; - break; - default: + value = ucontrol->value.integer.value[0] << RK3308_AGC_APPROX_RATE_SFT; + + if (e->shift_l) { + /* ALC AGC Right Approximate Sample Rate */ + regmap_update_bits(rk3308->regmap, RK3308_ALC_R_DIG_CON04(grp), + RK3308_AGC_APPROX_RATE_MSK, + value); + rk3308->agc_asr_r[e->reg] = ucontrol->value.integer.value[0]; + } else { + /* ALC AGC Left Approximate Sample Rate */ + regmap_update_bits(rk3308->regmap, RK3308_ALC_L_DIG_CON04(grp), + RK3308_AGC_APPROX_RATE_MSK, + value); + rk3308->agc_asr_l[e->reg] = ucontrol->value.integer.value[0]; + } + + return 0; +} + +static int rk3308_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 rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int value; + int grp = e->reg; + + if (e->reg < 0 || e->reg > ADC_LR_GROUP_MAX - 1) { + dev_err(rk3308->plat_dev, + "%s: Invalid ADC grp: %d\n", __func__, e->reg); return -EINVAL; } - for (grp = 0; grp < used_adc_grps; grp++) { - regmap_update_bits(rk3308->regmap, - RK3308_ADC_DIG_CON03(grp), - RK3308_ADC_L_CH_BIST_MSK | RK3308_ADC_R_CH_BIST_MSK, - RK3308_ADC_L_CH_NORMAL_LEFT | RK3308_ADC_R_CH_NORMAL_RIGHT); - regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON01(grp), - RK3308_ADC_I2S_VALID_LEN_MSK | RK3308_ADC_I2S_MONO, adc_aif1); - regmap_set_bits(rk3308->regmap, RK3308_ADC_DIG_CON02(grp), RK3308_ADC_I2S_WORK); + if (e->shift_l) { + /* ADC MIC Right Mute/Work Infos */ + regmap_read(rk3308->regmap, RK3308_ADC_DIG_CON03(grp), &value); + rk3308->mic_mute_r[e->reg] = (value & RK3308_ADC_R_CH_BIST_SINE) >> + RK3308_ADC_R_CH_BIST_SFT; + ucontrol->value.integer.value[0] = rk3308->mic_mute_r[e->reg]; + } else { + /* ADC MIC Left Mute/Work Infos */ + regmap_read(rk3308->regmap, RK3308_ADC_DIG_CON03(grp), &value); + rk3308->mic_mute_l[e->reg] = (value & RK3308_ADC_L_CH_BIST_SINE) >> + RK3308_ADC_L_CH_BIST_SFT; + ucontrol->value.integer.value[0] = rk3308->mic_mute_l[e->reg]; } return 0; } -static int rk3308_codec_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) +static int rk3308_codec_mic_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component = dai->component; + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int value; + int grp = e->reg; - return (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? - rk3308_codec_dac_dig_config(rk3308, params) : - rk3308_codec_adc_dig_config(rk3308, params); -} + if (e->reg < 0 || e->reg > ADC_LR_GROUP_MAX - 1) { + dev_err(rk3308->plat_dev, + "%s: Invalid ADC grp: %d\n", __func__, e->reg); + return -EINVAL; + } -static const struct snd_soc_dai_ops rk3308_codec_dai_ops = { - .hw_params = rk3308_codec_hw_params, - .set_fmt = rk3308_codec_set_dai_fmt, -}; + if (e->shift_l) { + /* ADC MIC Right Mute/Work Configuration */ + value = ucontrol->value.integer.value[0] << RK3308_ADC_R_CH_BIST_SFT; + regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON03(grp), + RK3308_ADC_R_CH_BIST_SINE, + value); + rk3308->mic_mute_r[e->reg] = ucontrol->value.integer.value[0]; + } else { + /* ADC MIC Left Mute/Work Configuration */ + value = ucontrol->value.integer.value[0] << RK3308_ADC_L_CH_BIST_SFT; + regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON03(grp), + RK3308_ADC_L_CH_BIST_SINE, + value); + rk3308->mic_mute_l[e->reg] = ucontrol->value.integer.value[0]; + } -static struct snd_soc_dai_driver rk3308_codec_dai_driver = { - .name = "rk3308-hifi", - .playback = { - .stream_name = "HiFi Playback", - .channels_min = 2, - .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 = 8, - .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 = &rk3308_codec_dai_ops, -}; + return 0; +} -static void rk3308_codec_reset(struct snd_soc_component *component) +static int rk3308_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 rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); - reset_control_assert(rk3308->reset); - usleep_range(10000, 11000); /* estimated value */ - reset_control_deassert(rk3308->reset); + ucontrol->value.integer.value[0] = rk3308->micbias_volt; - regmap_write(rk3308->regmap, RK3308_GLB_CON, 0x00); - usleep_range(10000, 11000); /* estimated value */ - regmap_write(rk3308->regmap, RK3308_GLB_CON, - RK3308_SYS_WORK | - RK3308_DAC_DIG_WORK | - RK3308_ADC_DIG_WORK); + return 0; } -/* - * Initialize register whose default after HW reset is problematic or which - * are never modified. - */ -static int rk3308_codec_initialize(struct rk3308_codec_priv *rk3308) +static int rk3308_codec_micbias_volts_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - int grp; + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + unsigned int volt = ucontrol->value.integer.value[0]; + int ret; - /* - * Init ADC digital vol to 0 dB (reset value is 0xff, undocumented). - * Range: -97dB ~ +32dB. - */ - if (rk3308->codec_ver == ACODEC_VERSION_C) { - for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) { - regmap_write(rk3308->regmap, RK3308_ADC_DIG_CON05(grp), - RK3308_ADC_DIG_VOL_CON_x_0DB); - regmap_write(rk3308->regmap, RK3308_ADC_DIG_CON06(grp), - RK3308_ADC_DIG_VOL_CON_x_0DB); - } + ret = check_micbias(volt); + if (ret < 0) { + dev_err(rk3308->plat_dev, "The invalid micbias volt: %d\n", + volt); + return ret; } - /* set HPMIX default gains (reset value is 0, which is illegal) */ - regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON12, - RK3308_DAC_L_HPMIX_GAIN_MSK | + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(0), + RK3308_ADC_LEVEL_RANGE_MICBIAS_MSK, + volt); + + rk3308->micbias_volt = volt; + + return 0; +} + +static int rk3308_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 rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = rk3308->enable_micbias; + + return 0; +} + +static int rk3308_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 rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + unsigned int on = ucontrol->value.integer.value[0]; + + if (on) { + if (!rk3308->enable_micbias) + rk3308_codec_micbias_enable(rk3308, rk3308->micbias_volt); + } else { + if (rk3308->enable_micbias) + rk3308_codec_micbias_disable(rk3308); + } + + return 0; +} + +static int rk3308_codec_mic_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return snd_soc_get_volsw_range(kcontrol, ucontrol); +} + +static int rk3308_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 rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + unsigned int gain = ucontrol->value.integer.value[0]; + + if (gain > RK3308_ADC_CH1_MIC_GAIN_MAX) { + dev_err(rk3308->plat_dev, "%s: invalid mic gain: %d\n", + __func__, gain); + return -EINVAL; + } + + if (rk3308->codec_ver == ACODEC_VERSION_A) { + /* + * From the TRM, there are only suupport 0dB(gain==0) and + * 20dB(gain==3) on the codec version A. + */ + if (!(gain == 0 || gain == RK3308_ADC_CH1_MIC_GAIN_MAX)) { + dev_err(rk3308->plat_dev, + "version A doesn't supported: %d, expect: 0,%d\n", + gain, RK3308_ADC_CH1_MIC_GAIN_MAX); + return 0; + } + } + + return snd_soc_put_volsw_range(kcontrol, ucontrol); +} + +static int rk3308_codec_hpf_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int value; + + if (e->reg < 0 || e->reg > ADC_LR_GROUP_MAX - 1) { + dev_err(rk3308->plat_dev, + "%s: Invalid ADC grp: %d\n", __func__, e->reg); + return -EINVAL; + } + + regmap_read(rk3308->regmap, RK3308_ADC_DIG_CON04(e->reg), &value); + if (value & RK3308_ADC_HPF_PATH_MSK) + rk3308->hpf_cutoff[e->reg] = 0; + else + rk3308->hpf_cutoff[e->reg] = 1; + + ucontrol->value.integer.value[0] = rk3308->hpf_cutoff[e->reg]; + + return 0; +} + +static int rk3308_codec_hpf_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk3308_codec_priv *rk3308 = 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 (e->reg < 0 || e->reg > ADC_LR_GROUP_MAX - 1) { + dev_err(rk3308->plat_dev, + "%s: Invalid ADC grp: %d\n", __func__, e->reg); + return -EINVAL; + } + + if (value) { + /* Enable high pass filter for ADCs */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON04(e->reg), + RK3308_ADC_HPF_PATH_MSK, + RK3308_ADC_HPF_PATH_EN); + } else { + /* Disable high pass filter for ADCs. */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON04(e->reg), + RK3308_ADC_HPF_PATH_MSK, + RK3308_ADC_HPF_PATH_DIS); + } + + rk3308->hpf_cutoff[e->reg] = value; + + return 0; +} + +static int rk3308_codec_hpout_l_get_tlv(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return snd_soc_get_volsw_range(kcontrol, ucontrol); +} + +static int rk3308_codec_hpout_l_put_tlv(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + unsigned int dgain = ucontrol->value.integer.value[0]; + + if (dgain > RK3308_DAC_L_HPOUT_GAIN_MAX) { + dev_err(rk3308->plat_dev, "%s: invalid l_dgain: %d\n", + __func__, dgain); + return -EINVAL; + } + + rk3308->hpout_l_dgain = dgain; + + return snd_soc_put_volsw_range(kcontrol, ucontrol); +} + +static int rk3308_codec_hpout_r_get_tlv(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return snd_soc_get_volsw_range(kcontrol, ucontrol); +} + +static int rk3308_codec_hpout_r_put_tlv(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + unsigned int dgain = ucontrol->value.integer.value[0]; + + if (dgain > RK3308_DAC_R_HPOUT_GAIN_MAX) { + dev_err(rk3308->plat_dev, "%s: invalid r_dgain: %d\n", + __func__, dgain); + return -EINVAL; + } + + rk3308->hpout_r_dgain = dgain; + + return snd_soc_put_volsw_range(kcontrol, ucontrol); +} + +static u32 to_mapped_grp(struct rk3308_codec_priv *rk3308, int idx) +{ + return rk3308->i2s_sdis[idx]; +} + +static bool adc_for_each_grp(struct rk3308_codec_priv *rk3308, + int type, int idx, u32 *grp) +{ + if (type == ADC_TYPE_NORMAL) { + u32 mapped_grp = to_mapped_grp(rk3308, idx); + int max_grps; + + if (rk3308->enable_all_adcs) + max_grps = ADC_LR_GROUP_MAX; + else + max_grps = rk3308->used_adc_grps; + + if (idx >= max_grps) + return false; + + if ((!rk3308->loopback_dacs_enabled) && + handle_loopback(rk3308) && + rk3308->loopback_grp == mapped_grp) { + /* + * Ths loopback DACs are closed, and specify the + * loopback ADCs. + */ + *grp = ADC_GRP_SKIP_MAGIC; + } else if (rk3308->en_always_grps_num && + rk3308->skip_grps[mapped_grp]) { + /* To set the skip flag if the ADC GRP is enabled. */ + *grp = ADC_GRP_SKIP_MAGIC; + } else { + *grp = mapped_grp; + } + + dev_dbg(rk3308->plat_dev, + "ADC_TYPE_NORMAL, idx: %d, mapped_grp: %d, get grp: %d,\n", + idx, mapped_grp, *grp); + } else if (type == ADC_TYPE_ALL) { + if (idx >= ADC_LR_GROUP_MAX) + return false; + + *grp = idx; + dev_dbg(rk3308->plat_dev, + "ADC_TYPE_ALL, idx: %d, get grp: %d\n", + idx, *grp); + } else if (type == ADC_TYPE_DBG) { + if (idx >= ADC_LR_GROUP_MAX) + return false; + + if (idx == (int)rk3308->cur_dbg_grp) + *grp = idx; + else + *grp = ADC_GRP_SKIP_MAGIC; + + dev_dbg(rk3308->plat_dev, + "ADC_TYPE_DBG, idx: %d, get grp: %d\n", + idx, *grp); + } else { + if (idx >= 1) + return false; + + *grp = rk3308->loopback_grp; + dev_dbg(rk3308->plat_dev, + "ADC_TYPE_LOOPBACK, idx: %d, get grp: %d\n", + idx, *grp); + } + + return true; +} + +static int rk3308_codec_get_dac_path_state(struct rk3308_codec_priv *rk3308) +{ + return rk3308->dac_path_state; +} + +static void rk3308_codec_set_dac_path_state(struct rk3308_codec_priv *rk3308, + int state) +{ + rk3308->dac_path_state = state; +} + +static void rk3308_headphone_ctl(struct rk3308_codec_priv *rk3308, int on) +{ + if (rk3308->hp_ctl_gpio) + gpiod_direction_output(rk3308->hp_ctl_gpio, on); +} + +static void rk3308_speaker_ctl(struct rk3308_codec_priv *rk3308, int on) +{ + if (on) { + if (rk3308->pa_drv_gpio) { + gpiod_direction_output(rk3308->pa_drv_gpio, on); + msleep(rk3308->delay_pa_drv_ms); + } + + if (rk3308->spk_ctl_gpio) + gpiod_direction_output(rk3308->spk_ctl_gpio, on); + } else { + if (rk3308->spk_ctl_gpio) + gpiod_direction_output(rk3308->spk_ctl_gpio, on); + + if (rk3308->pa_drv_gpio) { + msleep(rk3308->delay_pa_drv_ms); + gpiod_direction_output(rk3308->pa_drv_gpio, on); + } + } +} + +static int rk3308_codec_reset(struct snd_soc_component *component) +{ + struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + + reset_control_assert(rk3308->reset); + usleep_range(2000, 2500); /* estimated value */ + reset_control_deassert(rk3308->reset); + + regmap_write(rk3308->regmap, RK3308_GLB_CON, 0x00); + usleep_range(200, 300); /* estimated value */ + regmap_write(rk3308->regmap, RK3308_GLB_CON, + RK3308_SYS_WORK | + RK3308_DAC_DIG_WORK | + RK3308_ADC_DIG_WORK); + + return 0; +} + +static int rk3308_codec_adc_dig_reset(struct rk3308_codec_priv *rk3308) +{ + regmap_update_bits(rk3308->regmap, RK3308_GLB_CON, + RK3308_ADC_DIG_WORK, + RK3308_ADC_DIG_RESET); + udelay(50); + regmap_update_bits(rk3308->regmap, RK3308_GLB_CON, + RK3308_ADC_DIG_WORK, + RK3308_ADC_DIG_WORK); + + return 0; +} + +static int rk3308_codec_dac_dig_reset(struct rk3308_codec_priv *rk3308) +{ + regmap_update_bits(rk3308->regmap, RK3308_GLB_CON, + RK3308_DAC_DIG_WORK, + RK3308_DAC_DIG_RESET); + udelay(50); + regmap_update_bits(rk3308->regmap, RK3308_GLB_CON, + RK3308_DAC_DIG_WORK, + RK3308_DAC_DIG_WORK); + + return 0; +} + +static int rk3308_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + struct rk3308_codec_priv *rk3308 = 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(rk3308->regmap, false); + regcache_sync(rk3308->regmap); + break; + case SND_SOC_BIAS_OFF: + break; + } + + return 0; +} + +static int rk3308_set_dai_fmt(struct snd_soc_dai *dai, + unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + unsigned int adc_aif1 = 0, adc_aif2 = 0, dac_aif1 = 0, dac_aif2 = 0; + int idx, grp, is_master; + int type = ADC_TYPE_ALL; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + adc_aif2 |= RK3308_ADC_IO_MODE_SLAVE; + adc_aif2 |= RK3308_ADC_MODE_SLAVE; + dac_aif2 |= RK3308_DAC_IO_MODE_SLAVE; + dac_aif2 |= RK3308_DAC_MODE_SLAVE; + is_master = 0; + break; + case SND_SOC_DAIFMT_CBM_CFM: + adc_aif2 |= RK3308_ADC_IO_MODE_MASTER; + adc_aif2 |= RK3308_ADC_MODE_MASTER; + dac_aif2 |= RK3308_DAC_IO_MODE_MASTER; + dac_aif2 |= RK3308_DAC_MODE_MASTER; + is_master = 1; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + adc_aif1 |= RK3308_ADC_I2S_MODE_PCM; + dac_aif1 |= RK3308_DAC_I2S_MODE_PCM; + break; + case SND_SOC_DAIFMT_I2S: + adc_aif1 |= RK3308_ADC_I2S_MODE_I2S; + dac_aif1 |= RK3308_DAC_I2S_MODE_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + adc_aif1 |= RK3308_ADC_I2S_MODE_RJ; + dac_aif1 |= RK3308_DAC_I2S_MODE_RJ; + break; + case SND_SOC_DAIFMT_LEFT_J: + adc_aif1 |= RK3308_ADC_I2S_MODE_LJ; + dac_aif1 |= RK3308_DAC_I2S_MODE_LJ; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + adc_aif1 |= RK3308_ADC_I2S_LRC_POL_NORMAL; + adc_aif2 |= RK3308_ADC_I2S_BIT_CLK_POL_NORMAL; + dac_aif1 |= RK3308_DAC_I2S_LRC_POL_NORMAL; + dac_aif2 |= RK3308_DAC_I2S_BIT_CLK_POL_NORMAL; + break; + case SND_SOC_DAIFMT_IB_IF: + adc_aif1 |= RK3308_ADC_I2S_LRC_POL_REVERSAL; + adc_aif2 |= RK3308_ADC_I2S_BIT_CLK_POL_REVERSAL; + dac_aif1 |= RK3308_DAC_I2S_LRC_POL_REVERSAL; + dac_aif2 |= RK3308_DAC_I2S_BIT_CLK_POL_REVERSAL; + break; + case SND_SOC_DAIFMT_IB_NF: + adc_aif1 |= RK3308_ADC_I2S_LRC_POL_NORMAL; + adc_aif2 |= RK3308_ADC_I2S_BIT_CLK_POL_REVERSAL; + dac_aif1 |= RK3308_DAC_I2S_LRC_POL_NORMAL; + dac_aif2 |= RK3308_DAC_I2S_BIT_CLK_POL_REVERSAL; + break; + case SND_SOC_DAIFMT_NB_IF: + adc_aif1 |= RK3308_ADC_I2S_LRC_POL_REVERSAL; + adc_aif2 |= RK3308_ADC_I2S_BIT_CLK_POL_NORMAL; + dac_aif1 |= RK3308_DAC_I2S_LRC_POL_REVERSAL; + dac_aif2 |= RK3308_DAC_I2S_BIT_CLK_POL_NORMAL; + break; + default: + return -EINVAL; + } + + /* + * Hold ADC Digital registers start at master mode + * + * There are 8 ADCs and use the same SCLK and LRCK internal for master + * mode, We need to make sure that they are in effect at the same time, + * otherwise they will cause the abnormal clocks. + */ + if (is_master) + regmap_update_bits(rk3308->regmap, RK3308_GLB_CON, + RK3308_ADC_DIG_WORK, + RK3308_ADC_DIG_RESET); + + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON01(grp), + RK3308_ADC_I2S_LRC_POL_MSK | + RK3308_ADC_I2S_MODE_MSK, + adc_aif1); + regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON02(grp), + RK3308_ADC_IO_MODE_MSK | + RK3308_ADC_MODE_MSK | + RK3308_ADC_I2S_BIT_CLK_POL_MSK, + adc_aif2); + } + + /* Hold ADC Digital registers end at master mode */ + if (is_master) + regmap_update_bits(rk3308->regmap, RK3308_GLB_CON, + RK3308_ADC_DIG_WORK, + RK3308_ADC_DIG_WORK); + + regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON01, + RK3308_DAC_I2S_LRC_POL_MSK | + RK3308_DAC_I2S_MODE_MSK, + dac_aif1); + regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON02, + RK3308_DAC_IO_MODE_MSK | + RK3308_DAC_MODE_MSK | + RK3308_DAC_I2S_BIT_CLK_POL_MSK, + dac_aif2); + + return 0; +} + +static int rk3308_codec_dac_dig_config(struct rk3308_codec_priv *rk3308, + struct snd_pcm_hw_params *params) +{ + unsigned int dac_aif1 = 0, dac_aif2 = 0; + + /* Clear the status of DAC DIG Digital reigisters */ + rk3308_codec_dac_dig_reset(rk3308); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_16BITS; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_20BITS; + break; + case SNDRV_PCM_FORMAT_S24_LE: + dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_24BITS; + break; + case SNDRV_PCM_FORMAT_S32_LE: + dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_32BITS; + break; + default: + return -EINVAL; + } + + dac_aif1 |= RK3308_DAC_I2S_LR_NORMAL; + dac_aif2 |= RK3308_DAC_I2S_WORK; + + regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON01, + RK3308_DAC_I2S_VALID_LEN_MSK | + RK3308_DAC_I2S_LR_MSK, + dac_aif1); + regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON02, + RK3308_DAC_I2S_MSK, + dac_aif2); + + return 0; +} + +static int rk3308_codec_adc_dig_config(struct rk3308_codec_priv *rk3308, + struct snd_pcm_hw_params *params) +{ + unsigned int adc_aif1 = 0, adc_aif2 = 0; + int type = ADC_TYPE_NORMAL; + int idx, grp; + + /* Clear the status of ADC DIG Digital reigisters */ + rk3308_codec_adc_dig_reset(rk3308); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_16BITS; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_20BITS; + break; + case SNDRV_PCM_FORMAT_S24_LE: + adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_24BITS; + break; + case SNDRV_PCM_FORMAT_S32_LE: + adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_32BITS; + break; + default: + return -EINVAL; + } + + switch (params_channels(params)) { + case 1: + adc_aif1 |= RK3308_ADC_I2S_MONO; + break; + case 2: + case 4: + case 6: + case 8: + adc_aif1 |= RK3308_ADC_I2S_STEREO; + break; + default: + return -EINVAL; + } + + adc_aif1 |= RK3308_ADC_I2S_LR_NORMAL; + adc_aif2 |= RK3308_ADC_I2S_WORK; + + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON01(grp), + RK3308_ADC_I2S_VALID_LEN_MSK | + RK3308_ADC_I2S_LR_MSK | + RK3308_ADC_I2S_TYPE_MSK, + adc_aif1); + regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON02(grp), + RK3308_ADC_I2S_MSK, + adc_aif2); + } + + return 0; +} + +static int rk3308_codec_update_adc_grps(struct rk3308_codec_priv *rk3308, + struct snd_pcm_hw_params *params) +{ + switch (params_channels(params)) { + case 1: + rk3308->used_adc_grps = 1; + break; + case 2: + case 4: + case 6: + case 8: + rk3308->used_adc_grps = params_channels(params) / 2; + break; + default: + dev_err(rk3308->plat_dev, "Invalid channels: %d\n", + params_channels(params)); + return -EINVAL; + } + + return 0; +} + +static int rk3308_mute_stream(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_component *component = dai->component; + struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + int dgain; + + if (mute) { + for (dgain = 0x2; dgain <= 0x7; dgain++) { + /* + * Keep the max -> min digital CIC interpolation + * filter gain step by step. + * + * loud: 0x2; whisper: 0x7 + */ + regmap_update_bits(rk3308->regmap, + RK3308_DAC_DIG_CON04, + RK3308_DAC_CIC_IF_GAIN_MSK, + dgain); + usleep_range(200, 300); /* estimated value */ + } + +#if !DEBUG_POP_ALWAYS + rk3308_headphone_ctl(rk3308, 0); + rk3308_speaker_ctl(rk3308, 0); +#endif + } else { +#if !DEBUG_POP_ALWAYS + if (rk3308->dac_output == DAC_LINEOUT) + rk3308_speaker_ctl(rk3308, 1); + else if (rk3308->dac_output == DAC_HPOUT) + rk3308_headphone_ctl(rk3308, 1); + + if (rk3308->delay_start_play_ms) + msleep(rk3308->delay_start_play_ms); +#endif + for (dgain = 0x7; dgain >= 0x2; dgain--) { + /* + * Keep the min -> max digital CIC interpolation + * filter gain step by step + * + * loud: 0x2; whisper: 0x7 + */ + regmap_update_bits(rk3308->regmap, + RK3308_DAC_DIG_CON04, + RK3308_DAC_CIC_IF_GAIN_MSK, + dgain); + usleep_range(200, 300); /* estimated value */ + } + } + } + + return 0; +} + +static int rk3308_codec_digital_fadein(struct rk3308_codec_priv *rk3308) +{ + unsigned int dgain, dgain_ref; + + if (rk3308->hpout_l_dgain != rk3308->hpout_r_dgain) { + pr_warn("HPOUT l_dgain: 0x%x != r_dgain: 0x%x\n", + rk3308->hpout_l_dgain, rk3308->hpout_r_dgain); + dgain_ref = min(rk3308->hpout_l_dgain, rk3308->hpout_r_dgain); + } else { + dgain_ref = rk3308->hpout_l_dgain; + } + + /* + * We'd better change the gain of the left and right channels + * at the same time to avoid different listening + */ + for (dgain = RK3308_DAC_L_HPOUT_GAIN_NDB_39; + dgain <= dgain_ref; dgain++) { + /* Step 02 decrease dgains for de-pop */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON05, + RK3308_DAC_L_HPOUT_GAIN_MSK, + dgain); + + /* Step 02 decrease dgains for de-pop */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON06, + RK3308_DAC_R_HPOUT_GAIN_MSK, + dgain); + } + + return 0; +} + +static int rk3308_codec_digital_fadeout(struct rk3308_codec_priv *rk3308) +{ + unsigned int l_dgain, r_dgain; + + /* + * Note. In the step2, adjusting the register step by step to + * the appropriate value and taking 20ms as time step + */ + regmap_read(rk3308->regmap, RK3308_DAC_ANA_CON05, &l_dgain); + l_dgain &= RK3308_DAC_L_HPOUT_GAIN_MSK; + + regmap_read(rk3308->regmap, RK3308_DAC_ANA_CON06, &r_dgain); + r_dgain &= RK3308_DAC_R_HPOUT_GAIN_MSK; + + if (l_dgain != r_dgain) { + pr_warn("HPOUT l_dgain: 0x%x != r_dgain: 0x%x\n", + l_dgain, r_dgain); + l_dgain = min(l_dgain, r_dgain); + } + + /* + * We'd better change the gain of the left and right channels + * at the same time to avoid different listening + */ + while (l_dgain >= RK3308_DAC_L_HPOUT_GAIN_NDB_39) { + /* Step 02 decrease dgains for de-pop */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON05, + RK3308_DAC_L_HPOUT_GAIN_MSK, + l_dgain); + + /* Step 02 decrease dgains for de-pop */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON06, + RK3308_DAC_R_HPOUT_GAIN_MSK, + l_dgain); + + usleep_range(200, 300); /* estimated value */ + + if (l_dgain == RK3308_DAC_L_HPOUT_GAIN_NDB_39) + break; + + l_dgain--; + } + + return 0; +} + +static int rk3308_codec_dac_lineout_enable(struct rk3308_codec_priv *rk3308) +{ + if (rk3308->codec_ver == ACODEC_VERSION_B) { + /* Step 04 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON15, + RK3308_DAC_LINEOUT_POP_SOUND_L_MSK | + RK3308_DAC_LINEOUT_POP_SOUND_R_MSK, + RK3308_DAC_L_SEL_DC_FROM_INTERNAL | + RK3308_DAC_R_SEL_DC_FROM_INTERNAL); + } + + /* Step 07 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04, + RK3308_DAC_L_LINEOUT_EN | + RK3308_DAC_R_LINEOUT_EN, + RK3308_DAC_L_LINEOUT_EN | + RK3308_DAC_R_LINEOUT_EN); + + udelay(20); + + if (rk3308->codec_ver == ACODEC_VERSION_B) { + /* Step 10 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON15, + RK3308_DAC_LINEOUT_POP_SOUND_L_MSK | + RK3308_DAC_LINEOUT_POP_SOUND_R_MSK, + RK3308_DAC_L_SEL_LINEOUT_FROM_INTERNAL | + RK3308_DAC_R_SEL_LINEOUT_FROM_INTERNAL); + + udelay(20); + } + + /* Step 19 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04, + RK3308_DAC_L_LINEOUT_UNMUTE | + RK3308_DAC_R_LINEOUT_UNMUTE, + RK3308_DAC_L_LINEOUT_UNMUTE | + RK3308_DAC_R_LINEOUT_UNMUTE); + udelay(20); + + return 0; +} + +static int rk3308_codec_dac_lineout_disable(struct rk3308_codec_priv *rk3308) +{ + /* Step 08 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04, + RK3308_DAC_L_LINEOUT_UNMUTE | + RK3308_DAC_R_LINEOUT_UNMUTE, + RK3308_DAC_L_LINEOUT_MUTE | + RK3308_DAC_R_LINEOUT_MUTE); + + /* Step 09 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04, + RK3308_DAC_L_LINEOUT_EN | + RK3308_DAC_R_LINEOUT_EN, + RK3308_DAC_L_LINEOUT_DIS | + RK3308_DAC_R_LINEOUT_DIS); + + return 0; +} + +static int rk3308_codec_dac_hpout_enable(struct rk3308_codec_priv *rk3308) +{ + /* Step 03 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01, + RK3308_DAC_HPOUT_POP_SOUND_L_MSK | + RK3308_DAC_HPOUT_POP_SOUND_R_MSK, + RK3308_DAC_HPOUT_POP_SOUND_L_WORK | + RK3308_DAC_HPOUT_POP_SOUND_R_WORK); + + udelay(20); + + /* Step 07 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, + RK3308_DAC_L_HPOUT_EN | + RK3308_DAC_R_HPOUT_EN, + RK3308_DAC_L_HPOUT_EN | + RK3308_DAC_R_HPOUT_EN); + + udelay(20); + + /* Step 08 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, + RK3308_DAC_L_HPOUT_WORK | + RK3308_DAC_R_HPOUT_WORK, + RK3308_DAC_L_HPOUT_WORK | + RK3308_DAC_R_HPOUT_WORK); + + udelay(20); + + /* Step 16 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, + RK3308_DAC_L_HPOUT_UNMUTE | + RK3308_DAC_R_HPOUT_UNMUTE, + RK3308_DAC_L_HPOUT_UNMUTE | + RK3308_DAC_R_HPOUT_UNMUTE); + + udelay(20); + + return 0; +} + +static int rk3308_codec_dac_hpout_disable(struct rk3308_codec_priv *rk3308) +{ + /* Step 03 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01, + RK3308_DAC_HPOUT_POP_SOUND_L_MSK | + RK3308_DAC_HPOUT_POP_SOUND_R_MSK, + RK3308_DAC_HPOUT_POP_SOUND_L_INIT | + RK3308_DAC_HPOUT_POP_SOUND_R_INIT); + + /* Step 07 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, + RK3308_DAC_L_HPOUT_EN | + RK3308_DAC_R_HPOUT_EN, + RK3308_DAC_L_HPOUT_DIS | + RK3308_DAC_R_HPOUT_DIS); + + /* Step 08 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, + RK3308_DAC_L_HPOUT_WORK | + RK3308_DAC_R_HPOUT_WORK, + RK3308_DAC_L_HPOUT_INIT | + RK3308_DAC_R_HPOUT_INIT); + + /* Step 16 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, + RK3308_DAC_L_HPOUT_UNMUTE | + RK3308_DAC_R_HPOUT_UNMUTE, + RK3308_DAC_L_HPOUT_MUTE | + RK3308_DAC_R_HPOUT_MUTE); + + return 0; +} + +static int rk3308_codec_dac_switch(struct rk3308_codec_priv *rk3308, + int dac_output) +{ int ret = 0; + + if (rk3308->dac_output == dac_output) { + dev_info(rk3308->plat_dev, + "Don't need to change dac_output: %d\n", dac_output); + goto out; + } + + switch (dac_output) { + case DAC_LINEOUT: + case DAC_HPOUT: + case DAC_LINEOUT_HPOUT: + break; + default: + dev_err(rk3308->plat_dev, "Unknown value: %d\n", dac_output); + ret = -EINVAL; + goto out; + } + + if (rk3308_codec_get_dac_path_state(rk3308) == PATH_BUSY) { + /* + * We can only switch the audio path to LINEOUT or HPOUT on + * codec during playbacking, otherwise, just update the + * dac_output flag. + */ + switch (dac_output) { + case DAC_LINEOUT: + rk3308_headphone_ctl(rk3308, 0); + rk3308_speaker_ctl(rk3308, 1); + rk3308_codec_dac_hpout_disable(rk3308); + rk3308_codec_dac_lineout_enable(rk3308); + break; + case DAC_HPOUT: + rk3308_speaker_ctl(rk3308, 0); + rk3308_headphone_ctl(rk3308, 1); + rk3308_codec_dac_lineout_disable(rk3308); + rk3308_codec_dac_hpout_enable(rk3308); + break; + case DAC_LINEOUT_HPOUT: + rk3308_speaker_ctl(rk3308, 1); + rk3308_headphone_ctl(rk3308, 1); + rk3308_codec_dac_lineout_enable(rk3308); + rk3308_codec_dac_hpout_enable(rk3308); + break; + default: + break; + } + } + + rk3308->dac_output = dac_output; +out: + dev_dbg(rk3308->plat_dev, "switch dac_output to: %d\n", + rk3308->dac_output); + + return ret; +} + +static int rk3308_codec_dac_enable(struct rk3308_codec_priv *rk3308) +{ + /* + * Note1. If the ACODEC_DAC_ANA_CON12[6] or ACODEC_DAC_ANA_CON12[2] + * is set to 0x1, ignoring the step9~12. + */ + + /* + * Note2. If the ACODEC_ DAC_ANA_CON12[7] or ACODEC_DAC_ANA_CON12[3] + * is set to 0x1, the ADC0 or ADC1 should be enabled firstly, and + * please refer to Enable ADC Configuration Standard Usage Flow(expect + * step7~step9,step14). + */ + + /* + * Note3. If no opening the line out, ignoring the step6, step17 and + * step19. + */ + + /* + * Note4. If no opening the headphone out, ignoring the step3,step7~8, + * step16 and step18. + */ + + /* + * Note5. In the step18, adjust the register step by step to the + * appropriate value and taking 10ms as one time step + */ + + /* + * 1. Set the ACODEC_DAC_ANA_CON0[0] to 0x1, to enable the current + * source of DAC + */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON00, + RK3308_DAC_CURRENT_MSK, + RK3308_DAC_CURRENT_EN); + + udelay(20); + + /* + * 2. Set the ACODEC_DAC_ANA_CON1[6] and ACODEC_DAC_ANA_CON1[2] to 0x1, + * to enable the reference voltage buffer + */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01, + RK3308_DAC_BUF_REF_L_MSK | + RK3308_DAC_BUF_REF_R_MSK, + RK3308_DAC_BUF_REF_L_EN | + RK3308_DAC_BUF_REF_R_EN); + + /* Waiting the stable reference voltage */ + mdelay(1); + + if (rk3308->dac_output == DAC_HPOUT || + rk3308->dac_output == DAC_LINEOUT_HPOUT) { + /* Step 03 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01, + RK3308_DAC_HPOUT_POP_SOUND_L_MSK | + RK3308_DAC_HPOUT_POP_SOUND_R_MSK, + RK3308_DAC_HPOUT_POP_SOUND_L_WORK | + RK3308_DAC_HPOUT_POP_SOUND_R_WORK); + + udelay(20); + } + + if (rk3308->codec_ver == ACODEC_VERSION_B && + (rk3308->dac_output == DAC_LINEOUT || + rk3308->dac_output == DAC_LINEOUT_HPOUT)) { + /* Step 04 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON15, + RK3308_DAC_LINEOUT_POP_SOUND_L_MSK | + RK3308_DAC_LINEOUT_POP_SOUND_R_MSK, + RK3308_DAC_L_SEL_DC_FROM_INTERNAL | + RK3308_DAC_R_SEL_DC_FROM_INTERNAL); + + udelay(20); + } + + /* Step 05 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON13, + RK3308_DAC_L_HPMIX_EN | + RK3308_DAC_R_HPMIX_EN, + RK3308_DAC_L_HPMIX_EN | + RK3308_DAC_R_HPMIX_EN); + + /* Waiting the stable HPMIX */ + mdelay(1); + + /* Step 06. Reset HPMIX and recover HPMIX gains */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON13, + RK3308_DAC_L_HPMIX_WORK | + RK3308_DAC_R_HPMIX_WORK, + RK3308_DAC_L_HPMIX_INIT | + RK3308_DAC_R_HPMIX_INIT); + udelay(50); + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON13, + RK3308_DAC_L_HPMIX_WORK | + RK3308_DAC_R_HPMIX_WORK, + RK3308_DAC_L_HPMIX_WORK | + RK3308_DAC_R_HPMIX_WORK); + + udelay(20); + + if (rk3308->dac_output == DAC_LINEOUT || + rk3308->dac_output == DAC_LINEOUT_HPOUT) { + /* Step 07 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04, + RK3308_DAC_L_LINEOUT_EN | + RK3308_DAC_R_LINEOUT_EN, + RK3308_DAC_L_LINEOUT_EN | + RK3308_DAC_R_LINEOUT_EN); + + udelay(20); + } + + if (rk3308->dac_output == DAC_HPOUT || + rk3308->dac_output == DAC_LINEOUT_HPOUT) { + /* Step 08 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, + RK3308_DAC_L_HPOUT_EN | + RK3308_DAC_R_HPOUT_EN, + RK3308_DAC_L_HPOUT_EN | + RK3308_DAC_R_HPOUT_EN); + + udelay(20); + + /* Step 09 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, + RK3308_DAC_L_HPOUT_WORK | + RK3308_DAC_R_HPOUT_WORK, + RK3308_DAC_L_HPOUT_WORK | + RK3308_DAC_R_HPOUT_WORK); + + udelay(20); + } + + if (rk3308->codec_ver == ACODEC_VERSION_B) { + /* Step 10 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON15, + RK3308_DAC_LINEOUT_POP_SOUND_L_MSK | + RK3308_DAC_LINEOUT_POP_SOUND_R_MSK, + RK3308_DAC_L_SEL_LINEOUT_FROM_INTERNAL | + RK3308_DAC_R_SEL_LINEOUT_FROM_INTERNAL); + + udelay(20); + } + + /* Step 11 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON02, + RK3308_DAC_L_REF_EN | + RK3308_DAC_R_REF_EN, + RK3308_DAC_L_REF_EN | + RK3308_DAC_R_REF_EN); + + udelay(20); + + /* Step 12 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON02, + RK3308_DAC_L_CLK_EN | + RK3308_DAC_R_CLK_EN, + RK3308_DAC_L_CLK_EN | + RK3308_DAC_R_CLK_EN); + + udelay(20); + + /* Step 13 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON02, + RK3308_DAC_L_DAC_EN | + RK3308_DAC_R_DAC_EN, + RK3308_DAC_L_DAC_EN | + RK3308_DAC_R_DAC_EN); + + udelay(20); + + /* Step 14 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON02, + RK3308_DAC_L_DAC_WORK | + RK3308_DAC_R_DAC_WORK, + RK3308_DAC_L_DAC_WORK | + RK3308_DAC_R_DAC_WORK); + + udelay(20); + + /* Step 15 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON12, + RK3308_DAC_L_HPMIX_SEL_MSK | + RK3308_DAC_R_HPMIX_SEL_MSK, + RK3308_DAC_L_HPMIX_I2S | + RK3308_DAC_R_HPMIX_I2S); + + udelay(20); + + /* Step 16 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON13, + RK3308_DAC_L_HPMIX_UNMUTE | + RK3308_DAC_R_HPMIX_UNMUTE, + RK3308_DAC_L_HPMIX_UNMUTE | + RK3308_DAC_R_HPMIX_UNMUTE); + + udelay(20); + + /* Step 17: Put configuration HPMIX Gain to DAPM */ + + if (rk3308->dac_output == DAC_HPOUT || + rk3308->dac_output == DAC_LINEOUT_HPOUT) { + /* Step 18 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, + RK3308_DAC_L_HPOUT_UNMUTE | + RK3308_DAC_R_HPOUT_UNMUTE, + RK3308_DAC_L_HPOUT_UNMUTE | + RK3308_DAC_R_HPOUT_UNMUTE); + + udelay(20); + } + + if (rk3308->dac_output == DAC_LINEOUT || + rk3308->dac_output == DAC_LINEOUT_HPOUT) { + /* Step 19 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04, + RK3308_DAC_L_LINEOUT_UNMUTE | + RK3308_DAC_R_LINEOUT_UNMUTE, + RK3308_DAC_L_LINEOUT_UNMUTE | + RK3308_DAC_R_LINEOUT_UNMUTE); + udelay(20); + } + + /* Step 20, put configuration HPOUT gain to DAPM control */ + /* Step 21, put configuration LINEOUT gain to DAPM control */ + + if (rk3308->dac_output == DAC_HPOUT || + rk3308->dac_output == DAC_LINEOUT_HPOUT) { + /* Just for HPOUT */ + rk3308_codec_digital_fadein(rk3308); + } + + rk3308->dac_endisable = true; + + /* TODO: TRY TO TEST DRIVE STRENGTH */ + + return 0; +} + +static int rk3308_codec_dac_disable(struct rk3308_codec_priv *rk3308) +{ + /* + * Step 00 skipped. Keep the DAC channel work and input the mute signal. + */ + + /* Step 01 skipped. May set the min gain for LINEOUT. */ + + /* Step 02 skipped. May set the min gain for HPOUT. */ + + if (rk3308->dac_output == DAC_HPOUT || + rk3308->dac_output == DAC_LINEOUT_HPOUT) { + /* Just for HPOUT */ + rk3308_codec_digital_fadeout(rk3308); + } + + /* Step 03 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON13, + RK3308_DAC_L_HPMIX_UNMUTE | + RK3308_DAC_R_HPMIX_UNMUTE, + RK3308_DAC_L_HPMIX_UNMUTE | + RK3308_DAC_R_HPMIX_UNMUTE); + + /* Step 04 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON12, + RK3308_DAC_L_HPMIX_SEL_MSK | + RK3308_DAC_R_HPMIX_SEL_MSK, + RK3308_DAC_L_HPMIX_NONE | + RK3308_DAC_R_HPMIX_NONE); + /* Step 05 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, + RK3308_DAC_L_HPOUT_UNMUTE | + RK3308_DAC_R_HPOUT_UNMUTE, + RK3308_DAC_L_HPOUT_MUTE | + RK3308_DAC_R_HPOUT_MUTE); + + /* Step 06 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON02, + RK3308_DAC_L_DAC_WORK | + RK3308_DAC_R_DAC_WORK, + RK3308_DAC_L_DAC_INIT | + RK3308_DAC_R_DAC_INIT); + + /* Step 07 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, + RK3308_DAC_L_HPOUT_EN | + RK3308_DAC_R_HPOUT_EN, + RK3308_DAC_L_HPOUT_DIS | + RK3308_DAC_R_HPOUT_DIS); + + /* Step 08 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04, + RK3308_DAC_L_LINEOUT_UNMUTE | + RK3308_DAC_R_LINEOUT_UNMUTE, + RK3308_DAC_L_LINEOUT_MUTE | + RK3308_DAC_R_LINEOUT_MUTE); + + /* Step 09 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04, + RK3308_DAC_L_LINEOUT_EN | + RK3308_DAC_R_LINEOUT_EN, + RK3308_DAC_L_LINEOUT_DIS | + RK3308_DAC_R_LINEOUT_DIS); + + /* Step 10 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON13, + RK3308_DAC_L_HPMIX_EN | + RK3308_DAC_R_HPMIX_EN, + RK3308_DAC_L_HPMIX_DIS | + RK3308_DAC_R_HPMIX_DIS); + + /* Step 11 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON02, + RK3308_DAC_L_DAC_EN | + RK3308_DAC_R_DAC_EN, + RK3308_DAC_L_DAC_DIS | + RK3308_DAC_R_DAC_DIS); + + /* Step 12 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON02, + RK3308_DAC_L_CLK_EN | + RK3308_DAC_R_CLK_EN, + RK3308_DAC_L_CLK_DIS | + RK3308_DAC_R_CLK_DIS); + + /* Step 13 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON02, + RK3308_DAC_L_REF_EN | + RK3308_DAC_R_REF_EN, + RK3308_DAC_L_REF_DIS | + RK3308_DAC_R_REF_DIS); + + /* Step 14 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01, + RK3308_DAC_HPOUT_POP_SOUND_L_MSK | + RK3308_DAC_HPOUT_POP_SOUND_R_MSK, + RK3308_DAC_HPOUT_POP_SOUND_L_INIT | + RK3308_DAC_HPOUT_POP_SOUND_R_INIT); + + /* Step 15 */ + if (rk3308->codec_ver == ACODEC_VERSION_B && + (rk3308->dac_output == DAC_LINEOUT || + rk3308->dac_output == DAC_LINEOUT_HPOUT)) { + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON15, + RK3308_DAC_LINEOUT_POP_SOUND_L_MSK | + RK3308_DAC_LINEOUT_POP_SOUND_R_MSK, + RK3308_DAC_L_SEL_DC_FROM_VCM | + RK3308_DAC_R_SEL_DC_FROM_VCM); + } + + /* Step 16 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01, + RK3308_DAC_BUF_REF_L_EN | + RK3308_DAC_BUF_REF_R_EN, + RK3308_DAC_BUF_REF_L_DIS | + RK3308_DAC_BUF_REF_R_DIS); + + /* Step 17 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON00, + RK3308_DAC_CURRENT_EN, + RK3308_DAC_CURRENT_DIS); + + /* Step 18 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, + RK3308_DAC_L_HPOUT_WORK | + RK3308_DAC_R_HPOUT_WORK, + RK3308_DAC_L_HPOUT_INIT | + RK3308_DAC_R_HPOUT_INIT); + + /* Step 19 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON13, + RK3308_DAC_L_HPMIX_WORK | + RK3308_DAC_R_HPMIX_WORK, + RK3308_DAC_L_HPMIX_WORK | + RK3308_DAC_R_HPMIX_WORK); + + /* Step 20 skipped, may set the min gain for HPOUT. */ + + /* + * Note2. If the ACODEC_DAC_ANA_CON12[7] or ACODEC_DAC_ANA_CON12[3] + * is set to 0x1, add the steps from the section Disable ADC + * Configuration Standard Usage Flow after complete the step 19 + * + * IF USING LINE-IN + * rk3308_codec_adc_ana_disable(rk3308, type); + */ + + rk3308->dac_endisable = false; + + return 0; +} + +static int rk3308_codec_power_on(struct rk3308_codec_priv *rk3308) +{ + unsigned int v; + + /* 0. Supply the power of digital part and reset the Audio Codec */ + /* Do nothing */ + + /* + * 1. Configure ACODEC_DAC_ANA_CON1[1:0] and ACODEC_DAC_ANA_CON1[5:4] + * to 0x1, to setup dc voltage of the DAC channel output. + */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01, + RK3308_DAC_HPOUT_POP_SOUND_L_MSK, + RK3308_DAC_HPOUT_POP_SOUND_L_INIT); + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01, + RK3308_DAC_HPOUT_POP_SOUND_R_MSK, + RK3308_DAC_HPOUT_POP_SOUND_R_INIT); + + if (rk3308->codec_ver == ACODEC_VERSION_B) { + /* + * 2. Configure ACODEC_DAC_ANA_CON15[1:0] and + * ACODEC_DAC_ANA_CON15[5:4] to 0x1, to setup dc voltage of + * the DAC channel output. + */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON15, + RK3308_DAC_LINEOUT_POP_SOUND_L_MSK, + RK3308_DAC_L_SEL_DC_FROM_VCM); + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON15, + RK3308_DAC_LINEOUT_POP_SOUND_R_MSK, + RK3308_DAC_R_SEL_DC_FROM_VCM); + } + + /* + * 3. Configure the register ACODEC_ADC_ANA_CON10[3:0] to 7’b000_0001. + */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), + RK3308_ADC_CURRENT_CHARGE_MSK, + RK3308_ADC_SEL_I(0x1)); + + if (rk3308->codec_ver == ACODEC_VERSION_B) { + /* + * 4. Configure the register ACODEC_ADC_ANA_CON14[3:0] to + * 4’b0001. + */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON14, + RK3308_DAC_CURRENT_CHARGE_MSK, + RK3308_DAC_SEL_I(0x1)); + } + + /* 5. Supply the power of the analog part(AVDD,AVDDRV) */ + + /* + * 6. Configure the register ACODEC_ADC_ANA_CON10[7] to 0x1 to setup + * reference voltage + */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), + RK3308_ADC_REF_EN, RK3308_ADC_REF_EN); + + if (rk3308->codec_ver == ACODEC_VERSION_B) { + /* + * 7. Configure the register ACODEC_ADC_ANA_CON14[4] to 0x1 to + * setup reference voltage + */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON14, + RK3308_DAC_VCM_LINEOUT_EN, + RK3308_DAC_VCM_LINEOUT_EN); + } + + /* + * 8. Change the register ACODEC_ADC_ANA_CON10[6:0] from the 0x1 to + * 0x7f step by step or configure the ACODEC_ADC_ANA_CON10[6:0] to + * 0x7f directly. Here the slot time of the step is 200us. + */ + for (v = 0x1; v <= 0x7f; v++) { + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), + RK3308_ADC_CURRENT_CHARGE_MSK, + v); + udelay(200); + } + + if (rk3308->codec_ver == ACODEC_VERSION_B) { + /* + * 9. Change the register ACODEC_ADC_ANA_CON14[3:0] from the 0x1 + * to 0xf step by step or configure the + * ACODEC_ADC_ANA_CON14[3:0] to 0xf directly. Here the slot + * time of the step is 200us. + */ + for (v = 0x1; v <= 0xf; v++) { + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON14, + RK3308_DAC_CURRENT_CHARGE_MSK, + v); + udelay(200); + } + } + + /* 10. Wait until the voltage of VCM keeps stable at the AVDD/2 */ + msleep(20); /* estimated value */ + + /* + * 11. Configure the register ACODEC_ADC_ANA_CON10[6:0] to the + * appropriate value(expect 0x0) for reducing power. + */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), + RK3308_ADC_CURRENT_CHARGE_MSK, 0x7c); + + if (rk3308->codec_ver == ACODEC_VERSION_B) { + /* + * 12. Configure the register ACODEC_DAC_ANA_CON14[6:0] to the + * appropriate value(expect 0x0) for reducing power. + */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON14, + RK3308_DAC_CURRENT_CHARGE_MSK, 0xf); + } + + return 0; +} + +static int rk3308_codec_power_off(struct rk3308_codec_priv *rk3308) +{ + unsigned int v; + + /* + * 0. Keep the power on and disable the DAC and ADC path according to + * the section power on configuration standard usage flow. + */ + + /* + * 1. Configure the register ACODEC_ADC_ANA_CON10[6:0] to 7’b000_0001. + */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), + RK3308_ADC_CURRENT_CHARGE_MSK, + RK3308_ADC_SEL_I(0x1)); + + if (rk3308->codec_ver == ACODEC_VERSION_B) { + /* + * 2. Configure the register ACODEC_DAC_ANA_CON14[3:0] to + * 4’b0001. + */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON14, + RK3308_DAC_CURRENT_CHARGE_MSK, + RK3308_DAC_SEL_I(0x1)); + } + + /* 3. Configure the register ACODEC_ADC_ANA_CON10[7] to 0x0 */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), + RK3308_ADC_REF_EN, + RK3308_ADC_REF_DIS); + + if (rk3308->codec_ver == ACODEC_VERSION_B) { + /* 4. Configure the register ACODEC_DAC_ANA_CON14[7] to 0x0 */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON14, + RK3308_DAC_VCM_LINEOUT_EN, + RK3308_DAC_VCM_LINEOUT_DIS); + } + + /* + * 5. Change the register ACODEC_ADC_ANA_CON10[6:0] from the 0x1 to 0x7f + * step by step or configure the ACODEC_ADC_ANA_CON10[6:0] to 0x7f + * directly. Here the slot time of the step is 200us. + */ + for (v = 0x1; v <= 0x7f; v++) { + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), + RK3308_ADC_CURRENT_CHARGE_MSK, + v); + udelay(200); + } + + if (rk3308->codec_ver == ACODEC_VERSION_B) { + /* + * 6. Change the register ACODEC_DAC_ANA_CON14[3:0] from the 0x1 + * to 0xf step by step or configure the + * ACODEC_DAC_ANA_CON14[3:0] to 0xf directly. Here the slot + * time of the step is 200us. + */ + for (v = 0x1; v <= 0x7f; v++) { + regmap_update_bits(rk3308->regmap, + RK3308_ADC_ANA_CON10(0), + RK3308_ADC_CURRENT_CHARGE_MSK, + v); + udelay(200); + } + } + + /* 7. Wait until the voltage of VCM keeps stable at the AGND */ + msleep(20); /* estimated value */ + + /* 8. Power off the analog power supply */ + /* 9. Power off the digital power supply */ + + /* Do something via hardware */ + + return 0; +} + +static int rk3308_codec_headset_detect_enable(struct rk3308_codec_priv *rk3308) +{ + /* + * Set ACODEC_DAC_ANA_CON0[1] to 0x1, to enable the headset insert + * detection + * + * Note. When the voltage of PAD HPDET> 8*AVDD/9, the output value of + * the pin_hpdet will be set to 0x1 and assert a interrupt + */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON00, + RK3308_DAC_HEADPHONE_DET_MSK, + RK3308_DAC_HEADPHONE_DET_EN); + + return 0; +} + +static int rk3308_codec_headset_detect_disable(struct rk3308_codec_priv *rk3308) +{ + /* + * Set ACODEC_DAC_ANA_CON0[1] to 0x0, to disable the headset insert + * detection + */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON00, + RK3308_DAC_HEADPHONE_DET_MSK, + RK3308_DAC_HEADPHONE_DET_DIS); + + return 0; +} + +static int rk3308_codec_check_i2s_sdis(struct rk3308_codec_priv *rk3308, + int num) +{ + int i, j, ret = 0; + + switch (num) { + case 1: + rk3308->which_i2s = ACODEC_TO_I2S1_2CH; + break; + case 2: + rk3308->which_i2s = ACODEC_TO_I2S3_4CH; + break; + case 4: + rk3308->which_i2s = ACODEC_TO_I2S2_8CH; + break; + default: + dev_err(rk3308->plat_dev, "Invalid i2s sdis num: %d\n", num); + ret = -EINVAL; + goto err; + } + + for (i = 0; i < num; i++) { + if (rk3308->i2s_sdis[i] > ADC_LR_GROUP_MAX - 1) { + dev_err(rk3308->plat_dev, + "i2s_sdis[%d]: %d is overflow\n", + i, rk3308->i2s_sdis[i]); + ret = -EINVAL; + goto err; + } + + for (j = 0; j < num; j++) { + if (i == j) + continue; + + if (rk3308->i2s_sdis[i] == rk3308->i2s_sdis[j]) { + dev_err(rk3308->plat_dev, + "Invalid i2s_sdis: [%d]%d == [%d]%d\n", + i, rk3308->i2s_sdis[i], + j, rk3308->i2s_sdis[j]); + ret = -EINVAL; + goto err; + } + } + } + +err: + return ret; +} + +static int rk3308_codec_adc_grps_route_config(struct rk3308_codec_priv *rk3308) +{ + int idx = 0; + + if (rk3308->which_i2s == ACODEC_TO_I2S2_8CH) { + for (idx = 0; idx < rk3308->to_i2s_grps; idx++) { + regmap_write(rk3308->grf, GRF_SOC_CON1, + GRF_I2S2_8CH_SDI(idx, rk3308->i2s_sdis[idx])); + } + } else if (rk3308->which_i2s == ACODEC_TO_I2S3_4CH) { + for (idx = 0; idx < rk3308->to_i2s_grps; idx++) { + regmap_write(rk3308->grf, GRF_SOC_CON1, + GRF_I2S3_4CH_SDI(idx, rk3308->i2s_sdis[idx])); + } + } else if (rk3308->which_i2s == ACODEC_TO_I2S1_2CH) { + regmap_write(rk3308->grf, GRF_SOC_CON1, + GRF_I2S1_2CH_SDI(rk3308->i2s_sdis[idx])); + } + + return 0; +} + +/* Put default one-to-one mapping */ +static int rk3308_codec_adc_grps_route_default(struct rk3308_codec_priv *rk3308) +{ + unsigned int idx; + + /* + * The GRF values may be kept the previous status after hot reboot, + * if the property 'rockchip,adc-grps-route' is not set, we need to + * recover default the order of sdi/sdo for i2s2_8ch/i2s3_8ch/i2s1_2ch. + */ + regmap_write(rk3308->grf, GRF_SOC_CON1, + GRF_I2S1_2CH_SDI(0)); + + for (idx = 0; idx < 2; idx++) { + regmap_write(rk3308->grf, GRF_SOC_CON1, + GRF_I2S3_4CH_SDI(idx, idx)); + } + + /* Using i2s2_8ch by default. */ + rk3308->which_i2s = ACODEC_TO_I2S2_8CH; + rk3308->to_i2s_grps = ADC_LR_GROUP_MAX; + + for (idx = 0; idx < ADC_LR_GROUP_MAX; idx++) { + rk3308->i2s_sdis[idx] = idx; + regmap_write(rk3308->grf, GRF_SOC_CON1, + GRF_I2S2_8CH_SDI(idx, idx)); + } + + return 0; +} + +static int rk3308_codec_adc_grps_route(struct rk3308_codec_priv *rk3308, + struct device_node *np) +{ + int num, ret; + + num = of_count_phandle_with_args(np, "rockchip,adc-grps-route", NULL); + if (num < 0) { + if (num == -ENOENT) { + /* Not use 'rockchip,adc-grps-route' property here */ + rk3308_codec_adc_grps_route_default(rk3308); + ret = 0; + } else { + dev_err(rk3308->plat_dev, + "Failed to read 'rockchip,adc-grps-route' num: %d\n", + num); + ret = num; + } + return ret; + } + + ret = of_property_read_u32_array(np, "rockchip,adc-grps-route", + rk3308->i2s_sdis, num); + if (ret < 0) { + dev_err(rk3308->plat_dev, + "Failed to read 'rockchip,adc-grps-route': %d\n", + ret); + return ret; + } + + ret = rk3308_codec_check_i2s_sdis(rk3308, num); + if (ret < 0) { + dev_err(rk3308->plat_dev, + "Failed to check i2s_sdis: %d\n", ret); + return ret; + } + + rk3308->to_i2s_grps = num; + + rk3308_codec_adc_grps_route_config(rk3308); + + return 0; +} + +static int check_micbias(int micbias) +{ + switch (micbias) { + case RK3308_ADC_MICBIAS_VOLT_0_85: + case RK3308_ADC_MICBIAS_VOLT_0_8: + case RK3308_ADC_MICBIAS_VOLT_0_75: + case RK3308_ADC_MICBIAS_VOLT_0_7: + case RK3308_ADC_MICBIAS_VOLT_0_65: + case RK3308_ADC_MICBIAS_VOLT_0_6: + case RK3308_ADC_MICBIAS_VOLT_0_55: + case RK3308_ADC_MICBIAS_VOLT_0_5: + return 0; + } + + return -EINVAL; +} + +static bool handle_loopback(struct rk3308_codec_priv *rk3308) +{ + /* The version B doesn't need to handle loopback. */ + if (rk3308->codec_ver == ACODEC_VERSION_B) + return false; + + switch (rk3308->loopback_grp) { + case 0: + case 1: + case 2: + case 3: + return true; + } + + return false; +} + +static bool has_en_always_grps(struct rk3308_codec_priv *rk3308) +{ + int idx; + + if (rk3308->en_always_grps_num) { + for (idx = 0; idx < ADC_LR_GROUP_MAX; idx++) { + if (rk3308->en_always_grps[idx] >= 0 && + rk3308->en_always_grps[idx] <= ADC_LR_GROUP_MAX - 1) + return true; + } + } + + return false; +} + +static int rk3308_codec_micbias_enable(struct rk3308_codec_priv *rk3308, + int micbias) +{ + int ret; + + if (rk3308->ext_micbias != EXT_MICBIAS_NONE) + return 0; + + /* 0. Power up the ACODEC and keep the AVDDH stable */ + + /* Step 1. Configure ACODEC_ADC_ANA_CON7[2:0] to the certain value */ + ret = check_micbias(micbias); + if (ret < 0) { + dev_err(rk3308->plat_dev, "This is an invalid micbias: %d\n", + micbias); + return ret; + } + + /* + * Note: Only the reg (ADC_ANA_CON7+0x0)[2:0] represent the level range + * control signal of MICBIAS voltage + */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(0), + RK3308_ADC_LEVEL_RANGE_MICBIAS_MSK, + micbias); + + /* Step 2. Wait until the VCMH keep stable */ + msleep(20); /* estimated value */ + + /* + * Step 3. Configure ACODEC_ADC_ANA_CON8[4] to 0x1 + * + * Note: Only the reg (ADC_ANA_CON8+0x0)[4] represent the enable + * signal of current source for MICBIAS + */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON08(0), + RK3308_ADC_MICBIAS_CURRENT_MSK, + RK3308_ADC_MICBIAS_CURRENT_EN); + + /* + * Step 4. Configure the (ADC_ANA_CON7+0x40)[3] or + * (ADC_ANA_CON7+0x80)[3] to 0x1. + * + * (ADC_ANA_CON7+0x40)[3] used to control the MICBIAS1, and + * (ADC_ANA_CON7+0x80)[3] used to control the MICBIAS2 + */ + if (rk3308->micbias1) + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(1), + RK3308_ADC_MIC_BIAS_BUF_EN, + RK3308_ADC_MIC_BIAS_BUF_EN); + + if (rk3308->micbias2) + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(2), + RK3308_ADC_MIC_BIAS_BUF_EN, + RK3308_ADC_MIC_BIAS_BUF_EN); + + /* waiting micbias stabled*/ + mdelay(50); + + rk3308->enable_micbias = true; + + return 0; +} + +static int rk3308_codec_micbias_disable(struct rk3308_codec_priv *rk3308) +{ + if (rk3308->ext_micbias != EXT_MICBIAS_NONE) + return 0; + + /* Step 0. Enable the MICBIAS and keep the Audio Codec stable */ + /* Do nothing */ + + /* + * Step 1. Configure the (ADC_ANA_CON7+0x40)[3] or + * (ADC_ANA_CON7+0x80)[3] to 0x0 + */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(1), + RK3308_ADC_MIC_BIAS_BUF_EN, + RK3308_ADC_MIC_BIAS_BUF_DIS); + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(2), + RK3308_ADC_MIC_BIAS_BUF_EN, + RK3308_ADC_MIC_BIAS_BUF_DIS); + + /* + * Step 2. Configure ACODEC_ADC_ANA_CON8[4] to 0x0 + * + * Note: Only the reg (ADC_ANA_CON8+0x0)[4] represent the enable + * signal of current source for MICBIAS + */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON08(0), + RK3308_ADC_MICBIAS_CURRENT_MSK, + RK3308_ADC_MICBIAS_CURRENT_DIS); + + rk3308->enable_micbias = false; + + return 0; +} + +static int rk3308_codec_adc_reinit_mics(struct rk3308_codec_priv *rk3308, + int type) +{ + int idx, grp; + + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + /* vendor step 1 */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp), + RK3308_ADC_CH1_ADC_WORK | + RK3308_ADC_CH2_ADC_WORK, + RK3308_ADC_CH1_ADC_INIT | + RK3308_ADC_CH2_ADC_INIT); + } + + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + /* vendor step 2 */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp), + RK3308_ADC_CH1_ALC_WORK | + RK3308_ADC_CH2_ALC_WORK, + RK3308_ADC_CH1_ALC_INIT | + RK3308_ADC_CH2_ALC_INIT); + } + + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + /* vendor step 3 */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp), + RK3308_ADC_CH1_MIC_WORK | + RK3308_ADC_CH2_MIC_WORK, + RK3308_ADC_CH1_MIC_INIT | + RK3308_ADC_CH2_MIC_INIT); + } + + usleep_range(200, 250); /* estimated value */ + + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + /* vendor step 1 */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp), + RK3308_ADC_CH1_ADC_WORK | + RK3308_ADC_CH2_ADC_WORK, + RK3308_ADC_CH1_ADC_WORK | + RK3308_ADC_CH2_ADC_WORK); + } + + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + /* vendor step 2 */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp), + RK3308_ADC_CH1_ALC_WORK | + RK3308_ADC_CH2_ALC_WORK, + RK3308_ADC_CH1_ALC_WORK | + RK3308_ADC_CH2_ALC_WORK); + } + + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + /* vendor step 3 */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp), + RK3308_ADC_CH1_MIC_WORK | + RK3308_ADC_CH2_MIC_WORK, + RK3308_ADC_CH1_MIC_WORK | + RK3308_ADC_CH2_MIC_WORK); + } + + return 0; +} + +static int rk3308_codec_adc_ana_enable(struct rk3308_codec_priv *rk3308, + int type) +{ + unsigned int agc_func_en; + int idx, grp; + + /* + * 1. Set the ACODEC_ADC_ANA_CON7[7:6] and ACODEC_ADC_ANA_CON7[5:4], + * to select the line-in or microphone as input of ADC + * + * Note1. Please ignore the step1 for enabling ADC3, ADC4, ADC5, + * ADC6, ADC7, and ADC8 + */ + if (rk3308->adc_grp0_using_linein) { + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(0), + RK3308_ADC_CH1_IN_SEL_MSK | + RK3308_ADC_CH2_IN_SEL_MSK, + RK3308_ADC_CH1_IN_LINEIN | + RK3308_ADC_CH2_IN_LINEIN); + + /* Keep other ADCs as MIC-IN */ + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + /* The groups without line-in are >= 1 */ + if (grp < 1 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + regmap_update_bits(rk3308->regmap, + RK3308_ADC_ANA_CON07(grp), + RK3308_ADC_CH1_IN_SEL_MSK | + RK3308_ADC_CH2_IN_SEL_MSK, + RK3308_ADC_CH1_IN_MIC | + RK3308_ADC_CH2_IN_MIC); + } + } else { + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + regmap_update_bits(rk3308->regmap, + RK3308_ADC_ANA_CON07(grp), + RK3308_ADC_CH1_IN_SEL_MSK | + RK3308_ADC_CH2_IN_SEL_MSK, + RK3308_ADC_CH1_IN_MIC | + RK3308_ADC_CH2_IN_MIC); + } + } + + /* + * 2. Set ACODEC_ADC_ANA_CON0[7] and [3] to 0x1, to end the mute station + * of ADC, to enable the MIC module, to enable the reference voltage + * buffer, and to end the initialization of MIC + */ + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp), + RK3308_ADC_CH1_MIC_UNMUTE | + RK3308_ADC_CH2_MIC_UNMUTE, + RK3308_ADC_CH1_MIC_UNMUTE | + RK3308_ADC_CH2_MIC_UNMUTE); + } + + /* + * 3. Set ACODEC_ADC_ANA_CON6[0] to 0x1, to enable the current source + * of audio + */ + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON06(grp), + RK3308_ADC_CURRENT_MSK, + RK3308_ADC_CURRENT_EN); + } + + /* + * This is mainly used for BIST mode that wait ADCs are stable. + * + * By tested results, the type delay is >40us, but we need to leave + * enough delay margin. + */ + usleep_range(400, 500); + + /* vendor step 4*/ + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp), + RK3308_ADC_CH1_BUF_REF_EN | + RK3308_ADC_CH2_BUF_REF_EN, + RK3308_ADC_CH1_BUF_REF_EN | + RK3308_ADC_CH2_BUF_REF_EN); + } + + /* vendor step 5 */ + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp), + RK3308_ADC_CH1_MIC_EN | + RK3308_ADC_CH2_MIC_EN, + RK3308_ADC_CH1_MIC_EN | + RK3308_ADC_CH2_MIC_EN); + } + + /* vendor step 6 */ + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp), + RK3308_ADC_CH1_ALC_EN | + RK3308_ADC_CH2_ALC_EN, + RK3308_ADC_CH1_ALC_EN | + RK3308_ADC_CH2_ALC_EN); + } + + /* vendor step 7 */ + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp), + RK3308_ADC_CH1_CLK_EN | + RK3308_ADC_CH2_CLK_EN, + RK3308_ADC_CH1_CLK_EN | + RK3308_ADC_CH2_CLK_EN); + } + + /* vendor step 8 */ + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp), + RK3308_ADC_CH1_ADC_EN | + RK3308_ADC_CH2_ADC_EN, + RK3308_ADC_CH1_ADC_EN | + RK3308_ADC_CH2_ADC_EN); + } + + /* vendor step 9 */ + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp), + RK3308_ADC_CH1_ADC_WORK | + RK3308_ADC_CH2_ADC_WORK, + RK3308_ADC_CH1_ADC_WORK | + RK3308_ADC_CH2_ADC_WORK); + } + + /* vendor step 10 */ + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp), + RK3308_ADC_CH1_ALC_WORK | + RK3308_ADC_CH2_ALC_WORK, + RK3308_ADC_CH1_ALC_WORK | + RK3308_ADC_CH2_ALC_WORK); + } + + /* vendor step 11 */ + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp), + RK3308_ADC_CH1_MIC_WORK | + RK3308_ADC_CH2_MIC_WORK, + RK3308_ADC_CH1_MIC_WORK | + RK3308_ADC_CH2_MIC_WORK); + } + + /* vendor step 12 */ + + /* vendor step 13 */ + + /* vendor step 14 */ + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + regmap_read(rk3308->regmap, RK3308_ALC_L_DIG_CON09(grp), + &agc_func_en); + if (rk3308->adc_zerocross || + agc_func_en & RK3308_AGC_FUNC_SEL_EN) { + regmap_update_bits(rk3308->regmap, + RK3308_ADC_ANA_CON02(grp), + RK3308_ADC_CH1_ZEROCROSS_DET_EN, + RK3308_ADC_CH1_ZEROCROSS_DET_EN); + } + regmap_read(rk3308->regmap, RK3308_ALC_R_DIG_CON09(grp), + &agc_func_en); + if (rk3308->adc_zerocross || + agc_func_en & RK3308_AGC_FUNC_SEL_EN) { + regmap_update_bits(rk3308->regmap, + RK3308_ADC_ANA_CON02(grp), + RK3308_ADC_CH2_ZEROCROSS_DET_EN, + RK3308_ADC_CH2_ZEROCROSS_DET_EN); + } + } + + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + rk3308->adc_grps_endisable[grp] = true; + } + + return 0; +} + +static int rk3308_codec_adc_ana_disable(struct rk3308_codec_priv *rk3308, + int type) +{ + int idx, grp; + + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + /* vendor step 1 */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp), + RK3308_ADC_CH1_ZEROCROSS_DET_EN | + RK3308_ADC_CH2_ZEROCROSS_DET_EN, + RK3308_ADC_CH1_ZEROCROSS_DET_DIS | + RK3308_ADC_CH2_ZEROCROSS_DET_DIS); + } + + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + /* vendor step 2 */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp), + RK3308_ADC_CH1_ADC_EN | + RK3308_ADC_CH2_ADC_EN, + RK3308_ADC_CH1_ADC_DIS | + RK3308_ADC_CH2_ADC_DIS); + } + + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + /* vendor step 3 */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp), + RK3308_ADC_CH1_CLK_EN | + RK3308_ADC_CH2_CLK_EN, + RK3308_ADC_CH1_CLK_DIS | + RK3308_ADC_CH2_CLK_DIS); + } + + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + /* vendor step 4 */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp), + RK3308_ADC_CH1_ALC_EN | + RK3308_ADC_CH2_ALC_EN, + RK3308_ADC_CH1_ALC_DIS | + RK3308_ADC_CH2_ALC_DIS); + } + + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + /* vendor step 5 */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp), + RK3308_ADC_CH1_MIC_EN | + RK3308_ADC_CH2_MIC_EN, + RK3308_ADC_CH1_MIC_DIS | + RK3308_ADC_CH2_MIC_DIS); + } + + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + /* vendor step 6 */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp), + RK3308_ADC_CH1_BUF_REF_EN | + RK3308_ADC_CH2_BUF_REF_EN, + RK3308_ADC_CH1_BUF_REF_DIS | + RK3308_ADC_CH2_BUF_REF_DIS); + } + + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + /* vendor step 7 */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON06(grp), + RK3308_ADC_CURRENT_MSK, + RK3308_ADC_CURRENT_DIS); + } + + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + /* vendor step 8 */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp), + RK3308_ADC_CH1_ADC_WORK | + RK3308_ADC_CH2_ADC_WORK, + RK3308_ADC_CH1_ADC_INIT | + RK3308_ADC_CH2_ADC_INIT); + } + + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + /* vendor step 9 */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp), + RK3308_ADC_CH1_ALC_WORK | + RK3308_ADC_CH2_ALC_WORK, + RK3308_ADC_CH1_ALC_INIT | + RK3308_ADC_CH2_ALC_INIT); + } + + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + /* vendor step 10 */ + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp), + RK3308_ADC_CH1_MIC_WORK | + RK3308_ADC_CH2_MIC_WORK, + RK3308_ADC_CH1_MIC_INIT | + RK3308_ADC_CH2_MIC_INIT); + } + + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + rk3308->adc_grps_endisable[grp] = false; + } + + return 0; +} + +static int rk3308_codec_open_capture(struct rk3308_codec_priv *rk3308) +{ + int idx, grp = 0; + int type = ADC_TYPE_NORMAL; + + rk3308_codec_adc_ana_enable(rk3308, type); + rk3308_codec_adc_reinit_mics(rk3308, type); + + if (rk3308->adc_grp0_using_linein) { + regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON03(0), + RK3308_ADC_L_CH_BIST_MSK, + RK3308_ADC_L_CH_NORMAL_RIGHT); + regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON03(0), + RK3308_ADC_R_CH_BIST_MSK, + RK3308_ADC_R_CH_NORMAL_LEFT); + } else { + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (handle_loopback(rk3308) && + idx == rk3308->loopback_grp && + grp == ADC_GRP_SKIP_MAGIC) { + /* + * Switch to dummy BIST mode (BIST keep reset + * now) to keep the zero input data in I2S bus. + * + * It may cause the glitch if we hold the ADC + * digtital i2s module in codec. + * + * Then, the grp which is set from loopback_grp. + */ + regmap_update_bits(rk3308->regmap, + RK3308_ADC_DIG_CON03(rk3308->loopback_grp), + RK3308_ADC_L_CH_BIST_MSK, + RK3308_ADC_L_CH_BIST_SINE); + regmap_update_bits(rk3308->regmap, + RK3308_ADC_DIG_CON03(rk3308->loopback_grp), + RK3308_ADC_R_CH_BIST_MSK, + RK3308_ADC_R_CH_BIST_SINE); + } else { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + regmap_update_bits(rk3308->regmap, + RK3308_ADC_DIG_CON03(grp), + RK3308_ADC_L_CH_BIST_MSK, + RK3308_ADC_L_CH_NORMAL_LEFT); + regmap_update_bits(rk3308->regmap, + RK3308_ADC_DIG_CON03(grp), + RK3308_ADC_R_CH_BIST_MSK, + RK3308_ADC_R_CH_NORMAL_RIGHT); + } + } + } + + return 0; +} + +static void rk3308_codec_adc_mclk_disable(struct rk3308_codec_priv *rk3308) +{ + regmap_update_bits(rk3308->regmap, RK3308_GLB_CON, + RK3308_ADC_MCLK_MSK, + RK3308_ADC_MCLK_DIS); +} + +static void rk3308_codec_adc_mclk_enable(struct rk3308_codec_priv *rk3308) +{ + regmap_update_bits(rk3308->regmap, RK3308_GLB_CON, + RK3308_ADC_MCLK_MSK, + RK3308_ADC_MCLK_EN); + udelay(20); +} + +static void rk3308_codec_dac_mclk_disable(struct rk3308_codec_priv *rk3308) +{ + regmap_update_bits(rk3308->regmap, RK3308_GLB_CON, + RK3308_DAC_MCLK_MSK, + RK3308_DAC_MCLK_DIS); +} + +static void rk3308_codec_dac_mclk_enable(struct rk3308_codec_priv *rk3308) +{ + regmap_update_bits(rk3308->regmap, RK3308_GLB_CON, + RK3308_DAC_MCLK_MSK, + RK3308_DAC_MCLK_EN); + udelay(20); +} + +static int rk3308_codec_open_dbg_capture(struct rk3308_codec_priv *rk3308) +{ + rk3308_codec_adc_ana_enable(rk3308, ADC_TYPE_DBG); + + return 0; +} + +static int rk3308_codec_close_dbg_capture(struct rk3308_codec_priv *rk3308) +{ + rk3308_codec_adc_ana_disable(rk3308, ADC_TYPE_DBG); + + return 0; +} + +static int rk3308_codec_close_all_capture(struct rk3308_codec_priv *rk3308) +{ + rk3308_codec_adc_ana_disable(rk3308, ADC_TYPE_ALL); + + return 0; +} + +static int rk3308_codec_close_capture(struct rk3308_codec_priv *rk3308) +{ + rk3308_codec_adc_ana_disable(rk3308, ADC_TYPE_NORMAL); + + return 0; +} + +static int rk3308_codec_open_playback(struct rk3308_codec_priv *rk3308) +{ + rk3308_codec_dac_enable(rk3308); + + return 0; +} + +static int rk3308_codec_close_playback(struct rk3308_codec_priv *rk3308) +{ + rk3308_codec_dac_disable(rk3308); + + return 0; +} + +static int rk3308_codec_llp_down(struct rk3308_codec_priv *rk3308) +{ + rk3308_codec_adc_mclk_disable(rk3308); + rk3308_codec_dac_mclk_disable(rk3308); + + return 0; +} + +static int rk3308_codec_llp_up(struct rk3308_codec_priv *rk3308) +{ + rk3308_codec_adc_mclk_enable(rk3308); + rk3308_codec_dac_mclk_enable(rk3308); + + return 0; +} + +static int rk3308_codec_dlp_down(struct rk3308_codec_priv *rk3308) +{ + rk3308_codec_micbias_disable(rk3308); + rk3308_codec_power_off(rk3308); + + return 0; +} + +static int rk3308_codec_dlp_up(struct rk3308_codec_priv *rk3308) +{ + rk3308_codec_power_on(rk3308); + rk3308_codec_micbias_enable(rk3308, rk3308->micbias_volt); + + return 0; +} + +/* Just used for debug and trace power state */ +static void rk3308_codec_set_pm_state(struct rk3308_codec_priv *rk3308, + int pm_state) +{ + int ret; + + switch (pm_state) { + case PM_LLP_DOWN: + rk3308_codec_llp_down(rk3308); + break; + case PM_LLP_UP: + rk3308_codec_llp_up(rk3308); + break; + case PM_DLP_DOWN: + rk3308_codec_dlp_down(rk3308); + break; + case PM_DLP_UP: + rk3308_codec_dlp_up(rk3308); + break; + case PM_DLP_DOWN2: + clk_disable_unprepare(rk3308->mclk_rx); + clk_disable_unprepare(rk3308->mclk_tx); + clk_disable_unprepare(rk3308->pclk); + break; + case PM_DLP_UP2: + ret = clk_prepare_enable(rk3308->pclk); + if (ret < 0) { + dev_err(rk3308->plat_dev, + "Failed to enable acodec pclk: %d\n", ret); + goto err; + } + + ret = clk_prepare_enable(rk3308->mclk_rx); + if (ret < 0) { + dev_err(rk3308->plat_dev, + "Failed to enable i2s mclk_rx: %d\n", ret); + goto err; + } + + ret = clk_prepare_enable(rk3308->mclk_tx); + if (ret < 0) { + dev_err(rk3308->plat_dev, + "Failed to enable i2s mclk_tx: %d\n", ret); + goto err; + } + break; + default: + dev_err(rk3308->plat_dev, "Invalid pm_state: %d\n", pm_state); + goto err; + } + + rk3308->pm_state = pm_state; + +err: + return; +} + +static void rk3308_codec_update_adcs_status(struct rk3308_codec_priv *rk3308, + int state) +{ + int idx, grp; + + /* Update skip_grps flags if the ADCs need to be enabled always. */ + if (state == PATH_BUSY) { + for (idx = 0; idx < rk3308->used_adc_grps; idx++) { + u32 mapped_grp = to_mapped_grp(rk3308, idx); + + for (grp = 0; grp < rk3308->en_always_grps_num; grp++) { + u32 en_always_grp = rk3308->en_always_grps[grp]; + + if (mapped_grp == en_always_grp) + rk3308->skip_grps[en_always_grp] = 1; + } + } + } +} + +static int rk3308_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 rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + struct snd_pcm_str *playback_str = + &substream->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK]; + int type = ADC_TYPE_LOOPBACK; + int idx, grp; + int ret; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* DAC only supports 2 channels */ + rk3308_codec_dac_mclk_enable(rk3308); + rk3308_codec_open_playback(rk3308); + rk3308_codec_dac_dig_config(rk3308, params); + rk3308_codec_set_dac_path_state(rk3308, PATH_BUSY); + } else { + if (rk3308->micbias_num && + !rk3308->enable_micbias) + rk3308_codec_micbias_enable(rk3308, rk3308->micbias_volt); + + rk3308_codec_adc_mclk_enable(rk3308); + ret = rk3308_codec_update_adc_grps(rk3308, params); + if (ret < 0) + return ret; + + if (handle_loopback(rk3308)) { + if (rk3308->micbias_num && + (params_channels(params) == 2) && + to_mapped_grp(rk3308, 0) == rk3308->loopback_grp) + rk3308_codec_micbias_disable(rk3308); + + /* Check the DACs are opened */ + if (playback_str->substream_opened) { + rk3308->loopback_dacs_enabled = true; + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + regmap_update_bits(rk3308->regmap, + RK3308_ADC_DIG_CON03(grp), + RK3308_ADC_L_CH_BIST_MSK, + RK3308_ADC_L_CH_NORMAL_LEFT); + regmap_update_bits(rk3308->regmap, + RK3308_ADC_DIG_CON03(grp), + RK3308_ADC_R_CH_BIST_MSK, + RK3308_ADC_R_CH_NORMAL_RIGHT); + } + } else { + rk3308->loopback_dacs_enabled = false; + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + regmap_update_bits(rk3308->regmap, + RK3308_ADC_DIG_CON03(grp), + RK3308_ADC_L_CH_BIST_MSK, + RK3308_ADC_L_CH_BIST_SINE); + regmap_update_bits(rk3308->regmap, + RK3308_ADC_DIG_CON03(grp), + RK3308_ADC_R_CH_BIST_MSK, + RK3308_ADC_R_CH_BIST_SINE); + } + } + } + + rk3308_codec_open_capture(rk3308); + rk3308_codec_adc_dig_config(rk3308, params); + rk3308_codec_update_adcs_status(rk3308, PATH_BUSY); + } + + return 0; +} + +static int rk3308_pcm_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + int type = ADC_TYPE_LOOPBACK; + int idx, grp; + + if (handle_loopback(rk3308) && + rk3308->dac_output == DAC_LINEOUT && + substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (cmd == SNDRV_PCM_TRIGGER_START) { + struct snd_pcm_str *capture_str = + &substream->pcm->streams[SNDRV_PCM_STREAM_CAPTURE]; + + if (capture_str->substream_opened) + queue_delayed_work(system_power_efficient_wq, + &rk3308->loopback_work, + msecs_to_jiffies(rk3308->delay_loopback_handle_ms)); + } else if (cmd == SNDRV_PCM_TRIGGER_STOP) { + /* + * Switch to dummy bist mode to kick the glitch during disable + * ADCs and keep zero input data + */ + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + regmap_update_bits(rk3308->regmap, + RK3308_ADC_DIG_CON03(grp), + RK3308_ADC_L_CH_BIST_MSK, + RK3308_ADC_L_CH_BIST_SINE); + regmap_update_bits(rk3308->regmap, + RK3308_ADC_DIG_CON03(grp), + RK3308_ADC_R_CH_BIST_MSK, + RK3308_ADC_R_CH_BIST_SINE); + } + rk3308_codec_adc_ana_disable(rk3308, ADC_TYPE_LOOPBACK); + } + } + + return 0; +} + +static void rk3308_pcm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + rk3308_codec_close_playback(rk3308); + rk3308_codec_dac_mclk_disable(rk3308); + regcache_cache_only(rk3308->regmap, false); + regcache_sync(rk3308->regmap); + rk3308_codec_set_dac_path_state(rk3308, PATH_IDLE); + } else { + rk3308_codec_close_capture(rk3308); + if (!has_en_always_grps(rk3308)) { + rk3308_codec_adc_mclk_disable(rk3308); + rk3308_codec_update_adcs_status(rk3308, PATH_IDLE); + if (rk3308->micbias_num && + rk3308->enable_micbias) + rk3308_codec_micbias_disable(rk3308); + } + + regcache_cache_only(rk3308->regmap, false); + regcache_sync(rk3308->regmap); + } +} + +static struct snd_soc_dai_ops rk3308_dai_ops = { + .hw_params = rk3308_hw_params, + .set_fmt = rk3308_set_dai_fmt, + .mute_stream = rk3308_mute_stream, + .trigger = rk3308_pcm_trigger, + .shutdown = rk3308_pcm_shutdown, +}; + +static struct snd_soc_dai_driver rk3308_dai[] = { + { + .name = "rk3308-hifi", + .id = RK3308_HIFI, + .playback = { + .stream_name = "HiFi Playback", + .channels_min = 2, + .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 = 8, + .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 = &rk3308_dai_ops, + }, +}; + +static int rk3308_suspend(struct snd_soc_component *component) +{ + struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + + if (rk3308->no_deep_low_power) + goto out; + + rk3308_codec_dlp_down(rk3308); + clk_disable_unprepare(rk3308->mclk_rx); + clk_disable_unprepare(rk3308->mclk_tx); + clk_disable_unprepare(rk3308->pclk); + +out: + rk3308_set_bias_level(component, SND_SOC_BIAS_OFF); + return 0; +} + +static int rk3308_resume(struct snd_soc_component *component) +{ + struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + int ret = 0; + + if (rk3308->no_deep_low_power) + goto out; + + ret = clk_prepare_enable(rk3308->pclk); + if (ret < 0) { + dev_err(rk3308->plat_dev, + "Failed to enable acodec pclk: %d\n", ret); + goto out; + } + + ret = clk_prepare_enable(rk3308->mclk_rx); + if (ret < 0) { + dev_err(rk3308->plat_dev, + "Failed to enable i2s mclk_rx: %d\n", ret); + goto out; + } + + ret = clk_prepare_enable(rk3308->mclk_tx); + if (ret < 0) { + dev_err(rk3308->plat_dev, + "Failed to enable i2s mclk_tx: %d\n", ret); + goto out; + } + + rk3308_codec_dlp_up(rk3308); +out: + rk3308_set_bias_level(component, SND_SOC_BIAS_STANDBY); + return ret; +} + +static int rk3308_codec_default_gains(struct rk3308_codec_priv *rk3308) +{ + int grp; + + /* Prepare ADC gains */ + /* vendor step 12, set MIC PGA default gains */ + for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) { + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON01(grp), + RK3308_ADC_CH1_MIC_GAIN_MSK | + RK3308_ADC_CH2_MIC_GAIN_MSK, + RK3308_ADC_CH1_MIC_GAIN_0DB | + RK3308_ADC_CH2_MIC_GAIN_0DB); + } + + /* vendor step 13, set ALC default gains */ + for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) { + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON03(grp), + RK3308_ADC_CH1_ALC_GAIN_MSK, + RK3308_ADC_CH1_ALC_GAIN_0DB); + regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON04(grp), + RK3308_ADC_CH2_ALC_GAIN_MSK, + RK3308_ADC_CH2_ALC_GAIN_0DB); + } + + /* Prepare DAC gains */ + /* Step 15, set HPMIX default gains */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON12, + RK3308_DAC_L_HPMIX_GAIN_MSK | RK3308_DAC_R_HPMIX_GAIN_MSK, RK3308_DAC_L_HPMIX_GAIN_NDB_6 | RK3308_DAC_R_HPMIX_GAIN_NDB_6); - /* recover DAC digital gain to 0 dB (reset value is 0xff, undocumented) */ - if (rk3308->codec_ver == ACODEC_VERSION_C) - regmap_write(rk3308->regmap, RK3308_DAC_DIG_CON04, - RK3308BS_DAC_DIG_GAIN_0DB); + /* Step 18, set HPOUT default gains */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON05, + RK3308_DAC_L_HPOUT_GAIN_MSK, + RK3308_DAC_L_HPOUT_GAIN_NDB_39); + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON06, + RK3308_DAC_R_HPOUT_GAIN_MSK, + RK3308_DAC_R_HPOUT_GAIN_NDB_39); + + /* Using the same gain to HPOUT LR channels */ + rk3308->hpout_l_dgain = RK3308_DAC_L_HPOUT_GAIN_NDB_39; + + /* Step 19, set LINEOUT default gains */ + regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04, + RK3308_DAC_L_LINEOUT_GAIN_MSK | + RK3308_DAC_R_LINEOUT_GAIN_MSK, + RK3308_DAC_L_LINEOUT_GAIN_NDB_6 | + RK3308_DAC_R_LINEOUT_GAIN_NDB_6); + + return 0; +} + +static int rk3308_codec_setup_en_always_adcs(struct rk3308_codec_priv *rk3308, + struct device_node *np) +{ + int num, ret; + + num = of_count_phandle_with_args(np, "rockchip,en-always-grps", NULL); + if (num < 0) { + if (num == -ENOENT) { + /* + * If there is note use 'rockchip,en-always-grps' + * property, return 0 is also right. + */ + ret = 0; + } else { + dev_err(rk3308->plat_dev, + "Failed to read 'rockchip,adc-grps-route' num: %d\n", + num); + ret = num; + } + + rk3308->en_always_grps_num = 0; + return ret; + } + + rk3308->en_always_grps_num = num; + + ret = of_property_read_u32_array(np, "rockchip,en-always-grps", + rk3308->en_always_grps, num); + if (ret < 0) { + dev_err(rk3308->plat_dev, + "Failed to read 'rockchip,en-always-grps': %d\n", + ret); + return ret; + } + + /* Clear all of skip_grps flags. */ + for (num = 0; num < ADC_LR_GROUP_MAX; num++) + rk3308->skip_grps[num] = 0; + + /* The loopback grp should not be enabled always. */ + for (num = 0; num < rk3308->en_always_grps_num; num++) { + if (rk3308->en_always_grps[num] == rk3308->loopback_grp) { + dev_err(rk3308->plat_dev, + "loopback_grp: %d should not be enabled always!\n", + rk3308->loopback_grp); + ret = -EINVAL; + return ret; + } + } + + return 0; +} + +static int rk3308_codec_dapm_mic_gains(struct rk3308_codec_priv *rk3308) +{ + int ret; + + if (rk3308->codec_ver == ACODEC_VERSION_B) { + ret = snd_soc_add_component_controls(rk3308->component, + mic_gains_b, + ARRAY_SIZE(mic_gains_b)); + if (ret) { + dev_err(rk3308->plat_dev, + "%s: add mic_gains_b failed: %d\n", + __func__, ret); + return ret; + } + } else { + ret = snd_soc_add_component_controls(rk3308->component, + mic_gains_a, + ARRAY_SIZE(mic_gains_a)); + if (ret) { + dev_err(rk3308->plat_dev, + "%s: add mic_gains_a failed: %d\n", + __func__, ret); + return ret; + } + } + + return 0; +} + +static int rk3308_codec_check_micbias(struct rk3308_codec_priv *rk3308, + struct device_node *np) +{ + struct device *dev = (struct device *)rk3308->plat_dev; + int num = 0, ret; + + /* Check internal micbias */ + rk3308->micbias1 = + of_property_read_bool(np, "rockchip,micbias1"); + if (rk3308->micbias1) + num++; + + rk3308->micbias2 = + of_property_read_bool(np, "rockchip,micbias2"); + if (rk3308->micbias2) + num++; + + rk3308->micbias_volt = RK3308_ADC_MICBIAS_VOLT_0_85; /* by default */ + rk3308->micbias_num = num; + + /* Check external micbias */ + rk3308->ext_micbias = EXT_MICBIAS_NONE; + + rk3308->micbias_en_gpio = devm_gpiod_get_optional(dev, + "micbias-en", + GPIOD_IN); + if (!rk3308->micbias_en_gpio) { + dev_info(dev, "Don't need micbias-en gpio\n"); + } else if (IS_ERR(rk3308->micbias_en_gpio)) { + ret = PTR_ERR(rk3308->micbias_en_gpio); + dev_err(dev, "Unable to claim gpio micbias-en\n"); + return ret; + } else if (gpiod_get_value(rk3308->micbias_en_gpio)) { + rk3308->ext_micbias = EXT_MICBIAS_FUNC1; + } + + rk3308->vcc_micbias = devm_regulator_get_optional(dev, + "vmicbias"); + if (IS_ERR(rk3308->vcc_micbias)) { + if (PTR_ERR(rk3308->vcc_micbias) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_info(dev, "no vmicbias regulator found\n"); + } else { + ret = regulator_enable(rk3308->vcc_micbias); + if (ret) { + dev_err(dev, "Can't enable vmicbias: %d\n", ret); + return ret; + } + rk3308->ext_micbias = EXT_MICBIAS_FUNC2; + } + + dev_info(dev, "Check ext_micbias: %d\n", rk3308->ext_micbias); + + return 0; +} + +static int rk3308_codec_dapm_controls_prepare(struct rk3308_codec_priv *rk3308) +{ + int grp; + + for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) { + rk3308->hpf_cutoff[grp] = 0; + rk3308->agc_l[grp] = 0; + rk3308->agc_r[grp] = 0; + rk3308->agc_asr_l[grp] = AGC_ASR_96KHZ; + rk3308->agc_asr_r[grp] = AGC_ASR_96KHZ; + } + + rk3308_codec_dapm_mic_gains(rk3308); + + return 0; +} + +static int rk3308_codec_prepare(struct rk3308_codec_priv *rk3308) +{ + /* Clear registers for ADC and DAC */ + rk3308_codec_close_playback(rk3308); + rk3308_codec_close_all_capture(rk3308); + rk3308_codec_default_gains(rk3308); + rk3308_codec_llp_down(rk3308); + rk3308_codec_dapm_controls_prepare(rk3308); + + return 0; +} + +static int rk3308_probe(struct snd_soc_component *component) +{ + struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + int ext_micbias; + + rk3308->component = component; + rk3308_codec_set_dac_path_state(rk3308, PATH_IDLE); + + rk3308_codec_reset(component); + rk3308_codec_power_on(rk3308); + + /* From vendor recommend, disable micbias at first. */ + ext_micbias = rk3308->ext_micbias; + rk3308->ext_micbias = EXT_MICBIAS_NONE; + rk3308_codec_micbias_disable(rk3308); + rk3308->ext_micbias = ext_micbias; + + rk3308_codec_prepare(rk3308); + if (!rk3308->no_hp_det) + rk3308_codec_headset_detect_enable(rk3308); + + regcache_cache_only(rk3308->regmap, false); + regcache_sync(rk3308->regmap); + + return 0; +} + +static void rk3308_remove(struct snd_soc_component *component) +{ + struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + + rk3308_headphone_ctl(rk3308, 0); + rk3308_speaker_ctl(rk3308, 0); + if (!rk3308->no_hp_det) + rk3308_codec_headset_detect_disable(rk3308); + rk3308_codec_micbias_disable(rk3308); + rk3308_codec_power_off(rk3308); + + rk3308_codec_set_dac_path_state(rk3308, PATH_IDLE); + + regcache_cache_only(rk3308->regmap, false); + regcache_sync(rk3308->regmap); + + return; +} + +static const struct snd_soc_component_driver soc_codec_dev_rk3308_component = { + .probe = rk3308_probe, + .remove = rk3308_remove, + .resume = rk3308_resume, + .suspend = rk3308_suspend, + .set_bias_level = rk3308_set_bias_level, + .controls = rk3308_codec_dapm_controls, + .num_controls = ARRAY_SIZE(rk3308_codec_dapm_controls), + // .dapm_widgets = rk3308_dapm_widgets, + // .num_dapm_widgets = ARRAY_SIZE(rk3308_dapm_widgets), + // .dapm_routes = rk3308_dapm_routes, + // .num_dapm_routes = ARRAY_SIZE(rk3308_dapm_routes), + // .suspend_bias_off = 1, + // .idle_bias_on = 1, + // .use_pmdown_time = 1, + .endianness = 1, + .legacy_dai_naming = 1, +}; + +static const struct reg_default rk3308_codec_reg_defaults[] = { + { RK3308_GLB_CON, 0x07 }, +}; + +static bool rk3308_codec_write_read_reg(struct device *dev, unsigned int reg) +{ + /* All registers can be read / write */ + return true; +} + +static bool rk3308_codec_volatile_reg(struct device *dev, unsigned int reg) +{ + return true; +} + +static void rk3308_codec_hpdetect_work(struct work_struct *work) +{ + struct rk3308_codec_priv *rk3308 = + container_of(work, struct rk3308_codec_priv, hpdet_work.work); + unsigned int val; + int need_poll = 0, need_irq = 0; + int need_report = 0, report_type = 0; + int dac_output = DAC_LINEOUT; + + if (rk3308->codec_ver == ACODEC_VERSION_B) { + /* Check headphone plugged/unplugged directly. */ + regmap_read(rk3308->detect_grf, + DETECT_GRF_ACODEC_HPDET_STATUS, &val); + regmap_write(rk3308->detect_grf, + DETECT_GRF_ACODEC_HPDET_STATUS_CLR, val); + + if (rk3308->hp_jack_reversed) { + switch (val) { + case 0x0: + case 0x2: + dac_output = DAC_HPOUT; + report_type = SND_JACK_HEADPHONE; + break; + default: + break; + } + } else { + switch (val) { + case 0x1: + dac_output = DAC_HPOUT; + report_type = SND_JACK_HEADPHONE; + break; + default: + /* Includes val == 2 or others. */ + break; + } + } + + rk3308_codec_dac_switch(rk3308, dac_output); + if (rk3308->hpdet_jack) + snd_soc_jack_report(rk3308->hpdet_jack, + report_type, + SND_JACK_HEADPHONE); + + enable_irq(rk3308->irq); + + return; + } + + /* Check headphone unplugged via poll. */ + regmap_read(rk3308->regmap, RK3308_DAC_DIG_CON14, &val); + + if (rk3308->hp_jack_reversed) { + if (!val) { + rk3308->hp_plugged = true; + report_type = SND_JACK_HEADPHONE; + + need_report = 1; + need_irq = 1; + } else { + if (rk3308->hp_plugged) { + rk3308->hp_plugged = false; + need_report = 1; + } + need_poll = 1; + } + } else { + if (!val) { + rk3308->hp_plugged = false; + + need_report = 1; + need_irq = 1; + } else { + if (!rk3308->hp_plugged) { + rk3308->hp_plugged = true; + report_type = SND_JACK_HEADPHONE; + need_report = 1; + } + need_poll = 1; + } + } + + if (need_poll) + queue_delayed_work(system_power_efficient_wq, + &rk3308->hpdet_work, + msecs_to_jiffies(HPDET_POLL_MS)); + + if (need_report) { + if (report_type) + dac_output = DAC_HPOUT; + + rk3308_codec_dac_switch(rk3308, dac_output); + + if (rk3308->hpdet_jack) + snd_soc_jack_report(rk3308->hpdet_jack, + report_type, + SND_JACK_HEADPHONE); + } + + if (need_irq) + enable_irq(rk3308->irq); +} + +static void rk3308_codec_loopback_work(struct work_struct *work) +{ + struct rk3308_codec_priv *rk3308 = + container_of(work, struct rk3308_codec_priv, loopback_work.work); + int type = ADC_TYPE_LOOPBACK; + int idx, grp; + + /* Prepare loopback ADCs */ + rk3308_codec_adc_ana_enable(rk3308, type); + + /* Waiting ADCs are stable */ + msleep(ADC_STABLE_MS); + + /* Recover normal mode after enable ADCs */ + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { + if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) + continue; + + regmap_update_bits(rk3308->regmap, + RK3308_ADC_DIG_CON03(grp), + RK3308_ADC_L_CH_BIST_MSK, + RK3308_ADC_L_CH_NORMAL_LEFT); + regmap_update_bits(rk3308->regmap, + RK3308_ADC_DIG_CON03(grp), + RK3308_ADC_R_CH_BIST_MSK, + RK3308_ADC_R_CH_NORMAL_RIGHT); + } +} + +static irqreturn_t rk3308_codec_hpdet_isr(int irq, void *data) +{ + struct rk3308_codec_priv *rk3308 = data; + + /* + * For the high level irq trigger, disable irq and avoid a lot of + * repeated irq handlers entry. + */ + disable_irq_nosync(rk3308->irq); + queue_delayed_work(system_power_efficient_wq, + &rk3308->hpdet_work, msecs_to_jiffies(10)); + + return IRQ_HANDLED; +} + +void (*rk3308_codec_set_jack_detect_cb)(struct snd_soc_component *component, + struct snd_soc_jack *hpdet_jack); +EXPORT_SYMBOL_GPL(rk3308_codec_set_jack_detect_cb); + +static void rk3308_codec_set_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *hpdet_jack) +{ + struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + + rk3308->hpdet_jack = hpdet_jack; + + /* To detect jack once during startup */ + disable_irq_nosync(rk3308->irq); + queue_delayed_work(system_power_efficient_wq, + &rk3308->hpdet_work, msecs_to_jiffies(10)); + + dev_info(rk3308->plat_dev, "%s: Request detect hp jack once\n", + __func__); +} + +static const struct regmap_config rk3308_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = RK3308_DAC_ANA_CON15, + .writeable_reg = rk3308_codec_write_read_reg, + .readable_reg = rk3308_codec_write_read_reg, + .volatile_reg = rk3308_codec_volatile_reg, + .reg_defaults = rk3308_codec_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(rk3308_codec_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +static ssize_t pm_state_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rk3308_codec_priv *rk3308 = + container_of(dev, struct rk3308_codec_priv, dev); + + return sprintf(buf, "pm_state: %d\n", rk3308->pm_state); +} - /* - * Unconditionally enable zero-cross detection (needed for AGC, - * harmless without AGC) - */ - for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) - regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp), - RK3308_ADC_CH1_ZEROCROSS_DET_EN | - RK3308_ADC_CH2_ZEROCROSS_DET_EN); +static ssize_t pm_state_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rk3308_codec_priv *rk3308 = + container_of(dev, struct rk3308_codec_priv, dev); + unsigned long pm_state; + int ret = kstrtoul(buf, 10, &pm_state); - return 0; + if (ret < 0) { + dev_err(dev, "Invalid pm_state: %ld, ret: %d\n", + pm_state, ret); + return -EINVAL; + } + + rk3308_codec_set_pm_state(rk3308, pm_state); + + dev_info(dev, "Store pm_state: %d\n", rk3308->pm_state); + + return count; } -static int rk3308_codec_probe(struct snd_soc_component *component) +static ssize_t adc_grps_show(struct device *dev, + struct device_attribute *attr, + char *buf) { - struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + struct rk3308_codec_priv *rk3308 = + container_of(dev, struct rk3308_codec_priv, dev); + u32 grp; + int type = ADC_TYPE_NORMAL, count = 0; + int idx; - rk3308->component = component; + count += sprintf(buf + count, "current used adc_grps:\n"); + count += sprintf(buf + count, "- normal:"); + for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) + count += sprintf(buf + count, " %d", grp); + count += sprintf(buf + count, "\n"); + count += sprintf(buf + count, "- loopback: %d\n", + rk3308->loopback_grp); - rk3308_codec_reset(component); - rk3308_codec_initialize(rk3308); + return count; +} - return 0; +static ssize_t adc_grps_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rk3308_codec_priv *rk3308 = + container_of(dev, struct rk3308_codec_priv, dev); + char adc_type; + int grps, ret; + + ret = sscanf(buf, "%c,%d", &adc_type, &grps); + if (ret != 2) { + dev_err(rk3308->plat_dev, "%s sscanf failed: %d\n", + __func__, ret); + return -EFAULT; + } + + if (adc_type == 'n') + rk3308->used_adc_grps = grps; + else if (adc_type == 'l') + rk3308->loopback_grp = grps; + + return count; } -static int rk3308_codec_set_bias_level(struct snd_soc_component *component, - enum snd_soc_bias_level level) +static ssize_t adc_grps_route_show(struct device *dev, + struct device_attribute *attr, + char *buf) { - struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); + struct rk3308_codec_priv *rk3308 = + container_of(dev, struct rk3308_codec_priv, dev); + char which_i2s[32] = {0}; + int count = 0; + u32 grp; - switch (level) { - case SND_SOC_BIAS_ON: + switch (rk3308->which_i2s) { + case ACODEC_TO_I2S1_2CH: + strcpy(which_i2s, "i2s1_2ch"); break; - case SND_SOC_BIAS_PREPARE: + case ACODEC_TO_I2S3_4CH: + strcpy(which_i2s, "i2s3_4ch"); break; - case SND_SOC_BIAS_STANDBY: - if (snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_OFF) - break; + default: + strcpy(which_i2s, "i2s2_8ch"); + break; + } - /* Sequence from TRM Section 8.6.3 "Power Up" */ - regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON02, - RK3308_DAC_L_DAC_EN | RK3308_DAC_R_DAC_EN); - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), - RK3308_ADC_CURRENT_CHARGE_MSK, 1); - regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), - RK3308_ADC_REF_EN); - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), - RK3308_ADC_CURRENT_CHARGE_MSK, 0x7f); - msleep(20); /* estimated value */ + count += sprintf(buf + count, "%s from acodec route mapping:\n", + which_i2s); + for (grp = 0; grp < rk3308->to_i2s_grps; grp++) { + count += sprintf(buf + count, "* sdi_%d <-- sdo_%d\n", + grp, rk3308->i2s_sdis[grp]); + } + + return count; +} + +static ssize_t adc_grps_route_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rk3308_codec_priv *rk3308 = + container_of(dev, struct rk3308_codec_priv, dev); + int which_i2s, idx, i2s_sdis[ADC_LR_GROUP_MAX]; + int ret; + + ret = sscanf(buf, "%d,%d,%d,%d,%d", &which_i2s, + &i2s_sdis[0], &i2s_sdis[1], &i2s_sdis[2], &i2s_sdis[3]); + if (ret != 5) { + dev_err(rk3308->plat_dev, "%s sscanf failed: %d\n", + __func__, ret); + goto err; + } + + if (which_i2s < ACODEC_TO_I2S2_8CH || + which_i2s > ACODEC_TO_I2S1_2CH) { + dev_err(rk3308->plat_dev, "Invalid i2s type: %d\n", which_i2s); + goto err; + } + + rk3308->which_i2s = which_i2s; + + switch (rk3308->which_i2s) { + case ACODEC_TO_I2S1_2CH: + rk3308->to_i2s_grps = 1; break; - case SND_SOC_BIAS_OFF: - /* Sequence from TRM Section 8.6.4 "Power Down" */ - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), - RK3308_ADC_CURRENT_CHARGE_MSK, 1); - regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), - RK3308_ADC_REF_EN); - regmap_clear_bits(rk3308->regmap, RK3308_DAC_ANA_CON02, - RK3308_DAC_L_DAC_EN | RK3308_DAC_R_DAC_EN); - msleep(20); /* estimated value */ + case ACODEC_TO_I2S3_4CH: + rk3308->to_i2s_grps = 2; + break; + default: + rk3308->to_i2s_grps = 4; break; } - return 0; + + for (idx = 0; idx < rk3308->to_i2s_grps; idx++) + rk3308->i2s_sdis[idx] = i2s_sdis[idx]; + + rk3308_codec_adc_grps_route_config(rk3308); + +err: + return count; } -static const struct snd_soc_component_driver rk3308_codec_component_driver = { - .probe = rk3308_codec_probe, - .set_bias_level = rk3308_codec_set_bias_level, - .controls = rk3308_codec_controls, - .num_controls = ARRAY_SIZE(rk3308_codec_controls), - .dapm_widgets = rk3308_codec_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(rk3308_codec_dapm_widgets), - .dapm_routes = rk3308_codec_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(rk3308_codec_dapm_routes), -}; +static ssize_t adc_grp0_in_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rk3308_codec_priv *rk3308 = + container_of(dev, struct rk3308_codec_priv, dev); -static const struct regmap_config rk3308_codec_regmap_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .max_register = RK3308_DAC_ANA_CON15, -}; + return sprintf(buf, "adc ch0 using: %s\n", + rk3308->adc_grp0_using_linein ? "line in" : "mic in"); +} -static int rk3308_codec_get_version(struct rk3308_codec_priv *rk3308) +static ssize_t adc_grp0_in_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - unsigned int chip_id; - int err; + struct rk3308_codec_priv *rk3308 = + container_of(dev, struct rk3308_codec_priv, dev); + unsigned long using_linein; + int ret = kstrtoul(buf, 10, &using_linein); - err = regmap_read(rk3308->grf, GRF_CHIP_ID, &chip_id); - if (err) - return err; + if (ret < 0 || using_linein > 1) { + dev_err(dev, "Invalid input status: %ld, ret: %d\n", + using_linein, ret); + return -EINVAL; + } - switch (chip_id) { - case 3306: - rk3308->codec_ver = ACODEC_VERSION_A; + rk3308->adc_grp0_using_linein = using_linein; + + dev_info(dev, "store using_linein: %d\n", + rk3308->adc_grp0_using_linein); + + return count; +} + +static ssize_t adc_zerocross_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rk3308_codec_priv *rk3308 = + container_of(dev, struct rk3308_codec_priv, dev); + + return sprintf(buf, "adc zerocross: %s\n", + rk3308->adc_zerocross ? "enabled" : "disabled"); +} + +static ssize_t adc_zerocross_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rk3308_codec_priv *rk3308 = + container_of(dev, struct rk3308_codec_priv, dev); + unsigned long zerocross; + int ret = kstrtoul(buf, 10, &zerocross); + + if (ret < 0 || zerocross > 1) { + dev_err(dev, "Invalid zerocross: %ld, ret: %d\n", + zerocross, ret); + return -EINVAL; + } + + rk3308->adc_zerocross = zerocross; + + dev_info(dev, "store adc zerocross: %d\n", rk3308->adc_zerocross); + + return count; +} + +static ssize_t adc_grps_endisable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rk3308_codec_priv *rk3308 = + container_of(dev, struct rk3308_codec_priv, dev); + int count = 0, i; + + count += sprintf(buf + count, "enabled adc grps:"); + for (i = 0; i < ADC_LR_GROUP_MAX; i++) + count += sprintf(buf + count, "%d ", + rk3308->adc_grps_endisable[i]); + + count += sprintf(buf + count, "\n"); + return count; +} + +static ssize_t adc_grps_endisable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rk3308_codec_priv *rk3308 = + container_of(dev, struct rk3308_codec_priv, dev); + int grp, endisable, ret; + + ret = sscanf(buf, "%d,%d", &grp, &endisable); + if (ret != 2) { + dev_err(rk3308->plat_dev, "%s sscanf failed: %d\n", + __func__, ret); + return -EFAULT; + } + + rk3308->cur_dbg_grp = grp; + + if (endisable) + rk3308_codec_open_dbg_capture(rk3308); + else + rk3308_codec_close_dbg_capture(rk3308); + + dev_info(dev, "ADC grp %d endisable: %d\n", grp, endisable); + + return count; +} + +static ssize_t dac_endisable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rk3308_codec_priv *rk3308 = + container_of(dev, struct rk3308_codec_priv, dev); + + return sprintf(buf, "%d\n", rk3308->dac_endisable); +} + +static ssize_t dac_endisable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rk3308_codec_priv *rk3308 = + container_of(dev, struct rk3308_codec_priv, dev); + unsigned long endisable; + int ret = kstrtoul(buf, 10, &endisable); + + if (ret < 0) { + dev_err(dev, "Invalid endisable: %ld, ret: %d\n", + endisable, ret); + return -EINVAL; + } + + if (endisable) + rk3308_codec_open_playback(rk3308); + else + rk3308_codec_close_playback(rk3308); + + dev_info(dev, "DAC endisable: %ld\n", endisable); + + return count; +} + +static ssize_t dac_output_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rk3308_codec_priv *rk3308 = + container_of(dev, struct rk3308_codec_priv, dev); + ssize_t ret = 0; + + switch (rk3308->dac_output) { + case DAC_LINEOUT: + ret = sprintf(buf, "dac path: %s\n", "line out"); break; - case 0x3308: - rk3308->codec_ver = ACODEC_VERSION_B; - return dev_err_probe(rk3308->dev, -EINVAL, "Chip version B not supported\n"); - case 0x3308c: - rk3308->codec_ver = ACODEC_VERSION_C; + case DAC_HPOUT: + ret = sprintf(buf, "dac path: %s\n", "hp out"); + break; + case DAC_LINEOUT_HPOUT: + ret = sprintf(buf, "dac path: %s\n", + "both line out and hp out"); break; default: - return dev_err_probe(rk3308->dev, -EINVAL, "Unknown chip_id: 0x%x\n", chip_id); + pr_err("Invalid dac path: %d ?\n", rk3308->dac_output); + break; + } + + return ret; +} + +static ssize_t dac_output_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rk3308_codec_priv *rk3308 = + container_of(dev, struct rk3308_codec_priv, dev); + unsigned long dac_output; + int ret = kstrtoul(buf, 10, &dac_output); + + if (ret < 0) { + dev_err(dev, "Invalid input status: %ld, ret: %d\n", + dac_output, ret); + return -EINVAL; + } + + rk3308_codec_dac_switch(rk3308, dac_output); + + dev_info(dev, "Store dac_output: %d\n", rk3308->dac_output); + + return count; +} + +static ssize_t enable_all_adcs_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rk3308_codec_priv *rk3308 = + container_of(dev, struct rk3308_codec_priv, dev); + + return sprintf(buf, "%d\n", rk3308->enable_all_adcs); +} + +static ssize_t enable_all_adcs_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rk3308_codec_priv *rk3308 = + container_of(dev, struct rk3308_codec_priv, dev); + unsigned long enable; + int ret = kstrtoul(buf, 10, &enable); + + if (ret < 0) { + dev_err(dev, "Invalid enable value: %ld, ret: %d\n", + enable, ret); + return -EINVAL; + } + + rk3308->enable_all_adcs = enable; + + return count; +} + +static const struct device_attribute acodec_attrs[] = { + __ATTR_RW(adc_grps), + __ATTR_RW(adc_grps_endisable), + __ATTR_RW(adc_grps_route), + __ATTR_RW(adc_grp0_in), + __ATTR_RW(adc_zerocross), + __ATTR_RW(dac_endisable), + __ATTR_RW(dac_output), + __ATTR_RW(enable_all_adcs), + __ATTR_RW(pm_state), +}; + +static void rk3308_codec_device_release(struct device *dev) +{ + /* Do nothing */ +} + +static int rk3308_codec_sysfs_init(struct platform_device *pdev, + struct rk3308_codec_priv *rk3308) +{ + struct device *dev = &rk3308->dev; + int i; + + dev->release = rk3308_codec_device_release; + dev->parent = &pdev->dev; + set_dev_node(dev, dev_to_node(&pdev->dev)); + dev_set_name(dev, "rk3308-acodec-dev"); + + if (device_register(dev)) { + dev_err(&pdev->dev, + "Register 'rk3308-acodec-dev' 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 'rk3308-acodec-dev' attr failed\n"); + device_unregister(dev); + return -ENOMEM; + } } - dev_info(rk3308->dev, "Found codec version %c\n", rk3308->codec_ver); return 0; } -static int rk3308_codec_set_micbias_level(struct rk3308_codec_priv *rk3308) +#if defined(CONFIG_DEBUG_FS) +static int rk3308_codec_debugfs_reg_show(struct seq_file *s, void *v) { - struct device_node *np = rk3308->dev->of_node; - u32 percent; - u32 mult; - int err; + struct rk3308_codec_priv *rk3308 = s->private; + unsigned int i; + unsigned int val; - err = of_property_read_u32(np, "rockchip,micbias-avdd-percent", &percent); - if (err == -EINVAL) - return 0; - if (err) - return dev_err_probe(rk3308->dev, err, - "Error reading 'rockchip,micbias-avdd-percent'\n"); + for (i = RK3308_GLB_CON; i <= RK3308_DAC_ANA_CON13; i += 4) { + regmap_read(rk3308->regmap, i, &val); + if (!(i % 16)) + seq_printf(s, "\nR:%04x: ", i); + seq_printf(s, "%08x ", val); + } - /* Convert percent to register value, linerarly (50% -> 0, 5% step = +1) */ - mult = (percent - 50) / 5; + seq_puts(s, "\n"); - /* Check range and that the percent was an exact value allowed */ - if (mult > RK3308_ADC_LEVEL_RANGE_MICBIAS_MAX || mult * 5 + 50 != percent) - return dev_err_probe(rk3308->dev, -EINVAL, - "Invalid value %u for 'rockchip,micbias-avdd-percent'\n", - percent); + return 0; +} - regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(0), - RK3308_ADC_LEVEL_RANGE_MICBIAS_MSK, - mult << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT); +static ssize_t rk3308_codec_debugfs_reg_operate(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct rk3308_codec_priv *rk3308 = + ((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(rk3308->regmap, reg, val); + regcache_cache_only(rk3308->regmap, false); + regcache_sync(rk3308->regmap); + pr_info("Read back reg: 0x%04x with val: 0x%08x\n", reg, val); + } else if (op == 'r') { + regmap_read(rk3308->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 rk3308_codec_debugfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, + rk3308_codec_debugfs_reg_show, inode->i_private); +} + +static const struct file_operations rk3308_codec_reg_debugfs_fops = { + .owner = THIS_MODULE, + .open = rk3308_codec_debugfs_open, + .read = seq_read, + .write = rk3308_codec_debugfs_reg_operate, + .llseek = seq_lseek, + .release = single_release, +}; +#endif /* CONFIG_DEBUG_FS */ + +static int rk3308_codec_get_version(struct rk3308_codec_priv *rk3308) +{ + unsigned int chip_id; + + regmap_read(rk3308->grf, GRF_CHIP_ID, &chip_id); + switch (chip_id) { + case 3306: + rk3308->codec_ver = ACODEC_VERSION_A; + break; + case 0x3308: + rk3308->codec_ver = ACODEC_VERSION_B; + break; + default: + pr_err("Unknown chip_id: %d / 0x%x\n", chip_id, chip_id); + return -EFAULT; + } + + pr_info("The acodec version is: %x\n", rk3308->codec_ver); return 0; } -static int rk3308_codec_platform_probe(struct platform_device *pdev) +static int rk3308_platform_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct device *dev = &pdev->dev; struct rk3308_codec_priv *rk3308; + struct resource *res; void __iomem *base; - int err; + int ret; rk3308 = devm_kzalloc(&pdev->dev, sizeof(*rk3308), GFP_KERNEL); if (!rk3308) return -ENOMEM; - rk3308->dev = dev; - rk3308->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); - if (IS_ERR(rk3308->grf)) - return dev_err_probe(dev, PTR_ERR(rk3308->grf), "Error getting GRF\n"); + if (IS_ERR(rk3308->grf)) { + dev_err(&pdev->dev, + "Missing 'rockchip,grf' property\n"); + return PTR_ERR(rk3308->grf); + } + + ret = rk3308_codec_sysfs_init(pdev, rk3308); + if (ret < 0) { + dev_err(&pdev->dev, "Sysfs init failed\n"); + return ret; + } - rk3308->reset = devm_reset_control_get_optional_exclusive(dev, "codec"); - if (IS_ERR(rk3308->reset)) - return dev_err_probe(dev, PTR_ERR(rk3308->reset), "Failed to get reset control\n"); +#if defined(CONFIG_DEBUG_FS) + rk3308->dbg_codec = debugfs_create_dir(CODEC_DRV_NAME, NULL); + if (IS_ERR(rk3308->dbg_codec)) + dev_err(&pdev->dev, + "Failed to create debugfs dir for rk3308!\n"); + else + debugfs_create_file("reg", 0644, rk3308->dbg_codec, + rk3308, &rk3308_codec_reg_debugfs_fops); +#endif + rk3308->plat_dev = &pdev->dev; - err = devm_clk_bulk_get(dev, ARRAY_SIZE(rk3308_codec_clocks), rk3308_codec_clocks); - if (err) - return dev_err_probe(dev, err, "Failed to get clocks\n"); + rk3308->reset = devm_reset_control_get(&pdev->dev, "acodec-reset"); + if (IS_ERR(rk3308->reset)) { + ret = PTR_ERR(rk3308->reset); + if (ret != -ENOENT) + return ret; - err = clk_bulk_prepare_enable(ARRAY_SIZE(rk3308_codec_clocks), rk3308_codec_clocks); - if (err) - return dev_err_probe(dev, err, "Failed to enable clocks\n"); + dev_dbg(&pdev->dev, "No reset control found\n"); + rk3308->reset = NULL; + } + + rk3308->hp_ctl_gpio = devm_gpiod_get_optional(&pdev->dev, "hp-ctl", + GPIOD_OUT_LOW); + if (!rk3308->hp_ctl_gpio) { + dev_info(&pdev->dev, "Don't need hp-ctl gpio\n"); + } else if (IS_ERR(rk3308->hp_ctl_gpio)) { + ret = PTR_ERR(rk3308->hp_ctl_gpio); + dev_err(&pdev->dev, "Unable to claim gpio hp-ctl\n"); + return ret; + } + + rk3308->spk_ctl_gpio = devm_gpiod_get_optional(&pdev->dev, "spk-ctl", + GPIOD_OUT_LOW); + + if (!rk3308->spk_ctl_gpio) { + dev_info(&pdev->dev, "Don't need spk-ctl gpio\n"); + } else if (IS_ERR(rk3308->spk_ctl_gpio)) { + ret = PTR_ERR(rk3308->spk_ctl_gpio); + dev_err(&pdev->dev, "Unable to claim gpio spk-ctl\n"); + return ret; + } + + rk3308->pa_drv_gpio = devm_gpiod_get_optional(&pdev->dev, "pa-drv", + GPIOD_OUT_LOW); + + if (!rk3308->pa_drv_gpio) { + dev_info(&pdev->dev, "Don't need pa-drv gpio\n"); + } else if (IS_ERR(rk3308->pa_drv_gpio)) { + ret = PTR_ERR(rk3308->pa_drv_gpio); + dev_err(&pdev->dev, "Unable to claim gpio pa-drv\n"); + return ret; + } + + if (rk3308->pa_drv_gpio) { + rk3308->delay_pa_drv_ms = PA_DRV_MS; + ret = of_property_read_u32(np, "rockchip,delay-pa-drv-ms", + &rk3308->delay_pa_drv_ms); + } + +#if DEBUG_POP_ALWAYS + dev_info(&pdev->dev, "Enable all ctl gpios always for debugging pop\n"); + rk3308_headphone_ctl(rk3308, 1); + rk3308_speaker_ctl(rk3308, 1); +#else + dev_info(&pdev->dev, "De-pop as much as possible\n"); + rk3308_headphone_ctl(rk3308, 0); + rk3308_speaker_ctl(rk3308, 0); +#endif + + rk3308->pclk = devm_clk_get(&pdev->dev, "acodec"); + if (IS_ERR(rk3308->pclk)) { + dev_err(&pdev->dev, "Can't get acodec pclk\n"); + return PTR_ERR(rk3308->pclk); + } + + rk3308->mclk_rx = devm_clk_get(&pdev->dev, "mclk_rx"); + if (IS_ERR(rk3308->mclk_rx)) { + dev_err(&pdev->dev, "Can't get acodec mclk_rx\n"); + return PTR_ERR(rk3308->mclk_rx); + } + + rk3308->mclk_tx = devm_clk_get(&pdev->dev, "mclk_tx"); + if (IS_ERR(rk3308->mclk_tx)) { + dev_err(&pdev->dev, "Can't get acodec mclk_tx\n"); + return PTR_ERR(rk3308->mclk_tx); + } + + ret = clk_prepare_enable(rk3308->pclk); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to enable acodec pclk: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(rk3308->mclk_rx); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to enable i2s mclk_rx: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(rk3308->mclk_tx); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to enable i2s mclk_tx: %d\n", ret); + return ret; + } + + rk3308_codec_check_micbias(rk3308, np); + + rk3308->enable_all_adcs = + of_property_read_bool(np, "rockchip,enable-all-adcs"); + + rk3308->hp_jack_reversed = + of_property_read_bool(np, "rockchip,hp-jack-reversed"); + + rk3308->no_deep_low_power = + of_property_read_bool(np, "rockchip,no-deep-low-power"); + + rk3308->no_hp_det = + of_property_read_bool(np, "rockchip,no-hp-det"); + + rk3308->delay_loopback_handle_ms = LOOPBACK_HANDLE_MS; + ret = of_property_read_u32(np, "rockchip,delay-loopback-handle-ms", + &rk3308->delay_loopback_handle_ms); + + rk3308->delay_start_play_ms = 0; + ret = of_property_read_u32(np, "rockchip,delay-start-play-ms", + &rk3308->delay_start_play_ms); + + rk3308->loopback_grp = NOT_USED; + ret = of_property_read_u32(np, "rockchip,loopback-grp", + &rk3308->loopback_grp); + /* + * If there is no loopback on some board, the -EINVAL indicates that + * we don't need add the node, and it is not an error. + */ + if (ret < 0 && ret != -EINVAL) { + dev_err(&pdev->dev, "Failed to read loopback property: %d\n", + ret); + return ret; + } + + ret = rk3308_codec_adc_grps_route(rk3308, np); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to route ADC groups: %d\n", + ret); + return ret; + } + + ret = rk3308_codec_setup_en_always_adcs(rk3308, np); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to setup enabled always ADCs: %d\n", + ret); + return ret; + } + + ret = rk3308_codec_get_version(rk3308); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to get acodec version: %d\n", + ret); + return ret; + } + + 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; + } + + rk3308->regmap = devm_regmap_init_mmio(&pdev->dev, base, + &rk3308_codec_regmap_config); + if (IS_ERR(rk3308->regmap)) { + ret = PTR_ERR(rk3308->regmap); + dev_err(&pdev->dev, "Failed to regmap mmio\n"); + goto failed; + } + + if (!rk3308->no_hp_det) { + int index = 0; + + if (rk3308->codec_ver == ACODEC_VERSION_B) + index = 1; + + rk3308->irq = platform_get_irq(pdev, index); + if (rk3308->irq < 0) { + dev_err(&pdev->dev, "Can not get codec irq\n"); + goto failed; + } + + INIT_DELAYED_WORK(&rk3308->hpdet_work, rk3308_codec_hpdetect_work); + + ret = devm_request_irq(&pdev->dev, rk3308->irq, + rk3308_codec_hpdet_isr, + 0, + "acodec-hpdet", + rk3308); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request IRQ: %d\n", ret); + goto failed; + } - err = rk3308_codec_get_version(rk3308); - if (err) - return err; + if (rk3308->codec_ver == ACODEC_VERSION_B) { + rk3308->detect_grf = + syscon_regmap_lookup_by_phandle(np, "rockchip,detect-grf"); + if (IS_ERR(rk3308->detect_grf)) { + dev_err(&pdev->dev, + "Missing 'rockchip,detect-grf' property\n"); + return PTR_ERR(rk3308->detect_grf); + } + + /* Configure filter count and enable hpdet irq. */ + regmap_write(rk3308->detect_grf, + DETECT_GRF_ACODEC_HPDET_COUNTER, + DEFAULT_HPDET_COUNT); + regmap_write(rk3308->detect_grf, + DETECT_GRF_ACODEC_HPDET_CON, + (HPDET_BOTH_NEG_POS << 16) | + HPDET_BOTH_NEG_POS); + } + + rk3308_codec_set_jack_detect_cb = rk3308_codec_set_jack_detect; + } - base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) - return PTR_ERR(base); + if (rk3308->codec_ver == ACODEC_VERSION_A) + INIT_DELAYED_WORK(&rk3308->loopback_work, + rk3308_codec_loopback_work); - rk3308->regmap = devm_regmap_init_mmio(dev, base, &rk3308_codec_regmap_config); - if (IS_ERR(rk3308->regmap)) - return dev_err_probe(dev, PTR_ERR(rk3308->regmap), - "Failed to init regmap\n"); + rk3308->adc_grp0_using_linein = ADC_GRP0_MICIN; + rk3308->dac_output = DAC_LINEOUT; + rk3308->adc_zerocross = 1; + rk3308->pm_state = PM_NORMAL; platform_set_drvdata(pdev, rk3308); - err = rk3308_codec_set_micbias_level(rk3308); - if (err) - return err; + ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_rk3308_component, + rk3308_dai, ARRAY_SIZE(rk3308_dai)); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register component: %d\n", ret); + goto failed; + } - err = devm_snd_soc_register_component(dev, &rk3308_codec_component_driver, - &rk3308_codec_dai_driver, 1); - if (err) - return dev_err_probe(dev, err, "Failed to register codec\n"); + return ret; - return 0; +failed: + clk_disable_unprepare(rk3308->mclk_rx); + clk_disable_unprepare(rk3308->mclk_tx); + clk_disable_unprepare(rk3308->pclk); + device_unregister(&rk3308->dev); + + return ret; +} + +static void rk3308_platform_remove(struct platform_device *pdev) +{ + struct rk3308_codec_priv *rk3308 = + (struct rk3308_codec_priv *)platform_get_drvdata(pdev); + + clk_disable_unprepare(rk3308->mclk_rx); + clk_disable_unprepare(rk3308->mclk_tx); + clk_disable_unprepare(rk3308->pclk); + device_unregister(&rk3308->dev); + + return; } -static const struct of_device_id __maybe_unused rk3308_codec_of_match[] = { +static const struct of_device_id rk3308codec_of_match[] = { { .compatible = "rockchip,rk3308-codec", }, {}, }; -MODULE_DEVICE_TABLE(of, rk3308_codec_of_match); +MODULE_DEVICE_TABLE(of, rk3308codec_of_match); static struct platform_driver rk3308_codec_driver = { .driver = { - .name = "rk3308-acodec", - .of_match_table = rk3308_codec_of_match, + .name = CODEC_DRV_NAME, + .of_match_table = of_match_ptr(rk3308codec_of_match), }, - .probe = rk3308_codec_platform_probe, + .probe = rk3308_platform_probe, + .remove = rk3308_platform_remove, }; module_platform_driver(rk3308_codec_driver); MODULE_AUTHOR("Xing Zheng "); -MODULE_AUTHOR("Luca Ceresoli "); MODULE_DESCRIPTION("ASoC RK3308 Codec Driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rk3308_codec.h b/sound/soc/codecs/rk3308_codec.h index 111111111111..222222222222 100644 --- a/sound/soc/codecs/rk3308_codec.h +++ b/sound/soc/codecs/rk3308_codec.h @@ -1,15 +1,114 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ /* - * Rockchip RK3308 internal audio codec driver -- register definitions + * rk3308_codec.h -- RK3308 ALSA Soc Audio Driver * * Copyright (c) 2018, Fuzhou Rockchip Electronics Co., Ltd All rights reserved. - * Copyright (c) 2022, Vivax-Metrotech Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * */ #ifndef __RK3308_CODEC_H__ #define __RK3308_CODEC_H__ -#define RK3308_GLB_CON 0x00 +#define ACODEC_RESET_CTL 0x00 /* REG 0x00 */ + +/* ADC DIGITAL REGISTERS */ +#define ACODEC_ADC_I2S_CTL0 0x04 /* REG 0x01 */ +#define ACODEC_ADC_I2S_CTL1 0x08 /* REG 0x02 */ +#define ACODEC_ADC_BIST_MODE_SEL 0x0c /* REG 0x03 */ +#define ACODEC_ADC_HPF_PATH 0x10 /* REG 0x04 */ +/* Resevred REG 0x05 ~ 0x06 */ +#define ACODEC_ADC_DATA_PATH 0x1c /* REG 0x07 */ +/* Resevred REG 0x08 ~ 0x0f */ + +/* REG 0x10 ~ 0x1c are used to configure AGC of Left channel (ALC1) */ +#define ACODEC_ADC_PGA_AGC_L_CTL0 0x40 /* REG 0x10 */ +#define ACODEC_ADC_PGA_AGC_L_CTL1 0x44 /* REG 0x11 */ +#define ACODEC_ADC_PGA_AGC_L_CTL2 0x48 /* REG 0x12 */ +#define ACODEC_ADC_PGA_AGC_L_CTL3 0x4c /* REG 0x13 */ +#define ACODEC_ADC_PGA_AGC_L_CTL4 0x50 /* REG 0x14 */ +#define ACODEC_ADC_PGA_AGC_L_LO_MAX 0x54 /* REG 0x15 */ +#define ACODEC_ADC_PGA_AGC_L_HI_MAX 0x58 /* REG 0x16 */ +#define ACODEC_ADC_PGA_AGC_L_LO_MIN 0x5c /* REG 0x17 */ +#define ACODEC_ADC_PGA_AGC_L_HI_MIN 0x60 /* REG 0x18 */ +#define ACODEC_ADC_PGA_AGC_L_CTL5 0x64 /* REG 0x19 */ +/* Resevred REG 0x1a ~ 0x1b */ +#define ACODEC_ADC_AGC_L_RO_GAIN 0x70 /* REG 0x1c */ + +/* REG 0x20 ~ 0x2c are used to configure AGC of Right channel (ALC2) */ +#define ACODEC_ADC_PGA_AGC_R_CTL0 0x80 /* REG 0x20 */ +#define ACODEC_ADC_PGA_AGC_R_CTL1 0x84 /* REG 0x21 */ +#define ACODEC_ADC_PGA_AGC_R_CTL2 0x88 /* REG 0x22 */ +#define ACODEC_ADC_PGA_AGC_R_CTL3 0x8c /* REG 0x23 */ +#define ACODEC_ADC_PGA_AGC_R_CTL4 0x90 /* REG 0x24 */ +#define ACODEC_ADC_PGA_AGC_R_LO_MAX 0x94 /* REG 0x25 */ +#define ACODEC_ADC_PGA_AGC_R_HI_MAX 0x98 /* REG 0x26 */ +#define ACODEC_ADC_PGA_AGC_R_LO_MIN 0x9c /* REG 0x27 */ +#define ACODEC_ADC_PGA_AGC_R_HI_MIN 0xa0 /* REG 0x28 */ +#define ACODEC_ADC_PGA_AGC_R_CTL5 0xa4 /* REG 0x29 */ +/* Resevred REG 0x2a ~ 0x2b */ +#define ACODEC_ADC_AGC_R_RO_GAIN 0xb0 /* REG 0x2c */ + +/* DAC DIGITAL REGISTERS */ +#define ACODEC_DAC_I2S_CTL0 0x04 /* REG 0x01 */ +#define ACODEC_DAC_I2S_CTL1 0x08 /* REG 0x02 */ +#define ACODEC_DAC_BIST_MODE_SEL 0x0c /* REG 0x03 */ +#define ACODEC_DAC_DIGITAL_GAIN 0x10 /* REG 0x04 */ +#define ACODEC_DAC_DATA_SEL 0x14 /* REG 0x05 */ +/* Resevred REG 0x06 ~ 0x09 */ +#define ACODEC_DAC_DATA_HI 0x28 /* REG 0x0a */ +#define ACODEC_DAC_DATA_LO 0x2c /* REG 0x0b */ +/* Resevred REG 0x0c */ +#define ACODEC_DAC_HPDET_DELAYTIME 0x34 /* REG 0x0d */ +#define ACODEC_DAC_HPDET_STATUS 0x38 /* REG 0x0e, Read-only */ +/* Resevred REG 0x0f */ + +/* ADC ANALOG REGISTERS */ +#define ACODEC_ADC_ANA_MIC_CTL 0x00 /* REG 0x00 */ +#define ACODEC_ADC_ANA_MIC_GAIN 0x04 /* REG 0x01 */ +#define ACODEC_ADC_ANA_ALC_CTL 0x08 /* REG 0x02 */ +#define ACODEC_ADC_ANA_ALC_GAIN1 0x0c /* REG 0x03 */ +#define ACODEC_ADC_ANA_ALC_GAIN2 0x10 /* REG 0x04 */ +#define ACODEC_ADC_ANA_CTL0 0x14 /* REG 0x05 */ +#define ACODEC_ADC_ANA_CTL1 0x18 /* REG 0x06 */ +#define ACODEC_ADC_ANA_CTL2 0x1c /* REG 0x07 */ +#define ACODEC_ADC_ANA_CTL3 0x20 /* REG 0x08 */ +/* Resevred REG 0x09 */ +#define ACODEC_ADC_ANA_CTL4 0x28 /* REG 0x0a */ +#define ACODEC_ADC_ANA_ALC_PGA 0x2c /* REG 0x0b */ +/* Resevred REG 0x0c ~ 0x0f */ + +/* DAC ANALOG REGISTERS */ +#define ACODEC_DAC_ANA_CTL0 0x00 /* REG 0x00 */ +#define ACODEC_DAC_ANA_POP_VOLT 0x04 /* REG 0x01 */ +#define ACODEC_DAC_ANA_CTL1 0x08 /* REG 0x02 */ +#define ACODEC_DAC_ANA_HPOUT 0x0c /* REG 0x03 */ +#define ACODEC_DAC_ANA_LINEOUT 0x10 /* REG 0x04 */ +#define ACODEC_DAC_ANA_L_HPOUT_GAIN 0x14 /* REG 0x05 */ +#define ACODEC_DAC_ANA_R_HPOUT_GAIN 0x18 /* REG 0x06 */ +#define ACODEC_DAC_ANA_DRV_HPOUT 0x1c /* REG 0x07 */ +#define ACODEC_DAC_ANA_DRV_LINEOUT 0x20 /* REG 0x08 */ +/* Resevred REG 0x07 ~ 0x0b */ +#define ACODEC_DAC_ANA_HPMIX_CTL0 0x30 /* REG 0x0c */ +#define ACODEC_DAC_ANA_HPMIX_CTL1 0x34 /* REG 0x0d */ +#define ACODEC_DAC_ANA_LINEOUT_CTL0 0x38 /* REG 0x0e */ +#define ACODEC_DAC_ANA_LINEOUT_CTL1 0x3c /* REG 0x0f */ + +/* + * These registers are referenced by codec driver + */ + +#define RK3308_GLB_CON ACODEC_RESET_CTL /* ADC DIGITAL REGISTERS */ @@ -21,51 +120,50 @@ * CH2: left_2(ADC5) and right_2(ADC6) * CH3: left_3(ADC7) and right_3(ADC8) */ -#define RK3308_ADC_DIG_OFFSET(ch) (((ch) & 0x3) * 0xc0 + 0x0) - -#define RK3308_ADC_DIG_CON01(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x04) -#define RK3308_ADC_DIG_CON02(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x08) -#define RK3308_ADC_DIG_CON03(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x0c) -#define RK3308_ADC_DIG_CON04(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x10) -#define RK3308_ADC_DIG_CON05(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x14) // ver.C only -#define RK3308_ADC_DIG_CON06(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x18) // ver.C only -#define RK3308_ADC_DIG_CON07(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x1c) - -#define RK3308_ALC_L_DIG_CON00(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x40) -#define RK3308_ALC_L_DIG_CON01(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x44) -#define RK3308_ALC_L_DIG_CON02(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x48) -#define RK3308_ALC_L_DIG_CON03(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x4c) -#define RK3308_ALC_L_DIG_CON04(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x50) -#define RK3308_ALC_L_DIG_CON05(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x54) -#define RK3308_ALC_L_DIG_CON06(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x58) -#define RK3308_ALC_L_DIG_CON07(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x5c) -#define RK3308_ALC_L_DIG_CON08(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x60) -#define RK3308_ALC_L_DIG_CON09(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x64) -#define RK3308_ALC_L_DIG_CON12(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x70) - -#define RK3308_ALC_R_DIG_CON00(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x80) -#define RK3308_ALC_R_DIG_CON01(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x84) -#define RK3308_ALC_R_DIG_CON02(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x88) -#define RK3308_ALC_R_DIG_CON03(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x8c) -#define RK3308_ALC_R_DIG_CON04(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x90) -#define RK3308_ALC_R_DIG_CON05(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x94) -#define RK3308_ALC_R_DIG_CON06(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x98) -#define RK3308_ALC_R_DIG_CON07(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x9c) -#define RK3308_ALC_R_DIG_CON08(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0xa0) -#define RK3308_ALC_R_DIG_CON09(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0xa4) -#define RK3308_ALC_R_DIG_CON12(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0xb0) +#define RK3308_ADC_DIG_OFFSET(ch) ((ch & 0x3) * 0xc0 + 0x0) + +#define RK3308_ADC_DIG_CON01(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_I2S_CTL0) +#define RK3308_ADC_DIG_CON02(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_I2S_CTL1) +#define RK3308_ADC_DIG_CON03(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_BIST_MODE_SEL) +#define RK3308_ADC_DIG_CON04(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_HPF_PATH) +#define RK3308_ADC_DIG_CON07(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_DATA_PATH) + +#define RK3308_ALC_L_DIG_CON00(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_L_CTL0) +#define RK3308_ALC_L_DIG_CON01(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_L_CTL1) +#define RK3308_ALC_L_DIG_CON02(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_L_CTL2) +#define RK3308_ALC_L_DIG_CON03(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_L_CTL3) +#define RK3308_ALC_L_DIG_CON04(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_L_CTL4) +#define RK3308_ALC_L_DIG_CON05(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_L_LO_MAX) +#define RK3308_ALC_L_DIG_CON06(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_L_HI_MAX) +#define RK3308_ALC_L_DIG_CON07(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_L_LO_MIN) +#define RK3308_ALC_L_DIG_CON08(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_L_HI_MIN) +#define RK3308_ALC_L_DIG_CON09(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_L_CTL5) +#define RK3308_ALC_L_DIG_CON12(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_AGC_L_RO_GAIN) + +#define RK3308_ALC_R_DIG_CON00(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_R_CTL0) +#define RK3308_ALC_R_DIG_CON01(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_R_CTL1) +#define RK3308_ALC_R_DIG_CON02(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_R_CTL2) +#define RK3308_ALC_R_DIG_CON03(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_R_CTL3) +#define RK3308_ALC_R_DIG_CON04(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_R_CTL4) +#define RK3308_ALC_R_DIG_CON05(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_R_LO_MAX) +#define RK3308_ALC_R_DIG_CON06(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_R_HI_MAX) +#define RK3308_ALC_R_DIG_CON07(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_R_LO_MIN) +#define RK3308_ALC_R_DIG_CON08(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_R_HI_MIN) +#define RK3308_ALC_R_DIG_CON09(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_R_CTL5) +#define RK3308_ALC_R_DIG_CON12(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_AGC_R_RO_GAIN) /* DAC DIGITAL REGISTERS */ #define RK3308_DAC_DIG_OFFSET 0x300 -#define RK3308_DAC_DIG_CON01 (RK3308_DAC_DIG_OFFSET + 0x04) -#define RK3308_DAC_DIG_CON02 (RK3308_DAC_DIG_OFFSET + 0x08) -#define RK3308_DAC_DIG_CON03 (RK3308_DAC_DIG_OFFSET + 0x0c) -#define RK3308_DAC_DIG_CON04 (RK3308_DAC_DIG_OFFSET + 0x10) -#define RK3308_DAC_DIG_CON05 (RK3308_DAC_DIG_OFFSET + 0x14) -#define RK3308_DAC_DIG_CON10 (RK3308_DAC_DIG_OFFSET + 0x28) -#define RK3308_DAC_DIG_CON11 (RK3308_DAC_DIG_OFFSET + 0x2c) -#define RK3308_DAC_DIG_CON13 (RK3308_DAC_DIG_OFFSET + 0x34) -#define RK3308_DAC_DIG_CON14 (RK3308_DAC_DIG_OFFSET + 0x38) + +#define RK3308_DAC_DIG_CON01 (RK3308_DAC_DIG_OFFSET + ACODEC_DAC_I2S_CTL0) +#define RK3308_DAC_DIG_CON02 (RK3308_DAC_DIG_OFFSET + ACODEC_DAC_I2S_CTL1) +#define RK3308_DAC_DIG_CON03 (RK3308_DAC_DIG_OFFSET + ACODEC_DAC_BIST_MODE_SEL) +#define RK3308_DAC_DIG_CON04 (RK3308_DAC_DIG_OFFSET + ACODEC_DAC_DIGITAL_GAIN) +#define RK3308_DAC_DIG_CON05 (RK3308_DAC_DIG_OFFSET + ACODEC_DAC_DATA_SEL) +#define RK3308_DAC_DIG_CON10 (RK3308_DAC_DIG_OFFSET + ACODEC_DAC_DATA_HI) +#define RK3308_DAC_DIG_CON11 (RK3308_DAC_DIG_OFFSET + ACODEC_DAC_DATA_LO) +#define RK3308_DAC_DIG_CON13 (RK3308_DAC_DIG_OFFSET + ACODEC_DAC_HPDET_DELAYTIME) +#define RK3308_DAC_DIG_CON14 (RK3308_DAC_DIG_OFFSET + ACODEC_DAC_HPDET_STATUS) /* ADC ANALOG REGISTERS */ /* @@ -76,50 +174,63 @@ * CH2: left_2(ADC5) and right_2(ADC6) * CH3: left_3(ADC7) and right_3(ADC8) */ -#define RK3308_ADC_ANA_OFFSET(ch) (((ch) & 0x3) * 0x40 + 0x340) -#define RK3308_ADC_ANA_CON00(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x00) -#define RK3308_ADC_ANA_CON01(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x04) -#define RK3308_ADC_ANA_CON02(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x08) -#define RK3308_ADC_ANA_CON03(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x0c) -#define RK3308_ADC_ANA_CON04(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x10) -#define RK3308_ADC_ANA_CON05(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x14) -#define RK3308_ADC_ANA_CON06(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x18) -#define RK3308_ADC_ANA_CON07(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x1c) -#define RK3308_ADC_ANA_CON08(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x20) -#define RK3308_ADC_ANA_CON10(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x28) -#define RK3308_ADC_ANA_CON11(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x2c) +#define RK3308_ADC_ANA_OFFSET(ch) ((ch & 0x3) * 0x40 + 0x340) + +#define RK3308_ADC_ANA_CON00(ch) (RK3308_ADC_ANA_OFFSET(ch) + ACODEC_ADC_ANA_MIC_CTL) +#define RK3308_ADC_ANA_CON01(ch) (RK3308_ADC_ANA_OFFSET(ch) + ACODEC_ADC_ANA_MIC_GAIN) +#define RK3308_ADC_ANA_CON02(ch) (RK3308_ADC_ANA_OFFSET(ch) + ACODEC_ADC_ANA_ALC_CTL) +#define RK3308_ADC_ANA_CON03(ch) (RK3308_ADC_ANA_OFFSET(ch) + ACODEC_ADC_ANA_ALC_GAIN1) +#define RK3308_ADC_ANA_CON04(ch) (RK3308_ADC_ANA_OFFSET(ch) + ACODEC_ADC_ANA_ALC_GAIN2) +#define RK3308_ADC_ANA_CON05(ch) (RK3308_ADC_ANA_OFFSET(ch) + ACODEC_ADC_ANA_CTL0) +#define RK3308_ADC_ANA_CON06(ch) (RK3308_ADC_ANA_OFFSET(ch) + ACODEC_ADC_ANA_CTL1) +#define RK3308_ADC_ANA_CON07(ch) (RK3308_ADC_ANA_OFFSET(ch) + ACODEC_ADC_ANA_CTL2) +#define RK3308_ADC_ANA_CON08(ch) (RK3308_ADC_ANA_OFFSET(ch) + ACODEC_ADC_ANA_CTL3) +#define RK3308_ADC_ANA_CON10(ch) (RK3308_ADC_ANA_OFFSET(ch) + ACODEC_ADC_ANA_CTL4) +#define RK3308_ADC_ANA_CON11(ch) (RK3308_ADC_ANA_OFFSET(ch) + ACODEC_ADC_ANA_ALC_PGA) /* DAC ANALOG REGISTERS */ #define RK3308_DAC_ANA_OFFSET 0x440 -#define RK3308_DAC_ANA_CON00 (RK3308_DAC_ANA_OFFSET + 0x00) -#define RK3308_DAC_ANA_CON01 (RK3308_DAC_ANA_OFFSET + 0x04) -#define RK3308_DAC_ANA_CON02 (RK3308_DAC_ANA_OFFSET + 0x08) -#define RK3308_DAC_ANA_CON03 (RK3308_DAC_ANA_OFFSET + 0x0c) -#define RK3308_DAC_ANA_CON04 (RK3308_DAC_ANA_OFFSET + 0x10) -#define RK3308_DAC_ANA_CON05 (RK3308_DAC_ANA_OFFSET + 0x14) -#define RK3308_DAC_ANA_CON06 (RK3308_DAC_ANA_OFFSET + 0x18) -#define RK3308_DAC_ANA_CON07 (RK3308_DAC_ANA_OFFSET + 0x1c) -#define RK3308_DAC_ANA_CON08 (RK3308_DAC_ANA_OFFSET + 0x20) -#define RK3308_DAC_ANA_CON12 (RK3308_DAC_ANA_OFFSET + 0x30) -#define RK3308_DAC_ANA_CON13 (RK3308_DAC_ANA_OFFSET + 0x34) -#define RK3308_DAC_ANA_CON14 (RK3308_DAC_ANA_OFFSET + 0x38) -#define RK3308_DAC_ANA_CON15 (RK3308_DAC_ANA_OFFSET + 0x3c) +#define RK3308_DAC_ANA_CON00 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_CTL0) +#define RK3308_DAC_ANA_CON01 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_POP_VOLT) +#define RK3308_DAC_ANA_CON02 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_CTL1) +#define RK3308_DAC_ANA_CON03 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_HPOUT) +#define RK3308_DAC_ANA_CON04 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_LINEOUT) +#define RK3308_DAC_ANA_CON05 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_L_HPOUT_GAIN) +#define RK3308_DAC_ANA_CON06 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_R_HPOUT_GAIN) +#define RK3308_DAC_ANA_CON07 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_DRV_HPOUT) +#define RK3308_DAC_ANA_CON08 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_DRV_LINEOUT) +#define RK3308_DAC_ANA_CON12 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_HPMIX_CTL0) +#define RK3308_DAC_ANA_CON13 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_HPMIX_CTL1) +#define RK3308_DAC_ANA_CON14 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_LINEOUT_CTL0) +#define RK3308_DAC_ANA_CON15 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_LINEOUT_CTL1) /* * These are the bits for registers */ /* RK3308_GLB_CON - REG: 0x0000 */ -#define RK3308_ADC_BIST_WORK BIT(7) -#define RK3308_DAC_BIST_WORK BIT(6) -#define RK3308_ADC_MCLK_GATING BIT(5) -#define RK3308_DAC_MCLK_GATING BIT(4) -#define RK3308_ADC_DIG_WORK BIT(2) -#define RK3308_DAC_DIG_WORK BIT(1) -#define RK3308_SYS_WORK BIT(0) +#define RK3308_ADC_BIST_WORK (1 << 7) +#define RK3308_ADC_BIST_RESET (0 << 7) +#define RK3308_DAC_BIST_WORK (1 << 6) +#define RK3308_DAC_BIST_RESET (0 << 6) +#define RK3308_ADC_MCLK_MSK (1 << 5) +#define RK3308_ADC_MCLK_DIS (1 << 5) +#define RK3308_ADC_MCLK_EN (0 << 5) +#define RK3308_DAC_MCLK_MSK (1 << 4) +#define RK3308_DAC_MCLK_DIS (1 << 4) +#define RK3308_DAC_MCLK_EN (0 << 4) +#define RK3308_CODEC_RST_MSK (0x7 << 0) +#define RK3308_ADC_DIG_WORK (1 << 2) +#define RK3308_ADC_DIG_RESET (0 << 2) +#define RK3308_DAC_DIG_WORK (1 << 1) +#define RK3308_DAC_DIG_RESET (0 << 1) +#define RK3308_SYS_WORK (1 << 0) +#define RK3308_SYS_RESET (0 << 0) /* RK3308_ADC_DIG_CON01 - REG: 0x0004 */ -#define RK3308_ADC_I2S_LRC_POL_REVERSAL BIT(7) +#define RK3308_ADC_I2S_LRC_POL_MSK (1 << 0) +#define RK3308_ADC_I2S_LRC_POL_REVERSAL (1 << 0) +#define RK3308_ADC_I2S_LRC_POL_NORMAL (0 << 0) #define RK3308_ADC_I2S_VALID_LEN_SFT 5 #define RK3308_ADC_I2S_VALID_LEN_MSK (0x3 << RK3308_ADC_I2S_VALID_LEN_SFT) #define RK3308_ADC_I2S_VALID_LEN_32BITS (0x3 << RK3308_ADC_I2S_VALID_LEN_SFT) @@ -132,20 +243,32 @@ #define RK3308_ADC_I2S_MODE_I2S (0x2 << RK3308_ADC_I2S_MODE_SFT) #define RK3308_ADC_I2S_MODE_LJ (0x1 << RK3308_ADC_I2S_MODE_SFT) #define RK3308_ADC_I2S_MODE_RJ (0x0 << RK3308_ADC_I2S_MODE_SFT) -#define RK3308_ADC_I2S_LR_SWAP BIT(1) -#define RK3308_ADC_I2S_MONO BIT(0) +#define RK3308_ADC_I2S_LR_MSK (1 << 1) +#define RK3308_ADC_I2S_LR_SWAP (1 << 1) +#define RK3308_ADC_I2S_LR_NORMAL (0 << 1) +#define RK3308_ADC_I2S_TYPE_MSK (1 << 0) +#define RK3308_ADC_I2S_MONO (1 << 0) +#define RK3308_ADC_I2S_STEREO (0 << 0) /* RK3308_ADC_DIG_CON02 - REG: 0x0008 */ -#define RK3308_ADC_IO_MODE_MASTER BIT(5) -#define RK3308_ADC_MODE_MASTER BIT(4) +#define RK3308_ADC_IO_MODE_MSK (1 << 5) +#define RK3308_ADC_IO_MODE_MASTER (1 << 5) +#define RK3308_ADC_IO_MODE_SLAVE (0 << 5) +#define RK3308_ADC_MODE_MSK (1 << 4) +#define RK3308_ADC_MODE_MASTER (1 << 4) +#define RK3308_ADC_MODE_SLAVE (0 << 4) #define RK3308_ADC_I2S_FRAME_LEN_SFT 2 #define RK3308_ADC_I2S_FRAME_LEN_MSK (0x3 << RK3308_ADC_I2S_FRAME_LEN_SFT) #define RK3308_ADC_I2S_FRAME_32BITS (0x3 << RK3308_ADC_I2S_FRAME_LEN_SFT) #define RK3308_ADC_I2S_FRAME_24BITS (0x2 << RK3308_ADC_I2S_FRAME_LEN_SFT) #define RK3308_ADC_I2S_FRAME_20BITS (0x1 << RK3308_ADC_I2S_FRAME_LEN_SFT) #define RK3308_ADC_I2S_FRAME_16BITS (0x0 << RK3308_ADC_I2S_FRAME_LEN_SFT) -#define RK3308_ADC_I2S_WORK BIT(1) -#define RK3308_ADC_I2S_BIT_CLK_POL_REVERSAL BIT(0) +#define RK3308_ADC_I2S_MSK (0x1 << 1) +#define RK3308_ADC_I2S_WORK (0x1 << 1) +#define RK3308_ADC_I2S_RESET (0x0 << 1) +#define RK3308_ADC_I2S_BIT_CLK_POL_MSK (0x1 << 0) +#define RK3308_ADC_I2S_BIT_CLK_POL_REVERSAL (0x1 << 0) +#define RK3308_ADC_I2S_BIT_CLK_POL_NORMAL (0x0 << 0) /* RK3308_ADC_DIG_CON03 - REG: 0x000c */ #define RK3308_ADC_L_CH_BIST_SFT 2 @@ -162,7 +285,10 @@ #define RK3308_ADC_R_CH_NORMAL_RIGHT (0x0 << RK3308_ADC_R_CH_BIST_SFT) /* normal mode */ /* RK3308_ADC_DIG_CON04 - REG: 0x0010 */ -#define RK3308_ADC_HPF_PATH_DIS BIT(2) +#define RK3308_ADC_HPF_PATH_SFT 2 +#define RK3308_ADC_HPF_PATH_MSK (1 << RK3308_ADC_HPF_PATH_SFT) +#define RK3308_ADC_HPF_PATH_DIS (1 << RK3308_ADC_HPF_PATH_SFT) +#define RK3308_ADC_HPF_PATH_EN (0 << RK3308_ADC_HPF_PATH_SFT) #define RK3308_ADC_HPF_CUTOFF_SFT 0 #define RK3308_ADC_HPF_CUTOFF_MSK (0x3 << RK3308_ADC_HPF_CUTOFF_SFT) #define RK3308_ADC_HPF_CUTOFF_612HZ (0x2 << RK3308_ADC_HPF_CUTOFF_SFT) @@ -171,15 +297,20 @@ /* RK3308_ADC_DIG_CON07 - REG: 0x001c */ #define RK3308_ADCL_DATA_SFT 4 +#define RK3308_ADCL_DATA(x) (x << RK3308_ADCL_DATA_SFT) #define RK3308_ADCR_DATA_SFT 2 -#define RK3308_ADCL_DATA_SEL_ADCL BIT(1) -#define RK3308_ADCR_DATA_SEL_ADCR BIT(0) +#define RK3308_ADCR_DATA(x) (x << RK3308_ADCR_DATA_SFT) +#define RK3308_ADCL_DATA_SEL_ADCL (0x1 << 1) +#define RK3308_ADCL_DATA_SEL_NORMAL (0x0 << 1) +#define RK3308_ADCR_DATA_SEL_ADCR (0x1 << 0) +#define RK3308_ADCR_DATA_SEL_NORMAL (0x0 << 0) /* * RK3308_ALC_L_DIG_CON00 - REG: 0x0040 + ch * 0xc0 * RK3308_ALC_R_DIG_CON00 - REG: 0x0080 + ch * 0xc0 */ -#define RK3308_GAIN_ATTACK_JACK BIT(6) +#define RK3308_GAIN_ATTACK_JACK (0x1 << 6) +#define RK3308_GAIN_ATTACK_NORMAL (0x0 << 6) #define RK3308_CTRL_GEN_SFT 4 #define RK3308_CTRL_GEN_MSK (0x3 << RK3308_ALC_CTRL_GEN_SFT) #define RK3308_CTRL_GEN_JACK3 (0x3 << RK3308_ALC_CTRL_GEN_SFT) @@ -205,36 +336,145 @@ * RK3308_ALC_R_DIG_CON01 - REG: 0x0084 + ch * 0xc0 */ #define RK3308_AGC_DECAY_TIME_SFT 4 +/* Normal mode (reg_agc_mode = 0) */ +#define RK3308_AGC_DECAY_NORMAL_MSK (0xf << RK3308_AGC_DECAY_TIME_SFT) +#define RK3308_AGC_DECAY_NORMAL_512MS (0xa << RK3308_AGC_DECAY_TIME_SFT) +#define RK3308_AGC_DECAY_NORMAL_256MS (0x9 << RK3308_AGC_DECAY_TIME_SFT) +#define RK3308_AGC_DECAY_NORMAL_128MS (0x8 << RK3308_AGC_DECAY_TIME_SFT) +#define RK3308_AGC_DECAY_NORMAL_64MS (0x7 << RK3308_AGC_DECAY_TIME_SFT) +#define RK3308_AGC_DECAY_NORMAL_32MS (0x6 << RK3308_AGC_DECAY_TIME_SFT) +#define RK3308_AGC_DECAY_NORMAL_16MS (0x5 << RK3308_AGC_DECAY_TIME_SFT) +#define RK3308_AGC_DECAY_NORMAL_8MS (0x4 << RK3308_AGC_DECAY_TIME_SFT) +#define RK3308_AGC_DECAY_NORMAL_4MS (0x3 << RK3308_AGC_DECAY_TIME_SFT) +#define RK3308_AGC_DECAY_NORMAL_2MS (0x2 << RK3308_AGC_DECAY_TIME_SFT) +#define RK3308_AGC_DECAY_NORMAL_1MS (0x1 << RK3308_AGC_DECAY_TIME_SFT) +#define RK3308_AGC_DECAY_NORMAL_0MS (0x0 << RK3308_AGC_DECAY_TIME_SFT) +/* Limiter mode (reg_agc_mode = 1) */ +#define RK3308_AGC_DECAY_LIMITER_MSK (0xf << RK3308_AGC_DECAY_TIME_SFT) +#define RK3308_AGC_DECAY_LIMITER_128MS (0xa << RK3308_AGC_DECAY_TIME_SFT) +#define RK3308_AGC_DECAY_LIMITER_64MS (0x9 << RK3308_AGC_DECAY_TIME_SFT) +#define RK3308_AGC_DECAY_LIMITER_32MS (0x8 << RK3308_AGC_DECAY_TIME_SFT) +#define RK3308_AGC_DECAY_LIMITER_16MS (0x7 << RK3308_AGC_DECAY_TIME_SFT) +#define RK3308_AGC_DECAY_LIMITER_8MS (0x6 << RK3308_AGC_DECAY_TIME_SFT) +#define RK3308_AGC_DECAY_LIMITER_4MS (0x5 << RK3308_AGC_DECAY_TIME_SFT) +#define RK3308_AGC_DECAY_LIMITER_2MS (0x4 << RK3308_AGC_DECAY_TIME_SFT) +#define RK3308_AGC_DECAY_LIMITER_1MS (0x3 << RK3308_AGC_DECAY_TIME_SFT) +#define RK3308_AGC_DECAY_LIMITER_500US (0x2 << RK3308_AGC_DECAY_TIME_SFT) +#define RK3308_AGC_DECAY_LIMITER_250US (0x1 << RK3308_AGC_DECAY_TIME_SFT) +#define RK3308_AGC_DECAY_LIMITER_125US (0x0 << RK3308_AGC_DECAY_TIME_SFT) + #define RK3308_AGC_ATTACK_TIME_SFT 0 +/* Normal mode (reg_agc_mode = 0) */ +#define RK3308_AGC_ATTACK_NORMAL_MSK (0xf << RK3308_AGC_ATTACK_TIME_SFT) +#define RK3308_AGC_ATTACK_NORMAL_128MS (0xa << RK3308_AGC_ATTACK_TIME_SFT) +#define RK3308_AGC_ATTACK_NORMAL_64MS (0x9 << RK3308_AGC_ATTACK_TIME_SFT) +#define RK3308_AGC_ATTACK_NORMAL_32MS (0x8 << RK3308_AGC_ATTACK_TIME_SFT) +#define RK3308_AGC_ATTACK_NORMAL_16MS (0x7 << RK3308_AGC_ATTACK_TIME_SFT) +#define RK3308_AGC_ATTACK_NORMAL_8MS (0x6 << RK3308_AGC_ATTACK_TIME_SFT) +#define RK3308_AGC_ATTACK_NORMAL_4MS (0x5 << RK3308_AGC_ATTACK_TIME_SFT) +#define RK3308_AGC_ATTACK_NORMAL_2MS (0x4 << RK3308_AGC_ATTACK_TIME_SFT) +#define RK3308_AGC_ATTACK_NORMAL_1MS (0x3 << RK3308_AGC_ATTACK_TIME_SFT) +#define RK3308_AGC_ATTACK_NORMAL_500US (0x2 << RK3308_AGC_ATTACK_TIME_SFT) +#define RK3308_AGC_ATTACK_NORMAL_250US (0x1 << RK3308_AGC_ATTACK_TIME_SFT) +#define RK3308_AGC_ATTACK_NORMAL_125US (0x0 << RK3308_AGC_ATTACK_TIME_SFT) +/* Limiter mode (reg_agc_mode = 1) */ +#define RK3308_AGC_ATTACK_LIMITER_MSK (0xf << RK3308_AGC_ATTACK_TIME_SFT) +#define RK3308_AGC_ATTACK_LIMITER_32MS (0xa << RK3308_AGC_ATTACK_TIME_SFT) +#define RK3308_AGC_ATTACK_LIMITER_16MS (0x9 << RK3308_AGC_ATTACK_TIME_SFT) +#define RK3308_AGC_ATTACK_LIMITER_8MS (0x8 << RK3308_AGC_ATTACK_TIME_SFT) +#define RK3308_AGC_ATTACK_LIMITER_4MS (0x7 << RK3308_AGC_ATTACK_TIME_SFT) +#define RK3308_AGC_ATTACK_LIMITER_2MS (0x6 << RK3308_AGC_ATTACK_TIME_SFT) +#define RK3308_AGC_ATTACK_LIMITER_1MS (0x5 << RK3308_AGC_ATTACK_TIME_SFT) +#define RK3308_AGC_ATTACK_LIMITER_500US (0x4 << RK3308_AGC_ATTACK_TIME_SFT) +#define RK3308_AGC_ATTACK_LIMITER_250US (0x3 << RK3308_AGC_ATTACK_TIME_SFT) +#define RK3308_AGC_ATTACK_LIMITER_125US (0x2 << RK3308_AGC_ATTACK_TIME_SFT) +#define RK3308_AGC_ATTACK_LIMITER_64US (0x1 << RK3308_AGC_ATTACK_TIME_SFT) +#define RK3308_AGC_ATTACK_LIMITER_32US (0x0 << RK3308_AGC_ATTACK_TIME_SFT) /* * RK3308_ALC_L_DIG_CON02 - REG: 0x0048 + ch * 0xc0 * RK3308_ALC_R_DIG_CON02 - REG: 0x0088 + ch * 0xc0 */ -#define RK3308_AGC_MODE_LIMITER BIT(7) -#define RK3308_AGC_ZERO_CRO_EN BIT(6) -#define RK3308_AGC_AMP_RECOVER_GAIN BIT(5) -#define RK3308_AGC_FAST_DEC_EN BIT(4) -#define RK3308_AGC_NOISE_GATE_EN BIT(3) +#define RK3308_AGC_MODE_LIMITER (0x1 << 7) +#define RK3308_AGC_MODE_NORMAL (0x0 << 7) +#define RK3308_AGC_ZERO_CRO_EN (0x1 << 6) +#define RK3308_AGC_ZERO_CRO_DIS (0x0 << 6) +#define RK3308_AGC_AMP_RECOVER_GAIN (0x1 << 5) +#define RK3308_AGC_AMP_RECOVER_LVOL (0x0 << 5) +#define RK3308_AGC_FAST_DEC_EN (0x1 << 4) +#define RK3308_AGC_FAST_DEC_DIS (0x0 << 4) +#define RK3308_AGC_NOISE_GATE_EN (0x1 << 3) +#define RK3308_AGC_NOISE_GATE_DIS (0x0 << 3) #define RK3308_AGC_NOISE_GATE_THRESH_SFT 0 #define RK3308_AGC_NOISE_GATE_THRESH_MSK (0x7 << RK3308_AGC_NOISE_GATE_THRESH_SFT) +#define RK3308_AGC_NOISE_GATE_THRESH_N81DB (0x7 << RK3308_AGC_NOISE_GATE_THRESH_SFT) +#define RK3308_AGC_NOISE_GATE_THRESH_N75DB (0x6 << RK3308_AGC_NOISE_GATE_THRESH_SFT) +#define RK3308_AGC_NOISE_GATE_THRESH_N69DB (0x5 << RK3308_AGC_NOISE_GATE_THRESH_SFT) +#define RK3308_AGC_NOISE_GATE_THRESH_N63DB (0x4 << RK3308_AGC_NOISE_GATE_THRESH_SFT) +#define RK3308_AGC_NOISE_GATE_THRESH_N57DB (0x3 << RK3308_AGC_NOISE_GATE_THRESH_SFT) +#define RK3308_AGC_NOISE_GATE_THRESH_N51DB (0x2 << RK3308_AGC_NOISE_GATE_THRESH_SFT) +#define RK3308_AGC_NOISE_GATE_THRESH_N45DB (0x1 << RK3308_AGC_NOISE_GATE_THRESH_SFT) +#define RK3308_AGC_NOISE_GATE_THRESH_N39DB (0x0 << RK3308_AGC_NOISE_GATE_THRESH_SFT) /* * RK3308_ALC_L_DIG_CON03 - REG: 0x004c + ch * 0xc0 * RK3308_ALC_R_DIG_CON03 - REG: 0x008c + ch * 0xc0 */ -#define RK3308_AGC_PGA_ZERO_CRO_EN BIT(5) +#define RK3308_AGC_PGA_ZERO_CRO_EN (0x1 << 5) +#define RK3308_AGC_PGA_ZERO_CRO_DIS (0x0 << 5) #define RK3308_AGC_PGA_GAIN_MAX 0x1f #define RK3308_AGC_PGA_GAIN_MIN 0 #define RK3308_AGC_PGA_GAIN_SFT 0 +#define RK3308_AGC_PGA_GAIN_MSK (0x1f << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_PDB_28_5 (0x1f << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_PDB_27 (0x1e << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_PDB_25_5 (0x1d << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_PDB_24 (0x1c << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_PDB_22_5 (0x1b << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_PDB_21 (0x1a << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_PDB_19_5 (0x19 << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_PDB_18 (0x18 << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_PDB_16_5 (0x17 << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_PDB_15 (0x16 << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_PDB_13_5 (0x15 << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_PDB_12 (0x14 << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_PDB_10_5 (0x13 << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_PDB_9 (0x12 << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_PDB_7_5 (0x11 << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_PDB_6 (0x10 << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_PDB_4_5 (0x0f << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_PDB_3 (0x0e << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_PDB_1_5 (0x0d << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_0DB (0x0c << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_NDB_1_5 (0x0b << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_NDB_3 (0x0a << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_NDB_4_5 (0x09 << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_NDB_6 (0x08 << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_NDB_7_5 (0x07 << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_NDB_9 (0x06 << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_NDB_10_5 (0x05 << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_NDB_12 (0x04 << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_NDB_13_5 (0x03 << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_NDB_15 (0x02 << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_NDB_16_5 (0x01 << RK3308_AGC_PGA_GAIN_SFT) +#define RK3308_AGC_PGA_GAIN_NDB_18 (0x00 << RK3308_AGC_PGA_GAIN_SFT) /* * RK3308_ALC_L_DIG_CON04 - REG: 0x0050 + ch * 0xc0 * RK3308_ALC_R_DIG_CON04 - REG: 0x0090 + ch * 0xc0 */ -#define RK3308_AGC_SLOW_CLK_EN BIT(3) +#define RK3308_AGC_SLOW_CLK_EN (0x1 << 3) +#define RK3308_AGC_SLOW_CLK_DIS (0x0 << 3) #define RK3308_AGC_APPROX_RATE_SFT 0 #define RK3308_AGC_APPROX_RATE_MSK (0x7 << RK3308_AGC_APPROX_RATE_SFT) +#define RK3308_AGC_APPROX_RATE_8K (0x7 << RK3308_AGC_APPROX_RATE_SFT) +#define RK3308_AGC_APPROX_RATE_12K (0x6 << RK3308_AGC_APPROX_RATE_SFT) +#define RK3308_AGC_APPROX_RATE_16K (0x5 << RK3308_AGC_APPROX_RATE_SFT) +#define RK3308_AGC_APPROX_RATE_24K (0x4 << RK3308_AGC_APPROX_RATE_SFT) +#define RK3308_AGC_APPROX_RATE_32K (0x3 << RK3308_AGC_APPROX_RATE_SFT) +#define RK3308_AGC_APPROX_RATE_44_1K (0x2 << RK3308_AGC_APPROX_RATE_SFT) +#define RK3308_AGC_APPROX_RATE_48K (0x1 << RK3308_AGC_APPROX_RATE_SFT) +#define RK3308_AGC_APPROX_RATE_96K (0x0 << RK3308_AGC_APPROX_RATE_SFT) /* * RK3308_ALC_L_DIG_CON05 - REG: 0x0054 + ch * 0xc0 @@ -264,15 +504,33 @@ * RK3308_ALC_L_DIG_CON09 - REG: 0x0064 + ch * 0xc0 * RK3308_ALC_R_DIG_CON09 - REG: 0x00a4 + ch * 0xc0 */ -#define RK3308_AGC_FUNC_SEL BIT(6) +#define RK3308_AGC_FUNC_SEL_MSK (0x1 << 6) +#define RK3308_AGC_FUNC_SEL_EN (0x1 << 6) +#define RK3308_AGC_FUNC_SEL_DIS (0x0 << 6) #define RK3308_AGC_MAX_GAIN_PGA_MAX 0x7 #define RK3308_AGC_MAX_GAIN_PGA_MIN 0 #define RK3308_AGC_MAX_GAIN_PGA_SFT 3 #define RK3308_AGC_MAX_GAIN_PGA_MSK (0x7 << RK3308_AGC_MAX_GAIN_PGA_SFT) +#define RK3308_AGC_MAX_GAIN_PGA_PDB_28_5 (0x7 << RK3308_AGC_MAX_GAIN_PGA_SFT) +#define RK3308_AGC_MAX_GAIN_PGA_PDB_22_5 (0x6 << RK3308_AGC_MAX_GAIN_PGA_SFT) +#define RK3308_AGC_MAX_GAIN_PGA_PDB_16_5 (0x5 << RK3308_AGC_MAX_GAIN_PGA_SFT) +#define RK3308_AGC_MAX_GAIN_PGA_PDB_10_5 (0x4 << RK3308_AGC_MAX_GAIN_PGA_SFT) +#define RK3308_AGC_MAX_GAIN_PGA_PDB_4_5 (0x3 << RK3308_AGC_MAX_GAIN_PGA_SFT) +#define RK3308_AGC_MAX_GAIN_PGA_NDB_1_5 (0x2 << RK3308_AGC_MAX_GAIN_PGA_SFT) +#define RK3308_AGC_MAX_GAIN_PGA_NDB_7_5 (0x1 << RK3308_AGC_MAX_GAIN_PGA_SFT) +#define RK3308_AGC_MAX_GAIN_PGA_NDB_13_5 (0x0 << RK3308_AGC_MAX_GAIN_PGA_SFT) #define RK3308_AGC_MIN_GAIN_PGA_MAX 0x7 #define RK3308_AGC_MIN_GAIN_PGA_MIN 0 #define RK3308_AGC_MIN_GAIN_PGA_SFT 0 #define RK3308_AGC_MIN_GAIN_PGA_MSK (0x7 << RK3308_AGC_MIN_GAIN_PGA_SFT) +#define RK3308_AGC_MIN_GAIN_PGA_PDB_24 (0x7 << RK3308_AGC_MIN_GAIN_PGA_SFT) +#define RK3308_AGC_MIN_GAIN_PGA_PDB_18 (0x6 << RK3308_AGC_MIN_GAIN_PGA_SFT) +#define RK3308_AGC_MIN_GAIN_PGA_PDB_12 (0x5 << RK3308_AGC_MIN_GAIN_PGA_SFT) +#define RK3308_AGC_MIN_GAIN_PGA_PDB_6 (0x4 << RK3308_AGC_MIN_GAIN_PGA_SFT) +#define RK3308_AGC_MIN_GAIN_PGA_0DB (0x3 << RK3308_AGC_MIN_GAIN_PGA_SFT) +#define RK3308_AGC_MIN_GAIN_PGA_NDB_6 (0x2 << RK3308_AGC_MIN_GAIN_PGA_SFT) +#define RK3308_AGC_MIN_GAIN_PGA_NDB_12 (0x1 << RK3308_AGC_MIN_GAIN_PGA_SFT) +#define RK3308_AGC_MIN_GAIN_PGA_NDB_18 (0x0 << RK3308_AGC_MIN_GAIN_PGA_SFT) /* * RK3308_ALC_L_DIG_CON12 - REG: 0x0068 + ch * 0xc0 @@ -281,7 +539,9 @@ #define RK3308_AGC_GAIN_MSK 0x1f /* RK3308_DAC_DIG_CON01 - REG: 0x0304 */ -#define RK3308_DAC_I2S_LRC_POL_REVERSAL BIT(7) +#define RK3308_DAC_I2S_LRC_POL_MSK (0x1 << 7) +#define RK3308_DAC_I2S_LRC_POL_REVERSAL (0x1 << 7) +#define RK3308_DAC_I2S_LRC_POL_NORMAL (0x0 << 7) #define RK3308_DAC_I2S_VALID_LEN_SFT 5 #define RK3308_DAC_I2S_VALID_LEN_MSK (0x3 << RK3308_DAC_I2S_VALID_LEN_SFT) #define RK3308_DAC_I2S_VALID_LEN_32BITS (0x3 << RK3308_DAC_I2S_VALID_LEN_SFT) @@ -294,21 +554,29 @@ #define RK3308_DAC_I2S_MODE_I2S (0x2 << RK3308_DAC_I2S_MODE_SFT) #define RK3308_DAC_I2S_MODE_LJ (0x1 << RK3308_DAC_I2S_MODE_SFT) #define RK3308_DAC_I2S_MODE_RJ (0x0 << RK3308_DAC_I2S_MODE_SFT) -#define RK3308_DAC_I2S_LR_SWAP BIT(2) +#define RK3308_DAC_I2S_LR_MSK (0x1 << 2) +#define RK3308_DAC_I2S_LR_SWAP (0x1 << 2) +#define RK3308_DAC_I2S_LR_NORMAL (0x0 << 2) /* RK3308_DAC_DIG_CON02 - REG: 0x0308 */ -#define RK3308BS_DAC_IO_MODE_MASTER BIT(7) -#define RK3308BS_DAC_MODE_MASTER BIT(6) -#define RK3308_DAC_IO_MODE_MASTER BIT(5) -#define RK3308_DAC_MODE_MASTER BIT(4) +#define RK3308_DAC_IO_MODE_MSK (0x1 << 5) +#define RK3308_DAC_IO_MODE_MASTER (0x1 << 5) +#define RK3308_DAC_IO_MODE_SLAVE (0x0 << 5) +#define RK3308_DAC_MODE_MSK (0x1 << 4) +#define RK3308_DAC_MODE_MASTER (0x1 << 4) +#define RK3308_DAC_MODE_SLAVE (0x0 << 4) #define RK3308_DAC_I2S_FRAME_LEN_SFT 2 #define RK3308_DAC_I2S_FRAME_LEN_MSK (0x3 << RK3308_DAC_I2S_FRAME_LEN_SFT) #define RK3308_DAC_I2S_FRAME_32BITS (0x3 << RK3308_DAC_I2S_FRAME_LEN_SFT) #define RK3308_DAC_I2S_FRAME_24BITS (0x2 << RK3308_DAC_I2S_FRAME_LEN_SFT) #define RK3308_DAC_I2S_FRAME_20BITS (0x1 << RK3308_DAC_I2S_FRAME_LEN_SFT) #define RK3308_DAC_I2S_FRAME_16BITS (0x0 << RK3308_DAC_I2S_FRAME_LEN_SFT) -#define RK3308_DAC_I2S_WORK BIT(1) -#define RK3308_DAC_I2S_BIT_CLK_POL_REVERSAL BIT(0) +#define RK3308_DAC_I2S_MSK (0x1 << 1) +#define RK3308_DAC_I2S_WORK (0x1 << 1) +#define RK3308_DAC_I2S_RESET (0x0 << 1) +#define RK3308_DAC_I2S_BIT_CLK_POL_MSK (0x1 << 0) +#define RK3308_DAC_I2S_BIT_CLK_POL_REVERSAL (0x1 << 0) +#define RK3308_DAC_I2S_BIT_CLK_POL_NORMAL (0x0 << 0) /* RK3308_DAC_DIG_CON03 - REG: 0x030C */ #define RK3308_DAC_L_CH_BIST_SFT 2 @@ -325,62 +593,64 @@ #define RK3308_DAC_R_CH_BIST_RIGHT (0x0 << RK3308_DAC_R_CH_BIST_SFT) /* normal mode */ /* RK3308_DAC_DIG_CON04 - REG: 0x0310 */ -/* Versions up to B: */ #define RK3308_DAC_MODULATOR_GAIN_SFT 4 #define RK3308_DAC_MODULATOR_GAIN_MSK (0x7 << RK3308_DAC_MODULATOR_GAIN_SFT) +#define RK3308_DAC_MODULATOR_GAIN_4_8DB (0x5 << RK3308_DAC_MODULATOR_GAIN_SFT) +#define RK3308_DAC_MODULATOR_GAIN_4_2DB (0x4 << RK3308_DAC_MODULATOR_GAIN_SFT) +#define RK3308_DAC_MODULATOR_GAIN_3_5DB (0x3 << RK3308_DAC_MODULATOR_GAIN_SFT) +#define RK3308_DAC_MODULATOR_GAIN_2_8DB (0x2 << RK3308_DAC_MODULATOR_GAIN_SFT) +#define RK3308_DAC_MODULATOR_GAIN_2DB (0x1 << RK3308_DAC_MODULATOR_GAIN_SFT) +#define RK3308_DAC_MODULATOR_GAIN_0DB (0x0 << RK3308_DAC_MODULATOR_GAIN_SFT) #define RK3308_DAC_CIC_IF_GAIN_SFT 0 #define RK3308_DAC_CIC_IF_GAIN_MSK (0x7 << RK3308_DAC_CIC_IF_GAIN_SFT) -/* Version C: */ -#define RK3308BS_DAC_DIG_GAIN_SFT 0 -#define RK3308BS_DAC_DIG_GAIN_MSK (0xff << RK3308BS_DAC_DIG_GAIN_SFT) -#define RK3308BS_DAC_DIG_GAIN_0DB (0xed << RK3308BS_DAC_DIG_GAIN_SFT) - -/* RK3308BS_ADC_DIG_CON05..06 (Version C only) */ -#define RK3308_ADC_DIG_VOL_CON_x_SFT 0 -#define RK3308_ADC_DIG_VOL_CON_x_MSK (0xff << RK3308_ADC_DIG_VOL_CON_x_SFT) -#define RK3308_ADC_DIG_VOL_CON_x_0DB (0xc2 << RK3308_ADC_DIG_VOL_CON_x_SFT) /* RK3308_DAC_DIG_CON05 - REG: 0x0314 */ -#define RK3308_DAC_L_REG_CTL_INDATA BIT(2) -#define RK3308_DAC_R_REG_CTL_INDATA BIT(1) +#define RK3308_DAC_L_REG_CTL_INDATA (0x1 << 2) +#define RK3308_DAC_L_NORMAL_DATA (0x0 << 2) +#define RK3308_DAC_R_REG_CTL_INDATA (0x1 << 1) +#define RK3308_DAC_R_NORMAL_DATA (0x0 << 1) /* RK3308_DAC_DIG_CON10 - REG: 0x0328 */ -#define RK3308_DAC_DATA_HI4(x) ((x) & 0xf) +#define RK3308_DAC_DATA_HI4(x) (x & 0xf) /* Need to RK3308_DAC_x_REG_CTL_INDATA */ /* RK3308_DAC_DIG_CON11 - REG: 0x032c */ -#define RK3308_DAC_DATA_LO8(x) ((x) & 0xff) +#define RK3308_DAC_DATA_LO8(x) (x & 0xff) /* Need to RK3308_DAC_x_REG_CTL_INDATA */ /* RK3308_ADC_ANA_CON00 - REG: 0x0340 */ #define RK3308_ADC_CH1_CH2_MIC_ALL_MSK (0xff << 0) #define RK3308_ADC_CH1_CH2_MIC_ALL 0xff -#define RK3308_ADC_CH2_MIC_UNMUTE BIT(7) -#define RK3308_ADC_CH2_MIC_WORK BIT(6) -#define RK3308_ADC_CH2_MIC_EN BIT(5) -#define RK3308_ADC_CH2_BUF_REF_EN BIT(4) -#define RK3308_ADC_CH1_MIC_UNMUTE BIT(3) -#define RK3308_ADC_CH1_MIC_WORK BIT(2) -#define RK3308_ADC_CH1_MIC_EN BIT(1) -#define RK3308_ADC_CH1_BUF_REF_EN BIT(0) +#define RK3308_ADC_CH2_MIC_UNMUTE (0x1 << 7) +#define RK3308_ADC_CH2_MIC_MUTE (0x0 << 7) +#define RK3308_ADC_CH2_MIC_WORK (0x1 << 6) +#define RK3308_ADC_CH2_MIC_INIT (0x0 << 6) +#define RK3308_ADC_CH2_MIC_EN (0x1 << 5) +#define RK3308_ADC_CH2_MIC_DIS (0x0 << 5) +#define RK3308_ADC_CH2_BUF_REF_EN (0x1 << 4) +#define RK3308_ADC_CH2_BUF_REF_DIS (0x0 << 4) +#define RK3308_ADC_CH1_MIC_UNMUTE (0x1 << 3) +#define RK3308_ADC_CH1_MIC_MUTE (0x0 << 3) +#define RK3308_ADC_CH1_MIC_WORK (0x1 << 2) +#define RK3308_ADC_CH1_MIC_INIT (0x0 << 2) +#define RK3308_ADC_CH1_MIC_EN (0x1 << 1) +#define RK3308_ADC_CH1_MIC_DIS (0x0 << 1) +#define RK3308_ADC_CH1_BUF_REF_EN (0x1 << 0) +#define RK3308_ADC_CH1_BUF_REF_DIS (0x0 << 0) /* RK3308_ADC_ANA_CON01 - REG: 0x0344 * * The PGA of MIC-INs: - * - HW version A: - * 0x0 - MIC1~MIC8 0 dB (recommended when ADC used as loopback) - * 0x3 - MIC1~MIC8 20 dB (recommended when ADC used as MIC input) - * - HW version B: - * 0x0 - MIC1~MIC8 0 dB - * 0x1 - MIC1~MIC8 6.6 dB - * 0x2 - MIC1~MIC8 13 dB - * 0x3 - MIC1~MIC8 20 dB + * 0x0 - MIC1~MIC8 0dB + * 0x1 - MIC1~MIC8 6.6dB + * 0x2 - MIC1~MIC8 13dB + * 0x3 - MIC1~MIC8 20dB */ #define RK3308_ADC_CH2_MIC_GAIN_MAX 0x3 #define RK3308_ADC_CH2_MIC_GAIN_MIN 0 #define RK3308_ADC_CH2_MIC_GAIN_SFT 4 #define RK3308_ADC_CH2_MIC_GAIN_MSK (0x3 << RK3308_ADC_CH2_MIC_GAIN_SFT) #define RK3308_ADC_CH2_MIC_GAIN_20DB (0x3 << RK3308_ADC_CH2_MIC_GAIN_SFT) -#define RK3308_ADC_CH2_MIC_GAIN_13DB (0x2 << RK3308_ADC_CH2_MIC_GAIN_SFT) -#define RK3308_ADC_CH2_MIC_GAIN_6_6DB (0x1 << RK3308_ADC_CH2_MIC_GAIN_SFT) +#define RK3308_ADC_CH2_MIC_GAIN_13DB (0x2 << RK3308_ADC_CH2_MIC_GAIN_SFT) /* TRM: only used for version B */ +#define RK3308_ADC_CH2_MIC_GAIN_6_6DB (0x1 << RK3308_ADC_CH2_MIC_GAIN_SFT) /* TRM: only used for version B */ #define RK3308_ADC_CH2_MIC_GAIN_0DB (0x0 << RK3308_ADC_CH2_MIC_GAIN_SFT) #define RK3308_ADC_CH1_MIC_GAIN_MAX 0x3 @@ -388,42 +658,124 @@ #define RK3308_ADC_CH1_MIC_GAIN_SFT 0 #define RK3308_ADC_CH1_MIC_GAIN_MSK (0x3 << RK3308_ADC_CH1_MIC_GAIN_SFT) #define RK3308_ADC_CH1_MIC_GAIN_20DB (0x3 << RK3308_ADC_CH1_MIC_GAIN_SFT) -#define RK3308_ADC_CH1_MIC_GAIN_13DB (0x2 << RK3308_ADC_CH1_MIC_GAIN_SFT) -#define RK3308_ADC_CH1_MIC_GAIN_6_6DB (0x1 << RK3308_ADC_CH1_MIC_GAIN_SFT) +#define RK3308_ADC_CH1_MIC_GAIN_13DB (0x2 << RK3308_ADC_CH1_MIC_GAIN_SFT) /* TRM: only used for version B */ +#define RK3308_ADC_CH1_MIC_GAIN_6_6DB (0x1 << RK3308_ADC_CH1_MIC_GAIN_SFT) /* TRM: only used for version B */ #define RK3308_ADC_CH1_MIC_GAIN_0DB (0x0 << RK3308_ADC_CH1_MIC_GAIN_SFT) /* RK3308_ADC_ANA_CON02 - REG: 0x0348 */ -#define RK3308_ADC_CH2_ZEROCROSS_DET_EN BIT(6) -#define RK3308_ADC_CH2_ALC_WORK BIT(5) -#define RK3308_ADC_CH2_ALC_EN BIT(4) -#define RK3308_ADC_CH1_ZEROCROSS_DET_EN BIT(2) -#define RK3308_ADC_CH1_ALC_WORK BIT(1) -#define RK3308_ADC_CH1_ALC_EN BIT(0) +#define RK3308_ADC_CH2_ALC_ZC_MSK (0x7 << 4) +#define RK3308_ADC_CH2_ZEROCROSS_DET_EN (0x1 << 6) +#define RK3308_ADC_CH2_ZEROCROSS_DET_DIS (0x0 << 6) +#define RK3308_ADC_CH2_ALC_WORK (0x1 << 5) +#define RK3308_ADC_CH2_ALC_INIT (0x0 << 5) +#define RK3308_ADC_CH2_ALC_EN (0x1 << 4) +#define RK3308_ADC_CH2_ALC_DIS (0x0 << 4) + +#define RK3308_ADC_CH1_ALC_ZC_MSK (0x7 << 0) +#define RK3308_ADC_CH1_ZEROCROSS_DET_EN (0x1 << 2) +#define RK3308_ADC_CH1_ZEROCROSS_DET_DIS (0x0 << 2) +#define RK3308_ADC_CH1_ALC_WORK (0x1 << 1) +#define RK3308_ADC_CH1_ALC_INIT (0x0 << 1) +#define RK3308_ADC_CH1_ALC_EN (0x1 << 0) +#define RK3308_ADC_CH1_ALC_DIS (0x0 << 0) /* RK3308_ADC_ANA_CON03 - REG: 0x034c */ #define RK3308_ADC_CH1_ALC_GAIN_MAX 0x1f #define RK3308_ADC_CH1_ALC_GAIN_MIN 0 #define RK3308_ADC_CH1_ALC_GAIN_SFT 0 #define RK3308_ADC_CH1_ALC_GAIN_MSK (0x1f << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_PDB_28_5 (0x1f << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_PDB_27 (0x1e << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_PDB_25_5 (0x1d << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_PDB_24 (0x1c << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_PDB_22_5 (0x1b << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_PDB_21 (0x1a << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_PDB_19_5 (0x19 << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_PDB_18 (0x18 << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_PDB_16_5 (0x17 << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_PDB_15 (0x16 << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_PDB_13_5 (0x15 << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_PDB_12 (0x14 << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_PDB_10_5 (0x13 << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_PDB_9 (0x12 << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_PDB_7_5 (0x11 << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_PDB_6 (0x10 << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_PDB_4_5 (0x0f << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_PDB_3 (0x0e << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_PDB_1_5 (0x0d << RK3308_ADC_CH1_ALC_GAIN_SFT) #define RK3308_ADC_CH1_ALC_GAIN_0DB (0x0c << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_NDB_1_5 (0x0b << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_NDB_3 (0x0a << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_NDB_4_5 (0x09 << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_NDB_6 (0x08 << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_NDB_7_5 (0x07 << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_NDB_9 (0x06 << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_NDB_10_5 (0x05 << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_NDB_12 (0x04 << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_NDB_13_5 (0x03 << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_NDB_15 (0x02 << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_NDB_16_5 (0x01 << RK3308_ADC_CH1_ALC_GAIN_SFT) +#define RK3308_ADC_CH1_ALC_GAIN_NDB_18 (0x00 << RK3308_ADC_CH1_ALC_GAIN_SFT) /* RK3308_ADC_ANA_CON04 - REG: 0x0350 */ #define RK3308_ADC_CH2_ALC_GAIN_MAX 0x1f #define RK3308_ADC_CH2_ALC_GAIN_MIN 0 #define RK3308_ADC_CH2_ALC_GAIN_SFT 0 #define RK3308_ADC_CH2_ALC_GAIN_MSK (0x1f << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_PDB_28_5 (0x1f << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_PDB_27 (0x1e << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_PDB_25_5 (0x1d << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_PDB_24 (0x1c << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_PDB_22_5 (0x1b << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_PDB_21 (0x1a << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_PDB_19_5 (0x19 << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_PDB_18 (0x18 << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_PDB_16_5 (0x17 << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_PDB_15 (0x16 << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_PDB_13_5 (0x15 << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_PDB_12 (0x14 << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_PDB_10_5 (0x13 << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_PDB_9 (0x12 << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_PDB_7_5 (0x11 << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_PDB_6 (0x10 << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_PDB_4_5 (0x0f << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_PDB_3 (0x0e << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_PDB_1_5 (0x0d << RK3308_ADC_CH2_ALC_GAIN_SFT) #define RK3308_ADC_CH2_ALC_GAIN_0DB (0x0c << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_NDB_1_5 (0x0b << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_NDB_3 (0x0a << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_NDB_4_5 (0x09 << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_NDB_6 (0x08 << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_NDB_7_5 (0x07 << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_NDB_9 (0x06 << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_NDB_10_5 (0x05 << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_NDB_12 (0x04 << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_NDB_13_5 (0x03 << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_NDB_15 (0x02 << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_NDB_16_5 (0x01 << RK3308_ADC_CH2_ALC_GAIN_SFT) +#define RK3308_ADC_CH2_ALC_GAIN_NDB_18 (0x00 << RK3308_ADC_CH2_ALC_GAIN_SFT) /* RK3308_ADC_ANA_CON05 - REG: 0x0354 */ -#define RK3308_ADC_CH2_ADC_WORK BIT(6) -#define RK3308_ADC_CH2_ADC_EN BIT(5) -#define RK3308_ADC_CH2_CLK_EN BIT(4) -#define RK3308_ADC_CH1_ADC_WORK BIT(2) -#define RK3308_ADC_CH1_ADC_EN BIT(1) -#define RK3308_ADC_CH1_CLK_EN BIT(0) +#define RK3308_ADC_CH2_ADC_CLK_MSK (0x7 << 4) +#define RK3308_ADC_CH2_ADC_WORK (0x1 << 6) +#define RK3308_ADC_CH2_ADC_INIT (0x0 << 6) +#define RK3308_ADC_CH2_ADC_EN (0x1 << 5) +#define RK3308_ADC_CH2_ADC_DIS (0x0 << 5) +#define RK3308_ADC_CH2_CLK_EN (0x1 << 4) +#define RK3308_ADC_CH2_CLK_DIS (0x0 << 4) + +#define RK3308_ADC_CH1_ADC_CLK_MSK (0x7 << 0) +#define RK3308_ADC_CH1_ADC_WORK (0x1 << 2) +#define RK3308_ADC_CH1_ADC_INIT (0x0 << 2) +#define RK3308_ADC_CH1_ADC_EN (0x1 << 1) +#define RK3308_ADC_CH1_ADC_DIS (0x0 << 1) +#define RK3308_ADC_CH1_CLK_EN (0x1 << 0) +#define RK3308_ADC_CH1_CLK_DIS (0x0 << 0) /* RK3308_ADC_ANA_CON06 - REG: 0x0358 */ -#define RK3308_ADC_CURRENT_EN BIT(0) +#define RK3308_ADC_CURRENT_MSK (0x1 << 0) +#define RK3308_ADC_CURRENT_EN (0x1 << 0) +#define RK3308_ADC_CURRENT_DIS (0x0 << 0) /* RK3308_ADC_ANA_CON07 - REG: 0x035c */ /* Note: The register configuration is only valid for ADC2 */ @@ -440,80 +792,201 @@ #define RK3308_ADC_CH1_IN_LINEIN (0x2 << RK3308_ADC_CH1_IN_SEL_SFT) #define RK3308_ADC_CH1_IN_MIC (0x1 << RK3308_ADC_CH1_IN_SEL_SFT) #define RK3308_ADC_CH1_IN_NONE (0x0 << RK3308_ADC_CH1_IN_SEL_SFT) -#define RK3308_ADC_MIC_BIAS_BUF_EN BIT(3) -#define RK3308_ADC_LEVEL_RANGE_MICBIAS_MAX 7 + +#define RK3308_ADC_MIC_BIAS_BUF_SFT 3 +#define RK3308_ADC_MIC_BIAS_BUF_EN (0x1 << RK3308_ADC_MIC_BIAS_BUF_SFT) +#define RK3308_ADC_MIC_BIAS_BUF_DIS (0x0 << RK3308_ADC_MIC_BIAS_BUF_SFT) #define RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT 0 #define RK3308_ADC_LEVEL_RANGE_MICBIAS_MSK (0x7 << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT) +/* + * The follow MICBIAS_VOLTs are based on the external reference voltage(Vref). + * For example, the Vref == 3.3V, the MICBIAS_VOLT_0_85 is equal: + * 3.3V * 0.85 = 2.805V. + */ +#define RK3308_ADC_MICBIAS_VOLT_0_85 (0x7 << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT) +#define RK3308_ADC_MICBIAS_VOLT_0_8 (0x6 << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT) +#define RK3308_ADC_MICBIAS_VOLT_0_75 (0x5 << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT) +#define RK3308_ADC_MICBIAS_VOLT_0_7 (0x4 << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT) +#define RK3308_ADC_MICBIAS_VOLT_0_65 (0x3 << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT) +#define RK3308_ADC_MICBIAS_VOLT_0_6 (0x2 << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT) +#define RK3308_ADC_MICBIAS_VOLT_0_55 (0x1 << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT) +#define RK3308_ADC_MICBIAS_VOLT_0_5 (0x0 << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT) /* RK3308_ADC_ANA_CON08 - REG: 0x0360 */ -#define RK3308_ADC_MICBIAS_CURRENT_EN BIT(4) +#define RK3308_ADC_MICBIAS_CURRENT_MSK (0x1 << 4) +#define RK3308_ADC_MICBIAS_CURRENT_EN (0x1 << 4) +#define RK3308_ADC_MICBIAS_CURRENT_DIS (0x0 << 4) /* RK3308_ADC_ANA_CON10 - REG: 0x0368 */ -#define RK3308_ADC_REF_EN BIT(7) +#define RK3308_ADC_REF_EN (0x1 << 7) +#define RK3308_ADC_REF_DIS (0x0 << 7) #define RK3308_ADC_CURRENT_CHARGE_SFT 0 #define RK3308_ADC_CURRENT_CHARGE_MSK (0x7f << RK3308_ADC_CURRENT_CHARGE_SFT) +/* + * 1: Choose the current I + * 0: Don't choose the current I + */ +#define RK3308_ADC_SEL_I(x) (x & 0x7f) /* RK3308_ADC_ANA_CON11 - REG: 0x036c */ -#define RK3308_ADC_ALCR_CON_GAIN_PGAR_EN BIT(1) -#define RK3308_ADC_ALCL_CON_GAIN_PGAL_EN BIT(0) +#define RK3308_ADC_ALCR_CON_GAIN_PGAR_MSK (0x1 << 1) +#define RK3308_ADC_ALCR_CON_GAIN_PGAR_EN (0x1 << 1) +#define RK3308_ADC_ALCR_CON_GAIN_PGAR_DIS (0x0 << 1) +#define RK3308_ADC_ALCL_CON_GAIN_PGAL_MSK (0x1 << 0) +#define RK3308_ADC_ALCL_CON_GAIN_PGAL_EN (0x1 << 0) +#define RK3308_ADC_ALCL_CON_GAIN_PGAL_DIS (0x0 << 0) /* RK3308_DAC_ANA_CON00 - REG: 0x0440 */ -#define RK3308_DAC_HEADPHONE_DET_EN BIT(1) -#define RK3308_DAC_CURRENT_EN BIT(0) +#define RK3308_DAC_HEADPHONE_DET_MSK (0x1 << 1) +#define RK3308_DAC_HEADPHONE_DET_EN (0x1 << 1) +#define RK3308_DAC_HEADPHONE_DET_DIS (0x0 << 1) +#define RK3308_DAC_CURRENT_MSK (0x1 << 0) +#define RK3308_DAC_CURRENT_EN (0x1 << 0) +#define RK3308_DAC_CURRENT_DIS (0x0 << 0) /* RK3308_DAC_ANA_CON01 - REG: 0x0444 */ -#define RK3308_DAC_BUF_REF_R_EN BIT(6) -#define RK3308_DAC_BUF_REF_L_EN BIT(2) +#define RK3308_DAC_BUF_REF_R_MSK (0x1 << 6) +#define RK3308_DAC_BUF_REF_R_EN (0x1 << 6) +#define RK3308_DAC_BUF_REF_R_DIS (0x0 << 6) #define RK3308_DAC_HPOUT_POP_SOUND_R_SFT 4 +#define RK3308_DAC_HPOUT_POP_SOUND_R_MSK (0x3 << RK3308_DAC_HPOUT_POP_SOUND_R_SFT) +#define RK3308_DAC_HPOUT_POP_SOUND_R_WORK (0x2 << RK3308_DAC_HPOUT_POP_SOUND_R_SFT) +#define RK3308_DAC_HPOUT_POP_SOUND_R_INIT (0x1 << RK3308_DAC_HPOUT_POP_SOUND_R_SFT) +#define RK3308_DAC_BUF_REF_L_MSK (0x1 << 2) +#define RK3308_DAC_BUF_REF_L_EN (0x1 << 2) +#define RK3308_DAC_BUF_REF_L_DIS (0x0 << 2) #define RK3308_DAC_HPOUT_POP_SOUND_L_SFT 0 -// unshifted values for both L and R: -#define RK3308_DAC_HPOUT_POP_SOUND_x_MSK 0x3 -#define RK3308_DAC_HPOUT_POP_SOUND_x_WORK 0x2 -#define RK3308_DAC_HPOUT_POP_SOUND_x_INIT 0x1 +#define RK3308_DAC_HPOUT_POP_SOUND_L_MSK (0x3 << RK3308_DAC_HPOUT_POP_SOUND_L_SFT) +#define RK3308_DAC_HPOUT_POP_SOUND_L_WORK (0x2 << RK3308_DAC_HPOUT_POP_SOUND_L_SFT) +#define RK3308_DAC_HPOUT_POP_SOUND_L_INIT (0x1 << RK3308_DAC_HPOUT_POP_SOUND_L_SFT) /* RK3308_DAC_ANA_CON02 - REG: 0x0448 */ -#define RK3308_DAC_R_DAC_WORK BIT(7) -#define RK3308_DAC_R_DAC_EN BIT(6) -#define RK3308_DAC_R_CLK_EN BIT(5) -#define RK3308_DAC_R_REF_EN BIT(4) -#define RK3308_DAC_L_DAC_WORK BIT(3) -#define RK3308_DAC_L_DAC_EN BIT(2) -#define RK3308_DAC_L_CLK_EN BIT(1) -#define RK3308_DAC_L_REF_EN BIT(0) +#define RK3308_DAC_R_DAC_WORK (0x1 << 7) +#define RK3308_DAC_R_DAC_INIT (0x0 << 7) +#define RK3308_DAC_R_DAC_EN (0x1 << 6) +#define RK3308_DAC_R_DAC_DIS (0x0 << 6) +#define RK3308_DAC_R_CLK_EN (0x1 << 5) +#define RK3308_DAC_R_CLK_DIS (0x0 << 5) +#define RK3308_DAC_R_REF_EN (0x1 << 4) +#define RK3308_DAC_R_REF_DIS (0x0 << 4) +#define RK3308_DAC_L_DAC_WORK (0x1 << 3) +#define RK3308_DAC_L_DAC_INIT (0x0 << 3) +#define RK3308_DAC_L_DAC_EN (0x1 << 2) +#define RK3308_DAC_L_DAC_DIS (0x0 << 2) +#define RK3308_DAC_L_CLK_EN (0x1 << 1) +#define RK3308_DAC_L_CLK_DIS (0x0 << 1) +#define RK3308_DAC_L_REF_EN (0x1 << 0) +#define RK3308_DAC_L_REF_DIS (0x0 << 0) /* RK3308_DAC_ANA_CON03 - REG: 0x044c */ -#define RK3308_DAC_R_HPOUT_WORK BIT(6) -#define RK3308_DAC_R_HPOUT_EN BIT(5) -#define RK3308_DAC_R_HPOUT_MUTE_SFT 4 -#define RK3308_DAC_L_HPOUT_WORK BIT(2) -#define RK3308_DAC_L_HPOUT_EN BIT(1) -#define RK3308_DAC_L_HPOUT_MUTE_SFT 0 +#define RK3308_DAC_R_HPOUT_WORK (0x1 << 6) +#define RK3308_DAC_R_HPOUT_INIT (0x0 << 6) +#define RK3308_DAC_R_HPOUT_EN (0x1 << 5) +#define RK3308_DAC_R_HPOUT_DIS (0x0 << 5) +#define RK3308_DAC_R_HPOUT_UNMUTE (0x1 << 4) +#define RK3308_DAC_R_HPOUT_MUTE (0x0 << 4) +#define RK3308_DAC_L_HPOUT_WORK (0x1 << 2) +#define RK3308_DAC_L_HPOUT_INIT (0x0 << 2) +#define RK3308_DAC_L_HPOUT_EN (0x1 << 1) +#define RK3308_DAC_L_HPOUT_DIS (0x0 << 1) +#define RK3308_DAC_L_HPOUT_UNMUTE (0x1 << 0) +#define RK3308_DAC_L_HPOUT_MUTE (0x0 << 0) /* RK3308_DAC_ANA_CON04 - REG: 0x0450 */ -#define RK3308_DAC_x_LINEOUT_GAIN_MAX 0x3 +#define RK3308_DAC_R_LINEOUT_GAIN_MAX 0x3 #define RK3308_DAC_R_LINEOUT_GAIN_SFT 6 #define RK3308_DAC_R_LINEOUT_GAIN_MSK (0x3 << RK3308_DAC_R_LINEOUT_GAIN_SFT) #define RK3308_DAC_R_LINEOUT_GAIN_0DB (0x3 << RK3308_DAC_R_LINEOUT_GAIN_SFT) #define RK3308_DAC_R_LINEOUT_GAIN_NDB_1_5 (0x2 << RK3308_DAC_R_LINEOUT_GAIN_SFT) #define RK3308_DAC_R_LINEOUT_GAIN_NDB_3 (0x1 << RK3308_DAC_R_LINEOUT_GAIN_SFT) #define RK3308_DAC_R_LINEOUT_GAIN_NDB_6 (0x0 << RK3308_DAC_R_LINEOUT_GAIN_SFT) -#define RK3308_DAC_R_LINEOUT_MUTE_SFT 5 -#define RK3308_DAC_R_LINEOUT_EN BIT(4) +#define RK3308_DAC_R_LINEOUT_UNMUTE (0x1 << 5) +#define RK3308_DAC_R_LINEOUT_MUTE (0x0 << 5) +#define RK3308_DAC_R_LINEOUT_EN (0x1 << 4) +#define RK3308_DAC_R_LINEOUT_DIS (0x0 << 4) +#define RK3308_DAC_L_LINEOUT_GAIN_MAX 0x3 #define RK3308_DAC_L_LINEOUT_GAIN_SFT 2 #define RK3308_DAC_L_LINEOUT_GAIN_MSK (0x3 << RK3308_DAC_L_LINEOUT_GAIN_SFT) #define RK3308_DAC_L_LINEOUT_GAIN_0DB (0x3 << RK3308_DAC_L_LINEOUT_GAIN_SFT) #define RK3308_DAC_L_LINEOUT_GAIN_NDB_1_5 (0x2 << RK3308_DAC_L_LINEOUT_GAIN_SFT) #define RK3308_DAC_L_LINEOUT_GAIN_NDB_3 (0x1 << RK3308_DAC_L_LINEOUT_GAIN_SFT) #define RK3308_DAC_L_LINEOUT_GAIN_NDB_6 (0x0 << RK3308_DAC_L_LINEOUT_GAIN_SFT) -#define RK3308_DAC_L_LINEOUT_MUTE_SFT 1 -#define RK3308_DAC_L_LINEOUT_EN BIT(0) +#define RK3308_DAC_L_LINEOUT_UNMUTE (0x1 << 1) +#define RK3308_DAC_L_LINEOUT_MUTE (0x0 << 1) +#define RK3308_DAC_L_LINEOUT_EN (0x1 << 0) +#define RK3308_DAC_L_LINEOUT_DIS (0x0 << 0) /* RK3308_DAC_ANA_CON05 - REG: 0x0454, step is 1.5db */ +#define RK3308_DAC_L_HPOUT_GAIN_MAX 0x1e +#define RK3308_DAC_L_HPOUT_GAIN_SFT 0 +#define RK3308_DAC_L_HPOUT_GAIN_MSK (0x1f << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_PDB_6 (0x1e << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_PDB_4_5 (0x1d << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_PDB_3 (0x1c << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_PDB_1_5 (0x1b << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_0DB (0x1a << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_1_5 (0x19 << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_3 (0x18 << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_4_5 (0x17 << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_6 (0x16 << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_7_5 (0x15 << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_9 (0x14 << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_10_5 (0x13 << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_12 (0x12 << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_13_5 (0x11 << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_15 (0x10 << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_16_5 (0x0f << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_18 (0x0e << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_19_5 (0x0d << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_21 (0x0c << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_22_5 (0x0b << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_24 (0x0a << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_25_5 (0x09 << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_27 (0x08 << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_28_5 (0x07 << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_30 (0x06 << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_31_5 (0x05 << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_33 (0x04 << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_34_5 (0x03 << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_36 (0x02 << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_37_5 (0x01 << RK3308_DAC_L_HPOUT_GAIN_SFT) +#define RK3308_DAC_L_HPOUT_GAIN_NDB_39 (0x00 << RK3308_DAC_L_HPOUT_GAIN_SFT) + /* RK3308_DAC_ANA_CON06 - REG: 0x0458, step is 1.5db */ -#define RK3308_DAC_x_HPOUT_GAIN_MAX 0x1e -#define RK3308_DAC_x_HPOUT_GAIN_SFT 0 -#define RK3308_DAC_x_HPOUT_GAIN_MSK (0x1f << RK3308_DAC_x_HPOUT_GAIN_SFT) -#define RK3308_DAC_x_HPOUT_GAIN_MIN (0x00 << RK3308_DAC_x_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_MAX 0x1e +#define RK3308_DAC_R_HPOUT_GAIN_SFT 0 +#define RK3308_DAC_R_HPOUT_GAIN_MSK (0x1f << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_PDB_6 (0x1e << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_PDB_4_5 (0x1d << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_PDB_3 (0x1c << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_PDB_1_5 (0x1b << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_0DB (0x1a << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_1_5 (0x19 << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_3 (0x18 << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_4_5 (0x17 << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_6 (0x16 << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_7_5 (0x15 << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_9 (0x14 << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_10_5 (0x13 << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_12 (0x12 << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_13_5 (0x11 << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_15 (0x10 << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_16_5 (0x0f << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_18 (0x0e << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_19_5 (0x0d << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_21 (0x0c << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_22_5 (0x0b << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_24 (0x0a << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_25_5 (0x09 << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_27 (0x08 << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_28_5 (0x07 << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_30 (0x06 << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_31_5 (0x05 << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_33 (0x04 << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_34_5 (0x03 << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_36 (0x02 << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_37_5 (0x01 << RK3308_DAC_R_HPOUT_GAIN_SFT) +#define RK3308_DAC_R_HPOUT_GAIN_NDB_39 (0x00 << RK3308_DAC_R_HPOUT_GAIN_SFT) /* RK3308_DAC_ANA_CON07 - REG: 0x045c */ #define RK3308_DAC_R_HPOUT_DRV_SFT 4 @@ -534,36 +1007,51 @@ #define RK3308_DAC_R_HPMIX_LINEIN (0x2 << RK3308_DAC_R_HPMIX_SEL_SFT) #define RK3308_DAC_R_HPMIX_I2S (0x1 << RK3308_DAC_R_HPMIX_SEL_SFT) #define RK3308_DAC_R_HPMIX_NONE (0x0 << RK3308_DAC_R_HPMIX_SEL_SFT) +#define RK3308_DAC_R_HPMIX_GAIN_MIN 0x1 +#define RK3308_DAC_R_HPMIX_GAIN_MAX 0x2 +#define RK3308_DAC_R_HPMIX_GAIN_SFT 4 +#define RK3308_DAC_R_HPMIX_GAIN_MSK (0x3 << RK3308_DAC_R_HPMIX_GAIN_SFT) +#define RK3308_DAC_R_HPMIX_GAIN_0DB (0x2 << RK3308_DAC_R_HPMIX_GAIN_SFT) +#define RK3308_DAC_R_HPMIX_GAIN_NDB_6 (0x1 << RK3308_DAC_R_HPMIX_GAIN_SFT) #define RK3308_DAC_L_HPMIX_SEL_SFT 2 #define RK3308_DAC_L_HPMIX_SEL_MSK (0x3 << RK3308_DAC_L_HPMIX_SEL_SFT) #define RK3308_DAC_L_HPMIX_LINEIN_I2S (0x3 << RK3308_DAC_L_HPMIX_SEL_SFT) #define RK3308_DAC_L_HPMIX_LINEIN (0x2 << RK3308_DAC_L_HPMIX_SEL_SFT) #define RK3308_DAC_L_HPMIX_I2S (0x1 << RK3308_DAC_L_HPMIX_SEL_SFT) #define RK3308_DAC_L_HPMIX_NONE (0x0 << RK3308_DAC_L_HPMIX_SEL_SFT) -#define RK3308_DAC_x_HPMIX_GAIN_MIN 0x1 /* 0x0 and 0x3 are reserved */ -#define RK3308_DAC_x_HPMIX_GAIN_MAX 0x2 -#define RK3308_DAC_R_HPMIX_GAIN_SFT 4 -#define RK3308_DAC_R_HPMIX_GAIN_MSK (0x3 << RK3308_DAC_R_HPMIX_GAIN_SFT) -#define RK3308_DAC_R_HPMIX_GAIN_0DB (0x2 << RK3308_DAC_R_HPMIX_GAIN_SFT) -#define RK3308_DAC_R_HPMIX_GAIN_NDB_6 (0x1 << RK3308_DAC_R_HPMIX_GAIN_SFT) +#define RK3308_DAC_L_HPMIX_GAIN_MIN 0x1 +#define RK3308_DAC_L_HPMIX_GAIN_MAX 0x2 #define RK3308_DAC_L_HPMIX_GAIN_SFT 0 #define RK3308_DAC_L_HPMIX_GAIN_MSK (0x3 << RK3308_DAC_L_HPMIX_GAIN_SFT) #define RK3308_DAC_L_HPMIX_GAIN_0DB (0x2 << RK3308_DAC_L_HPMIX_GAIN_SFT) #define RK3308_DAC_L_HPMIX_GAIN_NDB_6 (0x1 << RK3308_DAC_L_HPMIX_GAIN_SFT) /* RK3308_DAC_ANA_CON13 - REG: 0x0474 */ -#define RK3308_DAC_R_HPMIX_UNMUTE BIT(6) -#define RK3308_DAC_R_HPMIX_WORK BIT(5) -#define RK3308_DAC_R_HPMIX_EN BIT(4) -#define RK3308_DAC_L_HPMIX_UNMUTE BIT(2) -#define RK3308_DAC_L_HPMIX_WORK BIT(1) -#define RK3308_DAC_L_HPMIX_EN BIT(0) +#define RK3308_DAC_R_HPMIX_UNMUTE (0x1 << 6) +#define RK3308_DAC_R_HPMIX_MUTE (0x0 << 6) +#define RK3308_DAC_R_HPMIX_WORK (0x1 << 5) +#define RK3308_DAC_R_HPMIX_INIT (0x0 << 5) +#define RK3308_DAC_R_HPMIX_EN (0x1 << 4) +#define RK3308_DAC_R_HPMIX_DIS (0x0 << 4) +#define RK3308_DAC_L_HPMIX_UNMUTE (0x1 << 2) +#define RK3308_DAC_L_HPMIX_MUTE (0x0 << 2) +#define RK3308_DAC_L_HPMIX_WORK (0x1 << 1) +#define RK3308_DAC_L_HPMIX_INIT (0x0 << 1) +#define RK3308_DAC_L_HPMIX_EN (0x1 << 0) +#define RK3308_DAC_L_HPMIX_DIS (0x0 << 0) /* RK3308_DAC_ANA_CON14 - REG: 0x0478 */ #define RK3308_DAC_VCM_LINEOUT_EN (0x1 << 4) +#define RK3308_DAC_VCM_LINEOUT_DIS (0x0 << 4) #define RK3308_DAC_CURRENT_CHARGE_SFT 0 #define RK3308_DAC_CURRENT_CHARGE_MSK (0xf << RK3308_DAC_CURRENT_CHARGE_SFT) +/* + * 1: Choose the current I + * 0: Don't choose the current I + */ +#define RK3308_DAC_SEL_I(x) (x & 0xf) + /* RK3308_DAC_ANA_CON15 - REG: 0x047C */ #define RK3308_DAC_LINEOUT_POP_SOUND_R_SFT 4 #define RK3308_DAC_LINEOUT_POP_SOUND_R_MSK (0x3 << RK3308_DAC_LINEOUT_POP_SOUND_R_SFT) @@ -576,4 +1064,6 @@ #define RK3308_DAC_L_SEL_DC_FROM_VCM (0x1 << RK3308_DAC_LINEOUT_POP_SOUND_L_SFT) #define RK3308_DAC_L_SEL_LINEOUT_FROM_INTERNAL (0x0 << RK3308_DAC_LINEOUT_POP_SOUND_L_SFT) +#define RK3308_HIFI 0x0 + #endif /* __RK3308_CODEC_H__ */ diff --git a/sound/soc/codecs/rk3308_codec_provider.h b/sound/soc/codecs/rk3308_codec_provider.h new file mode 100644 index 000000000000..111111111111 --- /dev/null +++ b/sound/soc/codecs/rk3308_codec_provider.h @@ -0,0 +1,28 @@ +/* + * rk3308_codec_provider.h -- RK3308 ALSA Soc Audio Driver + * + * Copyright (c) 2018, Fuzhou Rockchip Electronics Co., Ltd All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef __RK3308_CODEC_PROVIDER_H__ +#define __RK3308_CODEC_PROVIDER_H__ + +#ifdef CONFIG_SND_SOC_RK3308 +extern void (*rk3308_codec_set_jack_detect_cb)(struct snd_soc_component *component, + struct snd_soc_jack *hpdet_jack); +#endif + +#endif /* __RK3308_CODEC_PROVIDER_H__ */ -- Armbian