/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2018 MediaTek Inc. */ /******************************************************************************* * * Filename: * --------- * mtk_soc_codec_63xx * * Project: * -------- * * * Description: * ------------ * Audio codec stub file * * Author: * ------- * Chipeng Chang * *------------------------------------------------------------------------------ * * ******************************************************************************/ /***************************************************************************** * C O M P I L E R F L A G S *****************************************************************************/ /***************************************************************************** * E X T E R N A L R E F E R E N C E S *****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_MTK_ACCDET #include "accdet.h" #endif #include #include "mtk-auddrv-def.h" #include "mtk-auddrv-ana.h" #include "mtk-auddrv-gpio.h" #include "mtk-soc-analog-type.h" #include "mtk-soc-codec-63xx.h" #ifdef CONFIG_MTK_VOW_SUPPORT #include #endif #include #include #ifdef CONFIG_MT8183_QUERY_PCB_ID_METHOD #include #endif #define ANALOG_HPTRIM /* HP IMPEDANCE Current Calibration from EFUSE */ /* #define EFUSE_HP_IMPEDANCE */ /* static function declaration */ static bool AudioPreAmp1_Sel(int Mul_Sel); static bool GetAdcStatus(void); static bool TurnOnVOWDigitalHW(bool enable); static void TurnOffDacPower(void); static void TurnOnDacPower(int device); static void setDlMtkifSrc(bool enable); #ifndef ANALOG_HPTRIM static int SetDcCompenSation(bool enable); #endif static void Voice_Amp_Change(bool enable); static void Speaker_Amp_Change(bool enable); static bool TurnOnVOWADcPower(int MicType, bool enable); #ifdef CONFIG_MTK_VOW_SUPPORT static void TurnOnVOWPeriodicOnOff(int MicType, int On_period, int enable); static void VOW_GPIO_Enable(bool enable); static void VOW_Pwr_Enable(int MicType, bool enable); static void VOW_DCC_CLK_Enable(bool enable); static void VOW_MIC_DCC_Enable(int MicType, bool enable); static void VOW_MIC_ACC_Enable(int MicType, bool enable); static void VOW13MCK_Enable(bool enable); static void VOW32KCK_Enable(bool enable); #endif static struct mt6358_codec_priv *mCodec_data; static unsigned int mBlockSampleRate[ANA_DEV_IN_OUT_MAX] = { 48000, 48000, 48000 }; #define MAX_DL_SAMPLE_RATE (192000) #define MAX_UL_SAMPLE_RATE (192000) static DEFINE_MUTEX(Ana_Ctrl_Mutex); static DEFINE_MUTEX(Ana_buf_Ctrl_Mutex); static DEFINE_MUTEX(Ana_Clk_Mutex); static DEFINE_MUTEX(Ana_Power_Mutex); static DEFINE_MUTEX(AudAna_lock); static int mAudio_Analog_Mic1_mode = ANA_UL_MODE_ACC; static int mAudio_Analog_Mic2_mode = ANA_UL_MODE_ACC; static int mAudio_Analog_Mic3_mode = ANA_UL_MODE_ACC; static int mAudio_Analog_Mic4_mode = ANA_UL_MODE_ACC; static int mAudio_Vow_Analog_Func_Enable; static int mAudio_Vow_Digital_Func_Enable; enum { AUXADC_AVG_1, AUXADC_AVG_4, AUXADC_AVG_8, AUXADC_AVG_16, AUXADC_AVG_32, AUXADC_AVG_64, AUXADC_AVG_128, AUXADC_AVG_256, }; enum { MIC_BIAS_1p7 = 0, MIC_BIAS_1p8, MIC_BIAS_1p9, MIC_BIAS_2p0, MIC_BIAS_2p1, MIC_BIAS_2p5, MIC_BIAS_2p6, MIC_BIAS_2p7, }; enum { DL_GAIN_8DB = 0, DL_GAIN_0DB = 8, DL_GAIN_N_1DB = 9, DL_GAIN_N_10DB = 18, DL_GAIN_N_40DB = 0x1f, }; #define DL_GAIN_N_10DB_REG (DL_GAIN_N_10DB << 7 | DL_GAIN_N_10DB) #define DL_GAIN_N_40DB_REG (DL_GAIN_N_40DB << 7 | DL_GAIN_N_40DB) #define DL_GAIN_REG_MASK 0x0f9f enum hp_depop_flow { HP_DEPOP_FLOW_DEPOP_HW, HP_DEPOP_FLOW_33OHM, HP_DEPOP_FLOW_DEPOP_HW_33OHM, HP_DEPOP_FLOW_NONE, }; static unsigned int mUseHpDepopFlow; enum DBG_TYPE { DBG_DCTRIM_BYPASS_4POLE = 0x1 << 0, DBG_DCTRIM_4POLE_LOG = 0x1 << 1, }; enum DBG_TYPE codec_debug_enable; static int low_power_mode; #ifndef CONFIG_FPGA_EARLY_PORTING #ifdef EFUSE_HP_TRIM static unsigned int RG_AUDHPLTRIM_VAUDP15, RG_AUDHPRTRIM_VAUDP15, RG_AUDHPLFINETRIM_VAUDP15, RG_AUDHPRFINETRIM_VAUDP15, RG_AUDHPLTRIM_VAUDP15_SPKHP, RG_AUDHPRTRIM_VAUDP15_SPKHP, RG_AUDHPLFINETRIM_VAUDP15_SPKHP, RG_AUDHPRFINETRIM_VAUDP15_SPKHP; #endif #endif static int mAdc_Power_Mode; static int apply_n12db_gain; static unsigned int dAuxAdcChannel = 16; static const int mDcOffsetTrimChannel = 9; static bool mInitCodec; static bool mIsNeedPullDown = true; int (*enable_dc_compensation)(bool enable) = NULL; int (*set_lch_dc_compensation)(int value) = NULL; int (*set_rch_dc_compensation)(int value) = NULL; int (*set_ap_dmic)(bool enable) = NULL; int (*set_hp_impedance_ctl)(bool enable) = NULL; #ifdef CONFIG_MTK_VOW_SUPPORT static unsigned int MicbiasRef, GetMicbias; #endif /* #ifdef CONFIG_MTK_VOW_SUPPORT */ static int reg_AFE_VOW_CFG0; /* VOW AMPREF Setting */ static int reg_AFE_VOW_CFG1; /* VOW A,B timeout initial value (timer) */ static int reg_AFE_VOW_CFG2 = 0x2222; /* VOW A,B value setting (BABA) */ /* alhpa and beta K value setting (beta_rise,fall,alpha_rise,fall) */ static int reg_AFE_VOW_CFG3 = 0x8767; /* gamma K value setting (gamma), bit4:8 should not modify */ static int reg_AFE_VOW_CFG4 = 0x006E; static int reg_AFE_VOW_CFG5 = 0x0001; /* N mini value setting (Nmin) */ static int reg_AFE_VOW_PERIODIC; /* Periodic On/Off setting (On percent)*/ static bool mIsVOWOn; /* VOW using */ enum audio_vow_mic_type { VOW_MIC_TYPE_Handset_AMIC = 0, VOW_MIC_TYPE_Headset_MIC, VOW_MIC_TYPE_Handset_DMIC, /* 1P6 */ VOW_MIC_TYPE_Handset_DMIC_800K, /* 800K */ VOW_MIC_TYPE_Handset_AMIC_DCC, /* DCC mems */ VOW_MIC_TYPE_Headset_MIC_DCC, VOW_MIC_TYPE_Handset_AMIC_DCCECM, /* DCC ECM, dual differential */ VOW_MIC_TYPE_Headset_MIC_DCCECM,/* DCC ECM, signal differential */ VOW_MIC_TYPE_Handset_DMIC_VENDOR01, /* DMIC Vendor01 */ VOW_MIC_TYPE_NUM }; /* Jogi: Need? @{ */ #define SND_SOC_ADV_MT_FMTS (\ SNDRV_PCM_FMTBIT_S16_LE |\ SNDRV_PCM_FMTBIT_S16_BE |\ SNDRV_PCM_FMTBIT_U16_LE |\ SNDRV_PCM_FMTBIT_U16_BE |\ SNDRV_PCM_FMTBIT_S24_LE |\ SNDRV_PCM_FMTBIT_S24_BE |\ SNDRV_PCM_FMTBIT_U24_LE |\ SNDRV_PCM_FMTBIT_U24_BE |\ SNDRV_PCM_FMTBIT_S32_LE |\ SNDRV_PCM_FMTBIT_S32_BE |\ SNDRV_PCM_FMTBIT_U32_LE |\ SNDRV_PCM_FMTBIT_U32_BE) #define SND_SOC_STD_MT_FMTS (\ SNDRV_PCM_FMTBIT_S16_LE |\ SNDRV_PCM_FMTBIT_S16_BE |\ SNDRV_PCM_FMTBIT_U16_LE |\ SNDRV_PCM_FMTBIT_U16_BE) /* @} Build pass: */ #define SOC_HIGH_USE_RATE (SNDRV_PCM_RATE_CONTINUOUS |\ SNDRV_PCM_RATE_8000_192000) #ifdef CONFIG_MTK_VOW_SUPPORT /* VOW_MIC_TYPE_Handset_AMIC_DCC */ /* VOW_MIC_TYPE_Handset_AMIC_DCCECM */ static const unsigned short Handset_AMIC_DCC_PeriodicOnOff[7][22] = { { 0x8000, 0x8000, 0x81AA, 0x0000, 0x0000, 0x0000, 0x0000, 0x8000, 0x0000, 0x81EC, 0x0000, 0x1917, 0x8021, 0x1917, 0x0000, 0x0000, 0x0000, 0x0000, 0x1917, 0x0000, 0x18F6, 0x0000 },/* 90% */ { 0x828F, 0x828F, 0x8439, 0x0000, 0x0000, 0x0000, 0x0000, 0x828F, 0x0000, 0x847B, 0x0000, 0x1917, 0x82B0, 0x1917, 0x0000, 0x0000, 0x0000, 0x0000, 0x1917, 0x0000, 0x18F6, 0x0000 },/* 80% */ { 0x851F, 0x851F, 0x86C9, 0x0000, 0x0000, 0x0000, 0x0000, 0x851F, 0x0000, 0x870A, 0x0000, 0x1917, 0x853F, 0x1917, 0x0000, 0x0000, 0x0000, 0x0000, 0x1917, 0x0000, 0x18F6, 0x0000 },/* 70% */ { 0x87AE, 0x87AE, 0x8958, 0x0000, 0x0000, 0x80A4, 0x0000, 0x87AE, 0xC0A4, 0x899A, 0x0000, 0x1917, 0x87CF, 0x1917, 0x0000, 0x0000, 0x1917, 0x0000, 0x1917, 0x1917, 0x18F6, 0x0000 },/* 60% */ { 0x8A3D, 0x8A3D, 0x8BE7, 0x0000, 0x0000, 0x8333, 0x0000, 0x8A3D, 0xC333, 0x8C29, 0x0000, 0x1917, 0x8A5E, 0x1917, 0x0000, 0x0000, 0x1917, 0x0000, 0x1917, 0x1917, 0x18F6, 0x0000 },/* 50% */ { 0x8CCD, 0x8CCD, 0x8E77, 0x0000, 0x0000, 0x85C3, 0x0000, 0x8CCD, 0xC5C3, 0x8EB8, 0x0000, 0x1917, 0x8CEE, 0x1917, 0x0000, 0x0000, 0x1917, 0x0000, 0x1917, 0x1917, 0x18F6, 0x0000 },/* 40% */ { 0x8F5C, 0x8F5C, 0x9106, 0x0000, 0x0000, 0x8852, 0x0000, 0x8F5C, 0xC852, 0x9148, 0x0000, 0x1917, 0x8F7D, 0x1917, 0x0000, 0x0000, 0x1917, 0x0000, 0x1917, 0x1917, 0x18F6, 0x0000 } /* 30% */ }; /* VOW_MIC_TYPE_Headset_MIC_DCC */ /* VOW_MIC_TYPE_Headset_MIC_DCCECM */ static const unsigned short Headset_MIC_DCC_PeriodicOnOff[7][22] = { { 0x8000, 0x8000, 0x81AA, 0x0000, 0x0000, 0x0000, 0x0000, 0x8000, 0xC000, 0x81EC, 0x0000, 0x1917, 0x8021, 0x1917, 0x0000, 0x0000, 0x0000, 0x0000, 0x1917, 0x1917, 0x18F6, 0x0000 },/* 90% */ { 0x8148, 0x8148, 0x82F2, 0x0000, 0x0000, 0x0000, 0x80A4, 0x8148, 0xC0A4, 0x8333, 0x0000, 0x17CF, 0x8168, 0x17CF, 0x0000, 0x0000, 0x0000, 0x17CF, 0x17CF, 0x17CF, 0x17AE, 0x0000 },/* 80% */ { 0x828F, 0x828F, 0x8439, 0x0000, 0x0000, 0x0000, 0x81EC, 0x828F, 0xC1EC, 0x847B, 0x0000, 0x1687, 0x82B0, 0x1687, 0x0000, 0x0000, 0x0000, 0x1687, 0x1687, 0x1687, 0x1666, 0x0000 },/* 70% */ { 0x83D7, 0x83D7, 0x8581, 0x0000, 0x0000, 0x0000, 0x8333, 0x83D7, 0xC333, 0x85C3, 0x0000, 0x153F, 0x83F8, 0x153F, 0x0000, 0x0000, 0x0000, 0x153F, 0x153F, 0x153F, 0x151F, 0x0000 },/* 60% */ { 0x851F, 0x851F, 0x86C9, 0x0000, 0x0000, 0x0000, 0x847B, 0x851F, 0xC47B, 0x870A, 0x0000, 0x13F8, 0x853F, 0x13F8, 0x0000, 0x0000, 0x0000, 0x13F8, 0x13F8, 0x13F8, 0x13D7, 0x0000 },/* 50% */ { 0x8666, 0x8666, 0x8810, 0x0000, 0x0000, 0x0000, 0x85C3, 0x8666, 0xC5C3, 0x8852, 0x0000, 0x12B0, 0x8687, 0x12B0, 0x0000, 0x0000, 0x0000, 0x12B0, 0x12B0, 0x12B0, 0x128F, 0x0000 },/* 40% */ { 0x87AE, 0x87AE, 0x8958, 0x0000, 0x0000, 0x0000, 0x870A, 0x87AE, 0xC70A, 0x899A, 0x0000, 0x1168, 0x87CF, 0x1168, 0x0000, 0x0000, 0x0000, 0x1168, 0x1168, 0x1168, 0x1148, 0x0000 } /* 30% */ }; #endif static int mAudio_VOW_Mic_type = VOW_MIC_TYPE_Handset_AMIC; static void Audio_Amp_Change(int channels, bool enable); static void SavePowerState(void) { int i = 0; for (i = 0; i < ANA_DEV_MAX; i++) { mCodec_data->backup_dev_power[i] = mCodec_data->dev_power[i]; } } static void RestorePowerState(void) { int i = 0; for (i = 0; i < ANA_DEV_MAX; i++) { mCodec_data->dev_power[i] = mCodec_data->backup_dev_power[i]; } } static bool GetDLStatus(void) { int i = 0; for (i = 0; i < ANA_DEV_2IN1_SPK; i++) { if (mCodec_data->dev_power[i] == true) return true; } return false; } static bool mAnaSuspend; void SetAnalogSuspend(bool bEnable) { pr_debug("%s bEnable ==%d mAnaSuspend = %d\n", __func__, bEnable, mAnaSuspend); if ((bEnable == true) && (mAnaSuspend == false)) { /*Ana_Log_Print();*/ SavePowerState(); if (mCodec_data->dev_power[ANA_DEV_OUT_HEADSETL] == true) { mCodec_data->dev_power[ANA_DEV_OUT_HEADSETL] = false; Audio_Amp_Change(AUDIO_ANALOG_CHANNELS_LEFT1, false); } if (mCodec_data->dev_power[ANA_DEV_OUT_HEADSETR] == true) { mCodec_data->dev_power[ANA_DEV_OUT_HEADSETR] = false; Audio_Amp_Change(AUDIO_ANALOG_CHANNELS_RIGHT1, false); } if (mCodec_data->dev_power[ANA_DEV_OUT_EARPIECEL] == true) { mCodec_data->dev_power[ANA_DEV_OUT_EARPIECEL] = false; Voice_Amp_Change(false); } if (mCodec_data->dev_power[ANA_DEV_OUT_SPEAKERL] == true) { mCodec_data->dev_power[ANA_DEV_OUT_SPEAKERL] = false; Speaker_Amp_Change(false); } /*Ana_Log_Print();*/ mAnaSuspend = true; } else if ((bEnable == false) && (mAnaSuspend == true)) { /*Ana_Log_Print();*/ if (mCodec_data->backup_dev_power[ANA_DEV_OUT_HEADSETL] == true) { Audio_Amp_Change(AUDIO_ANALOG_CHANNELS_LEFT1, true); mCodec_data->dev_power[ANA_DEV_OUT_HEADSETL] = true; } if (mCodec_data->backup_dev_power[ANA_DEV_OUT_HEADSETR] == true) { Audio_Amp_Change(AUDIO_ANALOG_CHANNELS_RIGHT1, true); mCodec_data->dev_power[ANA_DEV_OUT_HEADSETR] = false; } if (mCodec_data->backup_dev_power[ANA_DEV_OUT_EARPIECEL] == true) { Voice_Amp_Change(true); mCodec_data->dev_power[ANA_DEV_OUT_EARPIECEL] = false; } if (mCodec_data->backup_dev_power[ANA_DEV_OUT_SPEAKERL] == true) { Speaker_Amp_Change(true); mCodec_data->dev_power[ANA_DEV_OUT_SPEAKERL] = false; } RestorePowerState(); /*Ana_Log_Print();*/ mAnaSuspend = false; } } static int audck_buf_Count; void audckbufEnable(bool enable) { mutex_lock(&Ana_buf_Ctrl_Mutex); if (enable) { if (audck_buf_Count == 0) { Ana_Set_Reg(DCXO_CW14, 0x1 << 13, 0x1 << 13); pr_debug("-PMIC DCXO XO_AUDIO_EN_M enable, DCXO_CW14 = 0x%x\n", Ana_Get_Reg(DCXO_CW14)); } audck_buf_Count++; } else { audck_buf_Count--; if (audck_buf_Count == 0) { Ana_Set_Reg(DCXO_CW14, 0x0 << 13, 0x1 << 13); pr_debug("-PMIC DCXO XO_AUDIO_EN_M disable, DCXO_CW14 = 0x%x\n", Ana_Get_Reg(DCXO_CW14)); /* if didn't close, 60uA leak at audio analog */ } if (audck_buf_Count < 0) { pr_warn("audck_buf_Count count < 0\n"); audck_buf_Count = 0; } } mutex_unlock(&Ana_buf_Ctrl_Mutex); } static int ClsqCount; static void ClsqEnable(bool enable) { mutex_lock(&AudAna_lock); if (enable) { if (ClsqCount == 0) { /* Enable CLKSQ, Audio CLK source: internal CLK DCXO */ Ana_Set_Reg(AUDENC_ANA_CON6, 0x0001, 0x0003); } ClsqCount++; } else { ClsqCount--; if (ClsqCount < 0) { pr_warn("%s(), count <0\n", __func__); ClsqCount = 0; } if (ClsqCount == 0) { /* disable CLKSQ */ Ana_Set_Reg(AUDENC_ANA_CON6, 0x0000, 0x0003); } } mutex_unlock(&AudAna_lock); } static int TopCkCount; static void Topck_Enable(bool enable) { mutex_lock(&Ana_Clk_Mutex); if (enable == true) { if (TopCkCount == 0) { Ana_Set_Reg(AUD_TOP_CKPDN_CON0, 0x0, 0x66); /* Turn on AUDNCP_CLKDIV engine clock,Turn on AUD 26M */ } TopCkCount++; } else { TopCkCount--; if (TopCkCount == 0) { Ana_Set_Reg(AUD_TOP_CKPDN_CON0, 0x66, 0x66); /* Turn off AUDNCP_CLKDIV engine clock, AUD 26M */ } if (TopCkCount < 0) { pr_warn("%s(), <0 =%d\n ", __func__, TopCkCount); TopCkCount = 0; } } mutex_unlock(&Ana_Clk_Mutex); } static int NvRegCount; static void NvregEnable(bool enable) { mutex_lock(&Ana_Clk_Mutex); if (enable == true) { if (NvRegCount == 0) { Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0, 0x1 << 4); /* Enable AUDGLB */ } NvRegCount++; } else { NvRegCount--; if (NvRegCount == 0) { Ana_Set_Reg(AUDDEC_ANA_CON13, 0x1 << 4, 0x1 << 4); /* Disable AUDGLB */ } if (NvRegCount < 0) { pr_warn("%s(), <0 =%d\n ", __func__, NvRegCount); NvRegCount = 0; } } mutex_unlock(&Ana_Clk_Mutex); } static void set_playback_gpio(bool enable) { if (enable) { /* set gpio mosi mode */ Ana_Set_Reg(GPIO_MODE2_CLR, 0xffff, 0xffff); Ana_Set_Reg(GPIO_MODE2_SET, 0x0249, 0xffff); Ana_Set_Reg(GPIO_MODE2, 0x0249, 0xffff); } else { /* set pad_aud_*_mosi to GPIO mode and dir input * reason: * pad_aud_dat_mosi*, because the pin is used as boot strap */ Ana_Set_Reg(GPIO_MODE2_CLR, 0xffff, 0xffff); Ana_Set_Reg(GPIO_MODE2, 0x0000, 0xffff); Ana_Set_Reg(GPIO_DIR0, 0x0, 0xf << 8); } } static void set_capture_gpio(bool enable) { if (enable) { /* set gpio miso mode */ Ana_Set_Reg(GPIO_MODE3_CLR, 0xffff, 0xffff); Ana_Set_Reg(GPIO_MODE3_SET, 0x0249, 0xffff); Ana_Set_Reg(GPIO_MODE3, 0x0249, 0xffff); } else { /* set pad_aud_*_miso to GPIO mode and dir input * reason: * pad_aud_clk_miso, because when playback only the miso_clk * will also have 26m, so will have power leak * pad_aud_dat_miso*, because the pin is used as boot strap */ Ana_Set_Reg(GPIO_MODE3_CLR, 0xffff, 0xffff); Ana_Set_Reg(GPIO_MODE3, 0x0000, 0xffff); Ana_Set_Reg(GPIO_DIR0, 0x0, 0xf << 12); } } bool hasHpDepopHw(void) { return mUseHpDepopFlow == HP_DEPOP_FLOW_DEPOP_HW || mUseHpDepopFlow == HP_DEPOP_FLOW_DEPOP_HW_33OHM; } bool hasHp33Ohm(void) { return mUseHpDepopFlow == HP_DEPOP_FLOW_33OHM || mUseHpDepopFlow == HP_DEPOP_FLOW_DEPOP_HW_33OHM; } int set_codec_ops(struct mtk_codec_ops *ops) { enable_dc_compensation = ops->enable_dc_compensation; set_lch_dc_compensation = ops->set_lch_dc_compensation; set_rch_dc_compensation = ops->set_rch_dc_compensation; set_ap_dmic = ops->set_ap_dmic; set_hp_impedance_ctl = ops->set_hp_impedance_ctl; return 0; } static int audio_get_auxadc_value(void) { return pmic_get_auxadc_value(AUXADC_LIST_HPOFS_CAL); } static int get_accdet_auxadc(void) { return pmic_get_auxadc_value(AUXADC_LIST_ACCDET); } #ifdef CONFIG_MTK_VOW_SUPPORT static int VOW13MCKCount; static int VOW32KCKCount; #endif #ifdef CONFIG_MTK_VOW_SUPPORT static void VOW13MCK_Enable(bool enable) { mutex_lock(&Ana_Clk_Mutex); if (enable == true) { if (VOW13MCKCount == 0) Ana_Set_Reg(AUD_TOP_CKPDN_CON0_CLR, 0x2000, 0x2000); /* Enable AUD_TOP_CKPDN_CON0 bit13 for enable VOW 13M clock */ VOW13MCKCount++; } else { VOW13MCKCount--; if (VOW13MCKCount == 0) Ana_Set_Reg(AUD_TOP_CKPDN_CON0_SET, 0x2000, 0x2000); /* disable AUD_TOP_CKPDN_CON0 bit13 for enable VOW 13M clock */ if (VOW13MCKCount < 0) { pr_debug("VOW13MCKCount <0 =%d\n ", VOW13MCKCount); VOW13MCKCount = 0; } } mutex_unlock(&Ana_Clk_Mutex); } static void VOW32KCK_Enable(bool enable) { mutex_lock(&Ana_Clk_Mutex); if (enable == true) { if (VOW32KCKCount == 0) Ana_Set_Reg(AUD_TOP_CKPDN_CON0_CLR, 0x1000, 0x1000); /* Enable AUD_TOP_CKPDN_CON0 bit12 for enable VOW 32k clock * (for periodic on/off use) */ VOW32KCKCount++; } else { VOW32KCKCount--; if (VOW32KCKCount == 0) Ana_Set_Reg(AUD_TOP_CKPDN_CON0_SET, 0x1000, 0x1000); /* disable AUD_TOP_CKPDN_CON0 bit12 for enable VOW 32k clock */ if (VOW32KCKCount < 0) { pr_debug("VOW32KCKCount <0 =%d\n ", VOW32KCKCount); VOW32KCKCount = 0; } } mutex_unlock(&Ana_Clk_Mutex); } #endif void vow_irq_handler(void) { #ifdef CONFIG_MTK_VOW_SUPPORT pr_debug("vow_irq,audio irq event....\n"); /* TurnOnVOWADcPower(ANA_DEV_IN_ADC1, false); */ /* TurnOnVOWDigitalHW(false); */ #if defined(VOW_TONE_TEST) EnableSineGen(Soc_Aud_InterConnectionOutput_O03, Soc_Aud_MemIF_Direction_DIRECTION_OUTPUT, true); #endif /* VowDrv_ChangeStatus(); */ #endif } /*extern kal_uint32 upmu_get_reg_value(kal_uint32 reg);*/ void Auddrv_Read_Efuse_HPOffset(void) { #ifndef CONFIG_FPGA_EARLY_PORTING #ifdef EFUSE_HP_TRIM U32 ret = 0; U32 reg_val = 0; int i = 0, j = 0; U32 efusevalue[3]; /* 1. enable efuse ctrl engine clock */ ret = pmic_config_interface(0x026C, 0x0040, 0xFFFF, 0); ret = pmic_config_interface(0x024E, 0x0004, 0xFFFF, 0); /* 2. */ ret = pmic_config_interface(0x0C16, 0x1, 0x1, 0); for (i = 0xe; i <= 0x10; i++) { /* 3. set row to read */ ret = pmic_config_interface(0x0C00, i, 0x1F, 1); /* 4. Toggle */ ret = pmic_read_interface(0xC10, ®_val, 0x1, 0); if (reg_val == 0) ret = pmic_config_interface(0xC10, 1, 0x1, 0); else ret = pmic_config_interface(0xC10, 0, 0x1, 0); /* 5. polling Reg[0xC1A] */ reg_val = 1; while (reg_val == 1) ret = pmic_read_interface(0xC1A, ®_val, 0x1, 0); udelay(1000); /* delay at least 1ms for 0xC1A and than can read 0xC18 */ /* 6. read data */ efusevalue[j] = upmu_get_reg_value(0x0C18); pr_debug("HPoffset : efuse[%d]=0x%x\n", j, efusevalue[j]); j++; } /* 7. Disable efuse ctrl engine clock */ ret = pmic_config_interface(0x024C, 0x0004, 0xFFFF, 0); ret = pmic_config_interface(0x026A, 0x0040, 0xFFFF, 0); RG_AUDHPLTRIM_VAUDP15 = (efusevalue[0] >> 10) & 0xf; RG_AUDHPRTRIM_VAUDP15 = ((efusevalue[0] >> 14) & 0x3) + (( efusevalue[1] & 0x3) << 2); RG_AUDHPLFINETRIM_VAUDP15 = (efusevalue[1] >> 3) & 0x3; RG_AUDHPRFINETRIM_VAUDP15 = (efusevalue[1] >> 5) & 0x3; RG_AUDHPLTRIM_VAUDP15_SPKHP = (efusevalue[1] >> 7) & 0xF; RG_AUDHPRTRIM_VAUDP15_SPKHP = (efusevalue[1] >> 11) & 0xF; RG_AUDHPLFINETRIM_VAUDP15_SPKHP = ((efusevalue[1] >> 15) & 0x1) + ((efusevalue[2] & 0x1) << 1); RG_AUDHPRFINETRIM_VAUDP15_SPKHP = ((efusevalue[2] >> 1) & 0x3); pr_debug("RG_AUDHPLTRIM_VAUDP15 = %x\n", RG_AUDHPLTRIM_VAUDP15); pr_debug("RG_AUDHPRTRIM_VAUDP15 = %x\n", RG_AUDHPRTRIM_VAUDP15); pr_debug("RG_AUDHPLFINETRIM_VAUDP15 = %x\n", RG_AUDHPLFINETRIM_VAUDP15); pr_debug("RG_AUDHPRFINETRIM_VAUDP15 = %x\n", RG_AUDHPRFINETRIM_VAUDP15); pr_debug("RG_AUDHPLTRIM_VAUDP15_SPKHP = %x\n", RG_AUDHPLTRIM_VAUDP15_SPKHP); pr_debug("RG_AUDHPRTRIM_VAUDP15_SPKHP = %x\n", RG_AUDHPRTRIM_VAUDP15_SPKHP); pr_debug("RG_AUDHPLFINETRIM_VAUDP15_SPKHP = %x\n", RG_AUDHPLFINETRIM_VAUDP15_SPKHP); pr_debug("RG_AUDHPRFINETRIM_VAUDP15_SPKHP = %x\n", RG_AUDHPRFINETRIM_VAUDP15_SPKHP); #endif #endif } EXPORT_SYMBOL(Auddrv_Read_Efuse_HPOffset); static void setHpGainZero(void) { Ana_Set_Reg(ZCD_CON2, DL_GAIN_0DB << 7, 0x0f80); Ana_Set_Reg(ZCD_CON2, DL_GAIN_0DB, 0x001f); } static void Hp_Zcd_Enable(bool _enable) { if (_enable) { /* Enable ZCD, for minimize pop noise */ /* when adjust gain during HP buffer on */ Ana_Set_Reg(ZCD_CON0, 0x1 << 8, 0x7 << 8); Ana_Set_Reg(ZCD_CON0, 0x0 << 7, 0x1 << 7); /* timeout, 1=5ms, 0=30ms */ Ana_Set_Reg(ZCD_CON0, 0x1 << 6, 0x1 << 6); Ana_Set_Reg(ZCD_CON0, 0x0 << 4, 0x3 << 4); Ana_Set_Reg(ZCD_CON0, 0x5 << 1, 0x7 << 1); Ana_Set_Reg(ZCD_CON0, 0x1 << 0, 0x1 << 0); } else { Ana_Set_Reg(ZCD_CON0, 0x0000, 0xffff); } } static void hp_main_output_ramp(bool up) { int i = 0, stage = 0; int target = 0; /* Enable/Reduce HPL/R main output stage step by step */ target = (low_power_mode == 1) ? 3 : 7; for (i = 0; i <= target; i++) { stage = up ? i : target - i; Ana_Set_Reg(AUDDEC_ANA_CON1, stage << 8, 0x7 << 8); Ana_Set_Reg(AUDDEC_ANA_CON1, stage << 11, 0x7 << 11); udelay(600); } } static void hp_aux_feedback_loop_gain_ramp(bool up) { int i = 0, stage = 0; /* Reduce HP aux feedback loop gain step by step */ for (i = 0; i <= 0xf; i++) { stage = up ? i : 0xf - i; Ana_Set_Reg(AUDDEC_ANA_CON9, stage << 12, 0xf << 12); udelay(600); } } static void hp_pull_down(bool enable) { int from = enable ? 0x0 : 0x6; int to = enable ? 0x6 : 0x0; int i; if (enable) { for (i = from; i <= to; i++) { Ana_Set_Reg(AUDDEC_ANA_CON4, i, 0x7); udelay(600); } } else { for (i = from; i >= to; i--) { Ana_Set_Reg(AUDDEC_ANA_CON4, i, 0x7); udelay(600); } } } static bool is_valid_hp_pga_idx(int reg_idx) { return (reg_idx >= DL_GAIN_8DB && reg_idx <= DL_GAIN_N_10DB) || reg_idx == DL_GAIN_N_40DB; } static void headset_volume_ramp(int from, int to) { int offset = 0, count = 1, reg_idx; if (!is_valid_hp_pga_idx(from) || !is_valid_hp_pga_idx(to)) pr_warn("%s(), volume index is not valid, from %d, to %d\n", __func__, from, to); if (to > from) { offset = to - from; while (offset > 0) { reg_idx = from + count; if (is_valid_hp_pga_idx(reg_idx)) { Ana_Set_Reg(ZCD_CON2, (reg_idx << 7) | reg_idx, DL_GAIN_REG_MASK); usleep_range(200, 300); } offset--; count++; } } else if (to < from) { offset = from - to; while (offset > 0) { reg_idx = from - count; if (is_valid_hp_pga_idx(reg_idx)) { Ana_Set_Reg(ZCD_CON2, (reg_idx << 7) | reg_idx, DL_GAIN_REG_MASK); usleep_range(200, 300); } offset--; count++; } } } static void setOffsetTrimMux(unsigned int Mux) { /* Audio offset trimming buffer mux selection */ Ana_Set_Reg(AUDDEC_ANA_CON8, Mux, 0xf); } static void setOffsetTrimBufferGain(unsigned int gain) { /* Audio offset trimming buffer gain selection */ Ana_Set_Reg(AUDDEC_ANA_CON8, gain << 4, 0x3 << 4); } static void EnableTrimbuffer(bool benable) { if (benable == true) { Ana_Set_Reg(AUDDEC_ANA_CON8, 0x1 << 6, 0x1 << 6); /* Audio offset trimming buffer enable */ } else { Ana_Set_Reg(AUDDEC_ANA_CON8, 0x0, 0x1 << 6); /* Audio offset trimming buffer disable */ } } /* For MT6358 LO */ #if 0 static void Apply_Speaker_Gain(void) { Ana_Set_Reg(ZCD_CON1, (mCodec_data->ana_gain[ANA_GAIN_LINEOUTR] << 7) | mCodec_data->ana_gain[ANA_GAIN_LINEOUTL], DL_GAIN_REG_MASK); } #else static void Apply_Speaker_Gain(int spk_pga_gain) { Ana_Set_Reg(ZCD_CON1, (spk_pga_gain << 7) | spk_pga_gain, DL_GAIN_REG_MASK); } #endif #ifndef CONFIG_FPGA_EARLY_PORTING static void OpenTrimBufferHardware(bool enable, bool buffer_on) { pr_debug("%s(), enable %d, buffer_on %d\n", __func__, enable, buffer_on); if (enable) { Ana_Set_Reg(AUDDEC_ANA_CON10, 0xa0, 0xff); TurnOnDacPower(ANA_DEV_OUT_HEADSETL); /* sdm output mute enable */ /* Ana_Set_Reg(AFUNC_AUD_CON1, 0x0000, 0xffff); */ /* Ana_Set_Reg(AFUNC_AUD_CON0, 0xcbad, 0xffff); */ /* Disable handset short-circuit protection */ /* Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0010, 0xffff); */ /* Disable linout short-circuit protection */ /* Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0010, 0xffff); */ /* Disable headphone short-circuit protection */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x3000, 0xffff); /* Reduce ESD resistance of AU_REFN */ Ana_Set_Reg(AUDDEC_ANA_CON2, 0xc000, 0xffff); /* Set HPL/HPR gain to -10dB*/ Ana_Set_Reg(ZCD_CON2, DL_GAIN_N_10DB_REG, 0xffff); /* Turn on DA_600K_NCP_VA18 */ Ana_Set_Reg(AUDNCP_CLKDIV_CON1, 0x0001, 0xffff); /* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */ Ana_Set_Reg(AUDNCP_CLKDIV_CON2, 0x002c, 0xffff); /* Toggle RG_DIVCKS_CHG */ Ana_Set_Reg(AUDNCP_CLKDIV_CON0, 0x0001, 0xffff); /* Set NCP soft start mode as default mode: 150us */ Ana_Set_Reg(AUDNCP_CLKDIV_CON4, 0x0002, 0xffff); /* Enable NCP */ Ana_Set_Reg(AUDNCP_CLKDIV_CON3, 0x0000, 0xffff); udelay(250); /* Enable cap-less LDOs (1.5V), LCLDO local sense */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x1055, 0x1055); /* Enable NV regulator (-1.2V) */ Ana_Set_Reg(AUDDEC_ANA_CON15, 0x0001, 0xffff); udelay(100); /* Disable AUD_ZCD */ /* Ana_Set_Reg(ZCD_CON0, 0x0000, 0xffff); */ Hp_Zcd_Enable(false); /* Enable IBIST */ Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0055, 0xffff); /* Set HP DR bias current optimization, 010: 6uA */ Ana_Set_Reg(AUDDEC_ANA_CON11, 0x4900, 0xffff); /* Set HP & ZCD bias current optimization */ /* 01: ZCD: 4uA, HP/HS/LO: 5uA */ Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0055, 0xffff); /* Set HPP/N STB enhance circuits */ Ana_Set_Reg(AUDDEC_ANA_CON2, 0xc033, 0xffff); if (buffer_on) { /* Enable HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x000c, 0xffff); /* Enable HP aux feedback loop */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x003c, 0xffff); /* Enable HP aux CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0c80, 0xffff); /* Enable HP driver bias circuits */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x30c0, 0xffff); /* Enable HP driver core circuits */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x30f0, 0xffff); /* Short HP main output to HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x00fc, 0x00ff); /* Enable HP main CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0e80, 0xffff); /* Disable HP aux CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0280, 0xffff); /* Select CMFB resistor bulk to AC mode */ /* Selec HS/LO cap size (6.5pF default) */ Ana_Set_Reg(AUDDEC_ANA_CON10, 0x0000, 0xffff); /* Enable HS driver bias circuits */ /* Disable HS main output stage */ Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0010, 0xffff); /* Enable LO driver bias circuits */ /* Disable LO main output stage */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0010, 0xffff); /* Enable HP main output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x00ff, 0x00ff); /* Enable HPR/L main output stage step by step */ hp_main_output_ramp(true); /* Reduce HP aux feedback loop gain step by step */ hp_aux_feedback_loop_gain_ramp(true); /* Disable HP aux feedback loop */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x3fcf, 0xffff); /* Increase HPL/HPR gain to normal gain step by step */ headset_volume_ramp(DL_GAIN_N_10DB, mCodec_data->ana_gain[ANA_GAIN_HPOUTL]); /* Disable HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x3fc3, 0xffff); /* Unshort HP main output to HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x3f03, 0xffff); udelay(1000); /* Disable AUD_CLK */ Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0, 0x1); /* Disable Audio DAC */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0000, 0x000f); /* Disable low-noise mode of DAC*/ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0000, 0x0001); /* Switch HPL/HPR MUX to open */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0000, 0x0f00); /* Disable Pull-down HPL/R to AVSS28_AUD*/ hp_pull_down(false); /* Enable Trim buffer VA28 reference */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x1<<1, 0x1<<1); } else { /* Enable HP driver bias circuits */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x30c0, 0xffff); /* Disable HP main output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0000, 0xffff); /* Enable HS driver bias circuits */ /* Disable HS main output stage */ Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0012, 0xffff); /* Enable LO driver bias circuits */ /* Disable LO main output stage */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0012, 0xffff); } /* Enable AUD_CLK */ /* Ana_Set_Reg(AUDDEC_ANA_CON13, 0x1, 0x1); */ /* Enable low-noise mode of DAC */ /* Ana_Set_Reg(AUDDEC_ANA_CON9, 0x1, 0x1); */ udelay(100); } else { /* Pull-down HPL/R to AVSS28_AUD */ hp_pull_down(true); /* HPR/HPL mux to open */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0000, 0x0f00); /* Disable low-noise mode of DAC */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0, 0x1); /* Disable Audio DAC */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0000, 0x000f); /* Disable AUD_CLK */ Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0, 0x1); /* Short HP main output to HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x3fc3, 0xffff); /* Enable HP aux output stage*/ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x3fcf, 0xffff); /* decrease HPL/R gain to normal gain step by step */ headset_volume_ramp(mCodec_data->ana_gain[ANA_GAIN_HPOUTL], DL_GAIN_N_10DB); /* Enable HP aux feedback loop */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x3fff, 0xffff); /* set HP aux feedback loop gain to max step by step */ hp_aux_feedback_loop_gain_ramp(false); /* decrease HPR/L main output stage step by step */ hp_main_output_ramp(false); /* Disable HP main output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0, 0x3); /* Enable HP aux CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0e00, 0x0f00); /* Disable HP main CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0c00, 0x0f00); /* Unshort HP main output to HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0, 0x3 << 6); /* Disable HP driver core circuits */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x30c0, 0xffff); /* Disable HP driver bias circuits */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x3000, 0xffff); /* Disable HP aux CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0, 0xffff); /* Open HP aux feedback loop */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0xc, 0xffff); /* Disable HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0, 0xffff); /* Disable IBIST */ Ana_Set_Reg(AUDDEC_ANA_CON12, 0x1 << 8, 0x1 << 8); /* Disable NV regulator (-1.2V) */ Ana_Set_Reg(AUDDEC_ANA_CON15, 0x0, 0x1); /* Disable cap-less LDOs (1.5V) */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x0, 0x1055); /* Disable NCP */ Ana_Set_Reg(AUDNCP_CLKDIV_CON3, 0x1, 0x1); /* Set HPL/HPR gain to mute */ Ana_Set_Reg(ZCD_CON2, DL_GAIN_N_40DB_REG, 0xffff); /* Increase ESD resistance of AU_REFN */ Ana_Set_Reg(AUDDEC_ANA_CON2, 0x0, 0x1 << 14); TurnOffDacPower(); } } static void set_input_mux(unsigned int Mux) { Ana_Set_Reg(AUDDEC_ANA_CON0, Mux << 8, 0x3 << 8); } static void enable_lo_buffer(bool benable) { Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0110, 0xffff); Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0112, 0xffff); Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0113, 0xffff); } static void OpenTrimBufferHardware_withLO(bool enable, bool buffer_on) { pr_debug("%s(), enable %d, buffer_on %d\n", __func__, enable, buffer_on); if (enable) { TurnOnDacPower(ANA_DEV_OUT_HEADSETL); /* HP IVBUF (Vin path) de-gain enable: -12dB */ if (apply_n12db_gain) Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0004, 0xff); /* Audio left headphone input multiplexor selection : LOL*/ set_input_mux(1); /* Disable headphone short-circuit protection */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x3000, 0xf0ff); /* Disable lineout short-ckt protection */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x1 << 4, 0x1 << 4); /* Reduce ESD resistance of AU_REFN */ Ana_Set_Reg(AUDDEC_ANA_CON2, 0xc000, 0xffff); /* Set HPL/HPR gain to -10dB*/ Ana_Set_Reg(ZCD_CON2, DL_GAIN_N_10DB_REG, 0xffff); /* Set LOLR/LOLL gain to -10dB */ Ana_Set_Reg(ZCD_CON1, DL_GAIN_N_10DB_REG, 0xffff); /* Turn on DA_600K_NCP_VA18 */ Ana_Set_Reg(AUDNCP_CLKDIV_CON1, 0x0001, 0xffff); /* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */ Ana_Set_Reg(AUDNCP_CLKDIV_CON2, 0x002c, 0xffff); /* Toggle RG_DIVCKS_CHG */ Ana_Set_Reg(AUDNCP_CLKDIV_CON0, 0x0001, 0xffff); /* Set NCP soft start mode as default mode: 150us */ Ana_Set_Reg(AUDNCP_CLKDIV_CON4, 0x0002, 0xffff); /* Enable NCP */ Ana_Set_Reg(AUDNCP_CLKDIV_CON3, 0x0000, 0xffff); udelay(250); /* Enable cap-less LDOs (1.5V), LCLDO local sense */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x1055, 0x1055); /* Enable NV regulator (-1.2V) */ Ana_Set_Reg(AUDDEC_ANA_CON15, 0x0001, 0xffff); udelay(100); /* Disable AUD_ZCD */ Hp_Zcd_Enable(false); /* Enable IBIST */ Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0055, 0xffff); /* Set HP DR bias current optimization, 010: 6uA */ Ana_Set_Reg(AUDDEC_ANA_CON11, 0x4900, 0xffff); /* Set HP & ZCD bias current optimization */ /* 01: ZCD: 4uA, HP/HS/LO: 5uA */ Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0055, 0xffff); /* Set HPP/N STB enhance circuits */ Ana_Set_Reg(AUDDEC_ANA_CON2, 0xc033, 0xffff); if (buffer_on) { if (apply_n12db_gain) { /* HP IVBUF (Vin path) de-gain enable: -12dB */ Ana_Set_Reg(AUDDEC_ANA_CON10, 0x04, 0xff); } /* Set LO STB enhance circuits */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x1 << 8, 0x1 << 8); /* Enable LO driver bias circuits */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x1 << 1, 0x1 << 1); /* Enable LO driver core circuits */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x1, 0x1); /* Set LOL gain to normal gain step by step */ Ana_Set_Reg(ZCD_CON1, DL_GAIN_N_10DB_REG, 0xffff); /* Switch HPL MUX to Line-out */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x01 << 8, 0x3 << 8); /* Enable HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0c, 0xff); /* Enable HP aux feedback loop */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x3c, 0xff); /* Enable HP aux CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0c00, 0xff00); /* Enable HP driver bias circuits */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0xc0, 0xf0); /* Enable HP driver core circuits */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0xf0, 0xf0); /* Short HP main output to HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0xfc, 0xff); /* Enable HP main CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0e00, 0xff00); /* Disable HP aux CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0200, 0xff00); /* Select CMFB resistor bulk to AC mode */ /* Selec HS/LO cap size (6.5pF default) */ Ana_Set_Reg(AUDDEC_ANA_CON10, 0x0000, 0xffff); /* Enable HS driver bias circuits */ /* Disable HS main output stage */ Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0010, 0xffff); /* Enable LO driver bias circuits */ /* Disable LO main output stage */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0010, 0xffff); /* Enable LO main output stage */ enable_lo_buffer(true); Apply_Speaker_Gain(DL_GAIN_0DB); /* Enable HP main output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x00ff, 0x00ff); /* Enable HPR/L main output stage step by step */ hp_main_output_ramp(true); /* Reduce HP aux feedback loop gain step by step */ hp_aux_feedback_loop_gain_ramp(true); /* Disable HP aux feedback loop */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x00cf, 0x00ff); /* Increase HPL/HPR gain to normal gain step by step */ headset_volume_ramp(DL_GAIN_N_10DB, mCodec_data->ana_gain[ANA_GAIN_HPOUTL]); /* Disable HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x00c3, 0x00ff); /* Unshort HP main output to HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0003, 0x00ff); udelay(1000); /* HP ESD resistor @AU_REFN short enable */ Ana_Set_Reg(AUDDEC_ANA_CON2, 0xc033, 0xffff); } /* Enable AUD_CLK */ Ana_Set_Reg(AUDDEC_ANA_CON13, 0x1, 0x1); /* Enable low-noise mode of DAC */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x1, 0x1); udelay(100); /* Switch LOL MUX to audio DAC */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x2 << 2, 0x3 << 2); /* Disable Pull-down HPL/R to AVSS28_AUD */ hp_pull_down(false); } else { /* Pull-down HPL/R to AVSS28_AUD */ hp_pull_down(true); /* Disable low-noise mode of DAC */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0, 0x1); /* Disable Audio DAC */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0, 0xf); /* Disable AUD_CLK */ Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0, 0x1); /* Short HP main output to HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x3fc3, 0xffff); /* Enable HP aux output stage*/ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x3fcf, 0xffff); /* decrease HPL/R gain to normal gain step by step */ headset_volume_ramp(mCodec_data->ana_gain[ANA_GAIN_HPOUTL], DL_GAIN_N_10DB); Ana_Set_Reg(ZCD_CON1, DL_GAIN_N_10DB_REG, 0xffff); /* set HP aux feedback loop gain to max */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0xf200, 0xff00); /* Enable HP aux feedback loop */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0xff, 0xff); /* Reduce HP aux feedback loop gain */ hp_aux_feedback_loop_gain_ramp(false); /* decrease HPR/L main output stage step by step */ hp_main_output_ramp(false); /* Switch HPL/HPR MUX to open */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0 << 8, 0xf << 8); /* Switch LOL MUX to open */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0 << 2, 0x3 << 2); /* Disable HP main output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0, 0x3); /* Enable HP aux CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0e00, 0x0f00); /* Disable HP main CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0c00, 0x0f00); /* Unshort HP main output to HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0, 0x3 << 6); /* Disable HP driver core circuits */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x30c0, 0xffff); /* Disable HP driver bias circuits */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x3000, 0xffff); /* Disable HP aux CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0, 0xffff); /* Open HP aux feedback loop */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0xc, 0xffff); /* Disable HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0, 0xffff); /* decrease LOL gain to minimum gain step by step */ Ana_Set_Reg(ZCD_CON1, DL_GAIN_N_40DB_REG, 0xffff); /* Disable LO driver core circuits */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0, 0x1); /* Disable LO driver bias circuits */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0 << 1, 0x1 << 1); /* Disable IBIST */ Ana_Set_Reg(AUDDEC_ANA_CON12, 0x1 << 8, 0x1 << 8); /* Disable NV regulator (-1.2V) */ Ana_Set_Reg(AUDDEC_ANA_CON15, 0x0, 0x1); /* Disable cap-less LDOs (1.5V) */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x0, 0x1055); /* Disable NCP */ Ana_Set_Reg(AUDNCP_CLKDIV_CON3, 0x1, 0x1); /* Set HPL/HPR gain to mute */ Ana_Set_Reg(ZCD_CON2, DL_GAIN_N_40DB_REG, 0xffff); /* Increase ESD resistance of AU_REFN */ Ana_Set_Reg(AUDDEC_ANA_CON2, 0x0, 0x1 << 14); TurnOffDacPower(); } } #endif static bool OpenHeadPhoneImpedanceSetting(bool bEnable) { pr_debug("%s benable = %d\n", __func__, bEnable); if (GetDLStatus() == true) return false; if (bEnable == true) { mIsNeedPullDown = false; TurnOnDacPower(ANA_DEV_OUT_HEADSETL); /* Disable headphone short-circuit protection */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x3000, 0xffff); /* Reduce ESD resistance of AU_REFN */ Ana_Set_Reg(AUDDEC_ANA_CON2, 0x4000, 0xffff); /* Turn on DA_600K_NCP_VA18 */ Ana_Set_Reg(AUDNCP_CLKDIV_CON1, 0x0001, 0xffff); /* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */ Ana_Set_Reg(AUDNCP_CLKDIV_CON2, 0x002c, 0xffff); /* Toggle RG_DIVCKS_CHG */ Ana_Set_Reg(AUDNCP_CLKDIV_CON0, 0x0001, 0xffff); /* Set NCP soft start mode as default mode: 150us */ Ana_Set_Reg(AUDNCP_CLKDIV_CON4, 0x0002, 0xffff); /* Enable NCP */ Ana_Set_Reg(AUDNCP_CLKDIV_CON3, 0x0000, 0xffff); udelay(250); /* Enable cap-less LDOs (1.5V) */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x1055, 0x1055); /* Enable NV regulator (-1.2V) */ Ana_Set_Reg(AUDDEC_ANA_CON15, 0x0001, 0xffff); udelay(100); /* Disable AUD_ZCD */ Hp_Zcd_Enable(false); /* Enable IBIST */ Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0055, 0xffff); /* Disable HPR/L STB enhance circuits */ Ana_Set_Reg(AUDDEC_ANA_CON2, 0x4000, 0xffff); /* Disable Pull-down HPL/R to AVSS28_AUD */ Ana_Set_Reg(AUDDEC_ANA_CON4, 0x0000, 0xffff); /* Enable AUD_CLK */ Ana_Set_Reg(AUDDEC_ANA_CON13, 0x1, 0x1); /* Enable Audio L channel DAC */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x3009, 0xffff); /* Enable Trim buffer VA28 reference */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0002, 0x00ff); /* Enable HPDET circuit, * select DACLP as HPDET input and HPR as HPDET output */ Ana_Set_Reg(AUDDEC_ANA_CON8, 0x1900, 0xffff); /* Enable TRIMBUF circuit, select HPR as TRIMBUF input */ /* Set TRIMBUF gain as 18dB */ Ana_Set_Reg(AUDDEC_ANA_CON8, 0x1972, 0xffff); } else { /* disable HPDET circuit */ Ana_Set_Reg(AUDDEC_ANA_CON8, 0x0000, 0xff00); /* Disable Trim buffer VA28 reference */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0000, 0x00ff); /* Disable Audio DAC */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0000, 0x000f); /* Disable AUD_CLK */ Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0, 0x1); /* Disable HP main output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0, 0x3); /* Disable HP driver core circuits */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0, 0x3 << 4); /* Disable HP driver bias circuits */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0, 0x3 << 6); /* Disable HP aux CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0, 0xff << 8); /* Disable IBIST */ Ana_Set_Reg(AUDDEC_ANA_CON12, 0x1 << 8, 0x1 << 8); /* Disable NV regulator (-1.2V) */ Ana_Set_Reg(AUDDEC_ANA_CON15, 0x0, 0x1); /* Disable cap-less LDOs (1.5V) */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x0, 0x1055); /* Disable NCP */ Ana_Set_Reg(AUDNCP_CLKDIV_CON3, 0x1, 0x1); /* Set HPL/HPR gain to mute */ Ana_Set_Reg(ZCD_CON2, DL_GAIN_N_10DB_REG, 0xffff); /* Set HPP/N STB enhance circuits */ Ana_Set_Reg(AUDDEC_ANA_CON2, 0x33, 0xff); /* Increase ESD resistance of AU_REFN */ Ana_Set_Reg(AUDDEC_ANA_CON2, 0x0, 0x1 << 14); TurnOffDacPower(); mIsNeedPullDown = true; } return true; } /* Headphone Impedance Detection */ /* Pmic Headphone Impedance variable */ struct mtk_hpdet_param { int auxadc_upper_bound; int dc_Step; int dc_Phase0; int dc_Phase1; int dc_Phase2; int resistance_first_threshold; int resistance_second_threshold; }; static int hp_impedance; static const int auxcable_impedance = 5000; static int efuse_current_calibrate; static void mtk_read_hp_detection_parameter(struct mtk_hpdet_param *hpdet_param) { hpdet_param->auxadc_upper_bound = 32630; /* should little lower than auxadc max resolution */ hpdet_param->dc_Step = 96; /* Dc ramp up and ramp down step */ hpdet_param->dc_Phase0 = 288; /* Phase 0 : high impedance with worst resolution */ hpdet_param->dc_Phase1 = 1440; /* Phase 1 : median impedance with normal resolution */ hpdet_param->dc_Phase2 = 6048; /* Phase 2 : low impedance with better resolution */ hpdet_param->resistance_first_threshold = 250; /* Resistance Threshold of phase 2 and phase 1 */ hpdet_param->resistance_second_threshold = 1000; /* Resistance Threshold of phase 1 and phase 0 */ } static int mtk_calculate_impedance_formula(int pcm_offset, int aux_diff) { /* The formula is from DE programming guide */ /* should be mantain by pmic owner */ /* R = V /I */ /* V = auxDiff * (1800mv /auxResolution) /TrimBufGain */ /* I = pcmOffset * DAC_constant * Gsdm * Gibuf */ long val = 3600000 / pcm_offset * aux_diff; return (int)DIV_ROUND_CLOSEST(val, 7832); } static int mtk_calculate_hp_impedance(int dc_init, int dc_input, short pcm_offset, const unsigned int detect_times) { int dc_value; int r_tmp = 0; if (dc_input < dc_init) { pr_warn("%s(), Wrong[%d] : dc_input(%d) > dc_init(%d)\n", __func__, pcm_offset, dc_input, dc_init); return 0; } dc_value = dc_input - dc_init; r_tmp = mtk_calculate_impedance_formula(pcm_offset, dc_value); r_tmp = DIV_ROUND_CLOSEST(r_tmp, detect_times); /* Efuse calibration */ if ((efuse_current_calibrate != 0) && (r_tmp != 0)) { pr_debug("%s(), Before Calibration from EFUSE: %d, R: %d\n", __func__, efuse_current_calibrate, r_tmp); r_tmp = DIV_ROUND_CLOSEST(r_tmp * 128 + efuse_current_calibrate, 128); } pr_debug("%s(), pcm_offset %d dcoffset %d detected resistor is %d\n", __func__, pcm_offset, dc_value, r_tmp); return r_tmp; } static int detect_impedance(void) { const unsigned int kDetectTimes = 8; unsigned int counter; int dcSum = 0, detectSum = 0; int detectsOffset[kDetectTimes]; int pick_impedance = 0, impedance = 0, phase_flag = 0; int dcValue = 0; int old_value_auxadc_con1 = Ana_Get_Reg(AUXADC_CON1); struct mtk_hpdet_param hpdet_param; if (enable_dc_compensation && set_lch_dc_compensation && set_rch_dc_compensation) { set_lch_dc_compensation(0); set_rch_dc_compensation(0); enable_dc_compensation(true); } else { pr_warn("%s(), dc compensation ops not ready\n", __func__); return 0; } mtk_read_hp_detection_parameter(&hpdet_param); Ana_Set_Reg(AUXADC_CON10, AUXADC_AVG_64, 0x7); /* Set AUXADC_SPL_NUM as 0xC for hp imp detect */ Ana_Set_Reg(AUXADC_CON1, 0xC << 6, 0xf << 6); setOffsetTrimMux(AUDIO_OFFSET_TRIM_MUX_HPR); setOffsetTrimBufferGain(3); /* HPDET trim. buffer gain : 18db */ EnableTrimbuffer(true); setHpGainZero(); for (dcValue = 0; dcValue <= hpdet_param.dc_Phase2; dcValue += hpdet_param.dc_Step) { /* apply dc by dc compensation: 16bit MSB and negative value */ set_lch_dc_compensation(-dcValue << 16); set_rch_dc_compensation(-dcValue << 16); /* save for DC =0 offset */ if (dcValue == 0) { usleep_range(1*1000, 1*1000); dcSum = 0; for (counter = 0; counter < kDetectTimes; counter++) { detectsOffset[counter] = audio_get_auxadc_value(); dcSum = dcSum + detectsOffset[counter]; } if ((dcSum / kDetectTimes) > hpdet_param.auxadc_upper_bound) { pr_debug("%s(), dcValue == 0, auxadc value %d > auxadc_upper_bound %d\n", __func__, dcSum / kDetectTimes, hpdet_param.auxadc_upper_bound); impedance = auxcable_impedance; break; } } /* start checking */ if (dcValue == hpdet_param.dc_Phase0) { usleep_range(1*1000, 1*1000); detectSum = 0; detectSum = audio_get_auxadc_value(); if ((dcSum / kDetectTimes) == detectSum) { pr_debug("%s(), dcSum / kDetectTimes %d == detectSum %d\n", __func__, dcSum / kDetectTimes, detectSum); impedance = auxcable_impedance; break; } pick_impedance = mtk_calculate_hp_impedance( dcSum/kDetectTimes, detectSum, dcValue, 1); if (pick_impedance < hpdet_param.resistance_first_threshold) { phase_flag = 2; continue; } else if (pick_impedance < hpdet_param.resistance_second_threshold) { phase_flag = 1; continue; } /* Phase 0 : detect range 1kohm to 5kohm impedance */ for (counter = 1; counter < kDetectTimes; counter++) { detectsOffset[counter] = audio_get_auxadc_value(); detectSum = detectSum + detectsOffset[counter]; } if ((detectSum / kDetectTimes) > hpdet_param.auxadc_upper_bound) impedance = auxcable_impedance; else impedance = mtk_calculate_hp_impedance( dcSum, detectSum, dcValue, kDetectTimes); break; } /* Phase 1 : detect range 250ohm to 1000ohm impedance */ if (dcValue == hpdet_param.dc_Phase1 && phase_flag == 1) { usleep_range(1*1000, 1*1000); detectSum = 0; for (counter = 0; counter < kDetectTimes; counter++) { detectsOffset[counter] = audio_get_auxadc_value(); detectSum = detectSum + detectsOffset[counter]; } impedance = mtk_calculate_hp_impedance(dcSum, detectSum, dcValue, kDetectTimes); break; } /* Phase 2 : detect under 250ohm impedance */ if (dcValue == hpdet_param.dc_Phase2 && phase_flag == 2) { usleep_range(1*1000, 1*1000); detectSum = 0; for (counter = 0; counter < kDetectTimes; counter++) { detectsOffset[counter] = audio_get_auxadc_value(); detectSum = detectSum + detectsOffset[counter]; } impedance = mtk_calculate_hp_impedance(dcSum, detectSum, dcValue, kDetectTimes); break; } usleep_range(1*200, 1*200); } pr_debug("%s(), phase %d [dc,detect]Sum %d times [%d,%d], hp_impedance %d, pick_impedance %d, AUXADC_CON1 0x%x, AUXADC_CON10 0x%x\n", __func__, phase_flag, kDetectTimes, dcSum, detectSum, impedance, pick_impedance, Ana_Get_Reg(AUXADC_CON1), Ana_Get_Reg(AUXADC_CON10)); /* Ramp-Down */ while (dcValue > 0) { dcValue = dcValue - hpdet_param.dc_Step; /* apply dc by dc compensation: 16bit MSB and negative value */ set_lch_dc_compensation(-dcValue << 16); set_rch_dc_compensation(-dcValue << 16); usleep_range(1*200, 1*200); } set_lch_dc_compensation(0); set_rch_dc_compensation(0); enable_dc_compensation(false); setOffsetTrimMux(AUDIO_OFFSET_TRIM_MUX_GROUND); EnableTrimbuffer(false); /* Restore AUXADC_CON1 after hp imp detect */ Ana_Set_Reg(AUXADC_CON1, old_value_auxadc_con1, 0xffff); return impedance; } /* 1.7V * 0.5kohm / (2.5 + 0.5)kohm = 0.283V, support 1k ~ 14k, 0.5k margin */ #define MIC_VINP_4POLE_THRES_MV 283 #define VINP_NORMALIZED_TO_MV 1700 static int dctrim_calibrated; static int hpl_dc_offset, hpr_dc_offset; static int mic_vinp_mv; static int spkl_dc_offset; #ifndef ANALOG_HPTRIM static int last_lch_comp_value, last_rch_comp_value; static int last_spk2hp_lch_comp_value, last_spk2hp_rch_comp_value; #else struct anaoffset { int enable; int hpl_trimecode; int hpr_trimecode; int hpl_finetrim; int hpr_finetrim; }; static struct anaoffset hp_3pole_anaoffset, hp_4pole_anaoffset, spk_3pole_anaoffset, spk_4pole_anaoffset; static int dc_compensation_disabled; static unsigned int hp_3_pole_trim_setting; static unsigned int hp_4_pole_trim_setting; static unsigned int spk_hp_3_pole_trim_setting; static unsigned int spk_hp_4_pole_trim_setting; #endif static int mHplTrimOffset; static int mHprTrimOffset; static const int dBFactor_Den = 8192; /* 1 / (10 ^ (dB / 20)) * dBFactor_Den */ static const int dBFactor_Nom[32] = { 3261, 3659, 4106, 4607, 5169, 5799, 6507, 7301, 8192, 9192, 10313, 11572, 12983, 14568, 16345, 18340, 20577, 23088, 25905, 819200, 819200, 819200, 819200, 819200, 819200, 819200, 819200, 819200, 819200, 819200, 819200, 819200, }; #ifndef ANALOG_HPTRIM static int get_mic_bias_mv(void) { unsigned int mic_bias = (Ana_Get_Reg(AUDENC_ANA_CON10) >> 4) & 0x7; switch (mic_bias) { case MIC_BIAS_1p7: return 1700; case MIC_BIAS_1p8: return 1800; case MIC_BIAS_1p9: return 1900; case MIC_BIAS_2p0: return 2000; case MIC_BIAS_2p1: return 2100; case MIC_BIAS_2p5: return 2500; case MIC_BIAS_2p6: return 2600; case MIC_BIAS_2p7: return 2700; default: pr_warn("%s(), invalid mic_bias %d\n", __func__, mic_bias); return 2600; }; } static int calOffsetToDcComp(int offset, int vol_type) { int gain = mCodec_data->ana_gain[vol_type]; int mic_bias_mv; int real_mic_vinp_mv; int offset_scale = DIV_ROUND_CLOSEST(offset * dBFactor_Nom[gain], dBFactor_Den); if (mic_vinp_mv > MIC_VINP_4POLE_THRES_MV && ((codec_debug_enable & DBG_DCTRIM_BYPASS_4POLE) == 0)) { int v_diff_bias_vinp; int v_diff_bias_vinp_scale; /* refine mic bias influence on 4 pole headset */ mic_bias_mv = get_mic_bias_mv(); real_mic_vinp_mv = DIV_ROUND_CLOSEST(mic_vinp_mv * mic_bias_mv, VINP_NORMALIZED_TO_MV); v_diff_bias_vinp = mic_bias_mv - real_mic_vinp_mv; v_diff_bias_vinp_scale = DIV_ROUND_CLOSEST((v_diff_bias_vinp) * dBFactor_Nom[gain], dBFactor_Den); if ((codec_debug_enable & DBG_DCTRIM_4POLE_LOG) != 0) { pr_debug("%s(), mic_bias_mv %d, mic_vinp_mv %d, real_mic_vinp_mv %d\n", __func__, mic_bias_mv, mic_vinp_mv, real_mic_vinp_mv); pr_debug("%s(), a %d, b %d\n", __func__, DIV_ROUND_CLOSEST(offset_scale * 2804225, 32768), DIV_ROUND_CLOSEST(v_diff_bias_vinp_scale * 1782, 1800)); } return DIV_ROUND_CLOSEST(offset_scale * 2804225, 32768) - DIV_ROUND_CLOSEST(v_diff_bias_vinp_scale * 1782, 1800); } else { /* The formula is from DE programming guide */ /* should be mantain by pmic owner */ return DIV_ROUND_CLOSEST(offset_scale * 2804225, 32768); } } static int get_dc_ramp_step(int gain) { /* each step should be smaller than 100uV */ /* 1 pcm of dc compensation = 0.0808uV HP buffer voltage @ 0dB*/ /* 90uV / 0.0808uV(0dB) = 1113.73 */ int step_0db = 1114; /* scale for specific gain */ return step_0db * dBFactor_Nom[gain] / dBFactor_Den; } static int SetDcCompenSation(bool enable) { int lch_value = 0, rch_value = 0, tmp_ramp = 0; int times = 0, i = 0; int sign_lch = 0, sign_rch = 0; int abs_lch = 0, abs_rch = 0; int index_lgain = mCodec_data->ana_gain[ANA_GAIN_HPOUTL]; int diff_lch = 0, diff_rch = 0, ramp_l = 0, ramp_r = 0; int ramp_step = get_dc_ramp_step(index_lgain); if (enable_dc_compensation == NULL || set_lch_dc_compensation == NULL || set_rch_dc_compensation == NULL) { pr_warn("%s(), function not ready, enable %p, lch %p, rch %p\n", __func__, enable_dc_compensation, set_lch_dc_compensation, set_rch_dc_compensation); return -EFAULT; } if (enable && index_lgain == DL_GAIN_N_40DB) { pr_debug("%s(), -40dB skip dc compensation\n", __func__); return 0; } lch_value = calOffsetToDcComp(hpl_dc_offset, ANA_GAIN_HPOUTL); rch_value = calOffsetToDcComp(hpr_dc_offset, ANA_GAIN_HPOUTR); diff_lch = enable ? lch_value - last_lch_comp_value : lch_value; diff_rch = enable ? rch_value - last_rch_comp_value : rch_value; sign_lch = diff_lch < 0 ? -1 : 1; sign_rch = diff_rch < 0 ? -1 : 1; abs_lch = sign_lch * diff_lch; abs_rch = sign_rch * diff_rch; times = abs_lch > abs_rch ? (abs_lch / ramp_step) : (abs_rch / ramp_step); pr_debug("%s(), enable = %d, index_gain = %d, times = %d, lch_value = %d -> %d, rch_value = %d -> %d, ramp_step %d, mic_vinp_mv %d\n", __func__, enable, index_lgain, times, last_lch_comp_value, lch_value, last_rch_comp_value, rch_value, ramp_step, mic_vinp_mv); if (enable) { enable_dc_compensation(true); for (i = 1; i <= times; i++) { tmp_ramp = i * ramp_step; if (tmp_ramp < abs_lch) { ramp_l = last_lch_comp_value + sign_lch * tmp_ramp; set_lch_dc_compensation(ramp_l << 8); } if (tmp_ramp < abs_rch) { ramp_r = last_rch_comp_value + sign_rch * tmp_ramp; set_rch_dc_compensation(ramp_r << 8); } udelay(100); } set_lch_dc_compensation(lch_value << 8); set_rch_dc_compensation(rch_value << 8); last_lch_comp_value = lch_value; last_rch_comp_value = rch_value; } else { for (i = times; i >= 0; i--) { tmp_ramp = i * ramp_step; if (tmp_ramp < abs_lch) set_lch_dc_compensation(tmp_ramp << 8); if (tmp_ramp < abs_rch) set_rch_dc_compensation(tmp_ramp << 8); udelay(100); } set_lch_dc_compensation(0); set_rch_dc_compensation(0); enable_dc_compensation(false); last_lch_comp_value = 0; last_rch_comp_value = 0; } return 0; } #endif static int calculate_trim_result(int *on_value, int *off_value, int trimTime, int discard_num, int useful_num) { int i = 0, j = 0, tmp = 0, offset = 0; /* sort */ for (i = 0; i < trimTime - 1; i++) { for (j = 0; j < trimTime - 1 - i; j++) { if (on_value[j] > on_value[j + 1]) { tmp = on_value[j + 1]; on_value[j + 1] = on_value[j]; on_value[j] = tmp; } if (off_value[j] > off_value[j + 1]) { tmp = off_value[j + 1]; off_value[j + 1] = off_value[j]; off_value[j] = tmp; } } } /* calculate result */ for (i = discard_num; i < trimTime - discard_num; i++) offset += on_value[i] - off_value[i]; return DIV_ROUND_CLOSEST(offset, useful_num); } static void get_hp_trim_offset(void) { #ifndef CONFIG_FPGA_EARLY_PORTING #ifdef ANALOG_HPTRIM #define TRIM_TIMES 7 #else #define TRIM_TIMES 26 #endif #define TRIM_DISCARD_NUM 1 #define TRIM_USEFUL_NUM (TRIM_TIMES - (TRIM_DISCARD_NUM * 2)) int on_valueL[TRIM_TIMES], on_valueR[TRIM_TIMES]; int off_valueL[TRIM_TIMES], off_valueR[TRIM_TIMES]; int i; Ana_Set_Reg(AUXADC_CON10, AUXADC_AVG_256, 0x7); /* Step1. turn on buffer */ OpenTrimBufferHardware(true, true); /* L Channel */ /* Step2. Enable TRIMBUF circuit, * select HPL as TRIMBUF input and set TRIMBUF gain as 18dB */ setOffsetTrimMux(AUDIO_OFFSET_TRIM_MUX_HPL); setOffsetTrimBufferGain(3); /* 18db */ EnableTrimbuffer(true); /* Step3. Request AuxADC to get HP on dc value */ usleep_range(1 * 1000, 10 * 1000); for (i = 0; i < TRIM_TIMES; i++) on_valueL[i] = audio_get_auxadc_value(); /* Step4. select AUDREFN as TRIMBUF input */ setOffsetTrimMux(AUDIO_OFFSET_TRIM_MUX_AU_REFN); /* Step5. Request AuxADC to get HP off dc value */ usleep_range(1 * 1000, 10 * 1000); for (i = 0; i < TRIM_TIMES; i++) off_valueL[i] = audio_get_auxadc_value(); /* Step6. Enable TRIMBUF circuit, * select HPR as TRIMBUF input and set TRIMBUF gain as 18dB */ /* R Channel */ setOffsetTrimMux(AUDIO_OFFSET_TRIM_MUX_HPR); /* Step7. Request AuxADC to get HP on dc value */ usleep_range(1 * 1000, 10 * 1000); for (i = 0; i < TRIM_TIMES; i++) on_valueR[i] = audio_get_auxadc_value(); /* Step8. select AUDREFN as TRIMBUF input */ setOffsetTrimMux(AUDIO_OFFSET_TRIM_MUX_AU_REFN); /* Step9. Request AuxADC to get HP off dc value */ usleep_range(1 * 1000, 10 * 1000); for (i = 0; i < TRIM_TIMES; i++) off_valueR[i] = audio_get_auxadc_value(); /* Step10. turn off buffer */ EnableTrimbuffer(false); OpenTrimBufferHardware(false, true); mHplTrimOffset = calculate_trim_result(on_valueL, off_valueL, TRIM_TIMES, TRIM_DISCARD_NUM, TRIM_USEFUL_NUM); mHprTrimOffset = calculate_trim_result(on_valueR, off_valueR, TRIM_TIMES, TRIM_DISCARD_NUM, TRIM_USEFUL_NUM); pr_debug("%s(), channeL = %d, channeR = %d\n", __func__, mHplTrimOffset, mHprTrimOffset); #endif } static int get_spk_trim_offset(int channel) { #ifndef CONFIG_FPGA_EARLY_PORTING int on_value[TRIM_TIMES]; int off_value[TRIM_TIMES]; int offset = 0; int i; Ana_Set_Reg(AUXADC_CON10, AUXADC_AVG_256, 0x7); /* Step1. turn on buffer */ OpenTrimBufferHardware_withLO(true, true); /* Step2. Enable TRIMBUF circuit and set TRIMBUF gain as 18dB */ setOffsetTrimMux(channel); setOffsetTrimBufferGain(3); /* 18db */ EnableTrimbuffer(true); /* Step3. Request AuxADC to get HP on dc value */ usleep_range(1 * 1000, 10 * 1000); for (i = 0; i < TRIM_TIMES; i++) on_value[i] = audio_get_auxadc_value(); /* Step4. select AUDREFN as TRIMBUF input */ setOffsetTrimMux(AUDIO_OFFSET_TRIM_MUX_AU_REFN); /* Step5. Request AuxADC to get HP off dc value */ usleep_range(1 * 1000, 10 * 1000); for (i = 0; i < TRIM_TIMES; i++) off_value[i] = audio_get_auxadc_value(); /* Step6. turn off buffer */ EnableTrimbuffer(false); OpenTrimBufferHardware_withLO(false, true); offset = calculate_trim_result(on_value, off_value, TRIM_TIMES, TRIM_DISCARD_NUM, TRIM_USEFUL_NUM); pr_debug("%s(), channel = %d, offset = %d\n", __func__, channel, offset); return offset; #endif } #ifdef ANALOG_HPTRIM #define HPTRIM_L_SHIFT 0 #define HPTRIM_R_SHIFT 4 #define HPFINETRIM_L_SHIFT 8 #define HPFINETRIM_R_SHIFT 10 #define HPTRIM_EN_SHIFT 12 #define HPTRIM_L_MASK (0xf << HPTRIM_L_SHIFT) #define HPTRIM_R_MASK (0xf << HPTRIM_R_SHIFT) #define HPFINETRIM_L_MASK (0x3 << HPFINETRIM_L_SHIFT) #define HPFINETRIM_R_MASK (0x3 << HPFINETRIM_R_SHIFT) #define HPTRIM_EN_MASK (0x1 << HPTRIM_EN_SHIFT) static int pick_hp_finetrim(int offset_base, int offset_finetrim_1, int offset_finetrim_3) { if (abs(offset_base) < abs(offset_finetrim_1)) { if (abs(offset_base) < abs(offset_finetrim_3)) return 0x0; else return 0x3; } else { if (abs(offset_finetrim_1) < abs(offset_finetrim_3)) return 0x1; else return 0x3; } } static int pick_spk_finetrim(int offset_base, int offset_finetrim_2, int offset_finetrim_3) { if (abs(offset_base) < abs(offset_finetrim_2)) { if (abs(offset_base) < abs(offset_finetrim_3)) return 0x0; else return 0x3; } else { if (abs(offset_finetrim_2) < abs(offset_finetrim_3)) return 0x2; else return 0x3; } } static void set_lr_trim_code(void) { int hpl_base = 0, hpr_base = 0; int hpl_min = 0, hpr_min = 0; int hpl_ceiling = 0, hpr_ceiling = 0; int hpl_floor = 0, hpr_floor = 0; int hpl_finetrim_1 = 0, hpr_finetrim_1 = 0; int hpl_finetrim_3 = 0, hpr_finetrim_3 = 0; int trimcodel = 0, trimcoder = 0; int trimcodel_ceiling = 0, trimcoder_ceiling = 0; int trimcodel_floor = 0, trimcoder_floor = 0; int finetriml = 0, finetrimr = 0; int trimcode_tmpl = 0, trimcode_tmpr = 0; int tmp = 0; bool code_change = false; pr_debug("%s(), Start DCtrim Calibrating, AUDDEC_ELR_0 = 0x%x\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0)); Ana_Set_Reg(AUDDEC_ELR_0, 0x1 << HPTRIM_EN_SHIFT, HPTRIM_EN_MASK); hp_3pole_anaoffset.enable = 1; hp_4pole_anaoffset.enable = 1; /* channel L */ Ana_Set_Reg(AUDDEC_ELR_0, 0x0 << HPTRIM_L_SHIFT, HPTRIM_L_MASK); Ana_Set_Reg(AUDDEC_ELR_0, 0x0 << HPFINETRIM_L_SHIFT, HPFINETRIM_L_MASK); /* channel R */ Ana_Set_Reg(AUDDEC_ELR_0, 0x0 << HPTRIM_R_SHIFT, HPTRIM_R_MASK); Ana_Set_Reg(AUDDEC_ELR_0, 0x0 << HPFINETRIM_R_SHIFT, HPFINETRIM_R_MASK); pr_debug("%s(), AUDDEC_ELR_0 = 0x%x\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0)); get_hp_trim_offset(); hpl_base = mHplTrimOffset; hpr_base = mHprTrimOffset; mdelay(10); /* Step1: get trim code */ if (hpl_base == 0) goto EXIT; if (hpr_base == 0) goto EXIT; if (hpl_base > 0 || hpr_base > 0) { if (hpl_base > 0) { Ana_Set_Reg(AUDDEC_ELR_0, 0x2 << HPTRIM_L_SHIFT, HPTRIM_L_MASK); code_change = true; } if (hpr_base > 0) { Ana_Set_Reg(AUDDEC_ELR_0, 0x2 << HPTRIM_R_SHIFT, HPTRIM_R_MASK); code_change = true; } pr_debug("%s(), step1 > 0 set 4 level AUDDEC_ELR_0 = 0x%x trimcode(L/R) = %d/%d\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0), trimcodel, trimcoder); if (code_change) { get_hp_trim_offset(); code_change = false; hpl_min = mHplTrimOffset; hpr_min = mHprTrimOffset; Ana_Set_Reg(AUDDEC_ELR_0, 0x0 << HPTRIM_L_SHIFT, HPTRIM_L_MASK); Ana_Set_Reg(AUDDEC_ELR_0, 0x0 << HPTRIM_R_SHIFT, HPTRIM_R_MASK); mdelay(10); /* Check floor & ceiling to avoid rounding error */ if (hpl_base > 0) { trimcodel_floor = (abs(hpl_base)*3) / (abs(hpl_base-hpl_min)); trimcodel_ceiling = trimcodel_floor + 1; } if (hpr_base > 0) { trimcoder_floor = (abs(hpr_base)*3) / (abs(hpr_base-hpr_min)); trimcoder_ceiling = trimcoder_floor + 1; } } } if (hpl_base < 0 || hpr_base < 0) { if (hpl_base < 0) { Ana_Set_Reg(AUDDEC_ELR_0, 0xa << HPTRIM_L_SHIFT, HPTRIM_L_MASK); code_change = true; } if (hpr_base < 0) { Ana_Set_Reg(AUDDEC_ELR_0, 0xa << HPTRIM_R_SHIFT, HPTRIM_R_MASK); code_change = true; } pr_debug("%s(), step1 < 0 set 4 level AUDDEC_ELR_0 = 0x%x trimcode(L/R) = %d/%d\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0), trimcodel, trimcoder); if (code_change) { get_hp_trim_offset(); code_change = false; hpl_min = mHplTrimOffset; hpr_min = mHprTrimOffset; Ana_Set_Reg(AUDDEC_ELR_0, 0x0 << HPTRIM_L_SHIFT, HPTRIM_L_MASK); Ana_Set_Reg(AUDDEC_ELR_0, 0x0 << HPTRIM_R_SHIFT, HPTRIM_R_MASK); mdelay(10); /* Check floor & ceiling to avoid rounding error */ if (hpl_base < 0) { trimcodel_floor = (abs(hpl_base)*3) / (abs(hpl_base-hpl_min)) + 8; trimcodel_ceiling = trimcodel_floor + 1; } if (hpr_base < 0) { trimcoder_floor = (abs(hpr_base)*3) / (abs(hpr_base-hpr_min)) + 8; trimcoder_ceiling = trimcoder_floor + 1; } } } /* Get the best trim code from floor and ceiling value */ /* Get floor trim code */ Ana_Set_Reg(AUDDEC_ELR_0, trimcodel_floor << HPTRIM_L_SHIFT, HPTRIM_L_MASK); Ana_Set_Reg(AUDDEC_ELR_0, trimcoder_floor << HPTRIM_R_SHIFT, HPTRIM_R_MASK); get_hp_trim_offset(); hpl_floor = mHplTrimOffset; hpr_floor = mHprTrimOffset; mdelay(10); /* Get ceiling trim code */ Ana_Set_Reg(AUDDEC_ELR_0, trimcodel_ceiling << HPTRIM_L_SHIFT, HPTRIM_L_MASK); Ana_Set_Reg(AUDDEC_ELR_0, trimcoder_ceiling << HPTRIM_R_SHIFT, HPTRIM_R_MASK); get_hp_trim_offset(); hpl_ceiling = mHplTrimOffset; hpr_ceiling = mHprTrimOffset; mdelay(10); /* Choose the best */ if (abs(hpl_ceiling) < abs(hpl_floor)) { hpl_base = hpl_ceiling; trimcodel = trimcodel_ceiling; } else { hpl_base = hpl_floor; trimcodel = trimcodel_floor; } if (abs(hpr_ceiling) < abs(hpr_floor)) { hpr_base = hpr_ceiling; trimcoder = trimcoder_ceiling; } else { hpr_base = hpr_floor; trimcoder = trimcoder_floor; } Ana_Set_Reg(AUDDEC_ELR_0, trimcodel << HPTRIM_L_SHIFT, HPTRIM_L_MASK); Ana_Set_Reg(AUDDEC_ELR_0, trimcoder << HPTRIM_R_SHIFT, HPTRIM_R_MASK); pr_debug("%s(), step1 result AUDDEC_ELR_0 = 0x%x hp_base(L/R) = %d/%d, trimcode(L/R) = %d/%d\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0), hpl_base, hpr_base, trimcodel, trimcoder); /* Step2: Trim code refine +1/0/-1 */ trimcode_tmpl = trimcodel; trimcode_tmpr = trimcoder; mdelay(10); if (hpl_base == 0) goto EXIT; if (hpr_base == 0) goto EXIT; if (hpl_base > 0 || hpr_base > 0) { if ((hpl_base > 0) && (trimcodel != 0x7) && (trimcodel != 0x8)) { tmp = trimcodel + ((trimcodel > 7) ? -1 : 1); Ana_Set_Reg(AUDDEC_ELR_0, tmp << HPTRIM_L_SHIFT, HPTRIM_L_MASK); code_change = true; } if ((hpr_base > 0) && (trimcoder != 0x7) && (trimcoder != 0x8)) { tmp = trimcoder + ((trimcoder > 7) ? -1 : 1); Ana_Set_Reg(AUDDEC_ELR_0, tmp << HPTRIM_R_SHIFT, HPTRIM_R_MASK); code_change = true; } pr_debug("%s(), step2 > 0 AUDDEC_ELR_0 = 0x%x trimcode_tmp = %d\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0), tmp); if (code_change) { get_hp_trim_offset(); code_change = false; hpl_min = mHplTrimOffset; hpr_min = mHprTrimOffset; mdelay(10); if ((hpl_base > 0) && (hpl_min >= 0 || abs(hpl_min) < abs(hpl_base))) { if ((trimcodel != 0x7) && (trimcodel != 0x8)) { trimcode_tmpl = trimcodel + ((trimcodel > 7) ? -1 : 1); } else { trimcode_tmpl = trimcodel; pr_debug("%s(), [Step2][L>0, bit-overflow!!], don't refine, trimcodel = %d\n", __func__, trimcodel); } } if ((hpr_base > 0) && (hpr_min >= 0 || abs(hpr_min) < abs(hpr_base))) { if ((trimcoder != 0x7) && (trimcoder != 0x8)) { trimcode_tmpr = trimcoder + ((trimcoder > 7) ? -1 : 1); } else { trimcode_tmpr = trimcoder; pr_debug("%s(), [Step2][R>0, bit-overflow!!], don't refine, trimcoder = %d\n", __func__, trimcoder); } } } } Ana_Set_Reg(AUDDEC_ELR_0, trimcodel << HPTRIM_L_SHIFT, HPTRIM_L_MASK); Ana_Set_Reg(AUDDEC_ELR_0, trimcoder << HPTRIM_R_SHIFT, HPTRIM_R_MASK); if (hpl_base < 0 || hpr_base < 0) { if ((hpl_base < 0) && (trimcodel != 0) && (trimcodel != 0xf)) { tmp = trimcodel - ((trimcodel > 7) ? -1 : 1); Ana_Set_Reg(AUDDEC_ELR_0, tmp << HPTRIM_L_SHIFT, HPTRIM_L_MASK); code_change = true; } if ((hpr_base < 0) && (trimcoder != 0) && (trimcoder != 0xf)) { tmp = trimcoder - ((trimcoder > 7) ? -1 : 1); Ana_Set_Reg(AUDDEC_ELR_0, tmp << HPTRIM_R_SHIFT, HPTRIM_R_MASK); code_change = true; } pr_debug("%s(), step2 < 0 AUDDEC_ELR_0 = 0x%x trimcode_tmp(L/R) = %d/%d\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0), trimcode_tmpl, trimcode_tmpr); if (code_change) { get_hp_trim_offset(); code_change = false; hpl_min = mHplTrimOffset; hpr_min = mHprTrimOffset; mdelay(10); if ((hpl_base < 0) && (hpl_min <= 0 || abs(hpl_min) < abs(hpl_base))) { if ((trimcodel != 0) && (trimcodel != 0xf)) { trimcode_tmpl = trimcodel - ((trimcodel > 7) ? -1 : 1); } else { trimcode_tmpl = trimcodel; pr_debug("%s(), [Step2][L<0, bit-overflow!!], don't refine, trimcodel = %d\n", __func__, trimcodel); } } if ((hpr_base < 0) && (hpr_min <= 0 || abs(hpr_min) < abs(hpr_base))) { if ((trimcoder != 0) && (trimcoder != 0xf)) { trimcode_tmpr = trimcoder - ((trimcoder > 7) ? -1 : 1); } else { trimcode_tmpr = trimcoder; pr_debug("%s(), [Step2][R<0, bit-overflow!!], don't refine, trimcoder = %d\n", __func__, trimcoder); } } } } trimcodel = trimcode_tmpl; trimcoder = trimcode_tmpr; /* channel L */ Ana_Set_Reg(AUDDEC_ELR_0, trimcodel << HPTRIM_L_SHIFT, HPTRIM_L_MASK); /* channel R */ Ana_Set_Reg(AUDDEC_ELR_0, trimcoder << HPTRIM_R_SHIFT, HPTRIM_R_MASK); pr_debug("%s(), step2 result AUDDEC_ELR_0 = 0x%x trimcode(L/R) = %d/%d\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0), trimcodel, trimcoder); /*Step3: Trim code fine tune*/ get_hp_trim_offset(); hpl_base = mHplTrimOffset; hpr_base = mHprTrimOffset; mdelay(10); if (hpl_base == 0) goto EXIT; if (hpr_base == 0) goto EXIT; if (hpl_base > 0 || hpr_base > 0) { if (hpl_base > 0) { Ana_Set_Reg(AUDDEC_ELR_0, 0x1 << HPFINETRIM_L_SHIFT, HPFINETRIM_L_MASK); code_change = true; } if (hpr_base > 0) { Ana_Set_Reg(AUDDEC_ELR_0, 0x1 << HPFINETRIM_R_SHIFT, HPFINETRIM_R_MASK); code_change = true; } pr_debug("%s(), step3 > 0 AUDDEC_ELR_0 = 0x%x\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0)); if (code_change) { get_hp_trim_offset(); code_change = false; hpl_finetrim_1 = mHplTrimOffset; hpr_finetrim_1 = mHprTrimOffset; Ana_Set_Reg(AUDDEC_ELR_0, 0x0 << HPFINETRIM_L_SHIFT, HPFINETRIM_L_MASK); Ana_Set_Reg(AUDDEC_ELR_0, 0x0 << HPFINETRIM_R_SHIFT, HPFINETRIM_R_MASK); mdelay(10); if ((hpl_base > 0) && (hpl_finetrim_1 >= 0 && abs(hpl_finetrim_1) < abs(hpl_base))) finetriml = 0x1; if ((hpr_base > 0) && (hpr_finetrim_1 >= 0 && abs(hpr_finetrim_1) < abs(hpr_base))) finetrimr = 0x1; if (hpl_finetrim_1 < 0 || hpr_finetrim_1 < 0) { /* base and finetrim=1 across zero. */ /* Choose base, finetrim=1, and finetrim=3 */ if (hpl_finetrim_1 < 0 && hpl_base > 0) { /* channel L */ Ana_Set_Reg(AUDDEC_ELR_0, 0x3 << HPFINETRIM_L_SHIFT, HPFINETRIM_L_MASK); code_change = true; } if (hpr_finetrim_1 < 0 && hpr_base > 0) { /* channel R */ Ana_Set_Reg(AUDDEC_ELR_0, 0x3 << HPFINETRIM_R_SHIFT, HPFINETRIM_R_MASK); code_change = true; } pr_debug("%s(), step3_2 > 0 AUDDEC_ELR_0 = 0x%x\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0)); if (code_change) { get_hp_trim_offset(); code_change = false; hpl_finetrim_3 = mHplTrimOffset; hpr_finetrim_3 = mHprTrimOffset; Ana_Set_Reg(AUDDEC_ELR_0, 0x0 << HPFINETRIM_L_SHIFT, HPFINETRIM_L_MASK); Ana_Set_Reg(AUDDEC_ELR_0, 0x0 << HPFINETRIM_R_SHIFT, HPFINETRIM_R_MASK); mdelay(10); if (hpl_base > 0) { finetriml = pick_hp_finetrim(hpl_base, hpl_finetrim_1, hpl_finetrim_3); pr_debug("%s(), [Step3] refine finetriml = %d\n", __func__, finetriml); } if (hpr_base > 0) { finetrimr = pick_hp_finetrim(hpr_base, hpr_finetrim_1, hpr_finetrim_3); pr_debug("%s(), [Step3] refine finetrimr = %d\n", __func__, finetrimr); } } } } } if (hpl_base < 0 || hpr_base < 0) { if (hpl_base < 0) { Ana_Set_Reg(AUDDEC_ELR_0, 0x2 << HPFINETRIM_L_SHIFT, HPFINETRIM_L_MASK); code_change = true; } if (hpr_base < 0) { Ana_Set_Reg(AUDDEC_ELR_0, 0x2 << HPFINETRIM_R_SHIFT, HPFINETRIM_R_MASK); code_change = true; } pr_debug("%s(), step3 < 0 AUDDEC_ELR_0 = 0x%x\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0)); if (code_change) { get_hp_trim_offset(); code_change = false; hpl_min = mHplTrimOffset; hpr_min = mHprTrimOffset; Ana_Set_Reg(AUDDEC_ELR_0, 0x0 << HPFINETRIM_L_SHIFT, HPFINETRIM_L_MASK); Ana_Set_Reg(AUDDEC_ELR_0, 0x0 << HPFINETRIM_R_SHIFT, HPFINETRIM_R_MASK); mdelay(10); if ((hpl_base < 0) && (hpl_min <= 0 || abs(hpl_min) < abs(hpl_base))) finetriml = 0x2; if ((hpr_base < 0) && (hpr_min <= 0 || abs(hpr_min) < abs(hpr_base))) finetrimr = 0x2; } } /* channel L */ Ana_Set_Reg(AUDDEC_ELR_0, finetriml << HPFINETRIM_L_SHIFT, HPFINETRIM_L_MASK); Ana_Set_Reg(AUDDEC_ELR_0, finetrimr << HPFINETRIM_R_SHIFT, HPFINETRIM_R_MASK); pr_debug("%s(), step3 result AUDDEC_ELR_0 = 0x%x\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0)); EXIT: /* 4 pole fine trim */ get_hp_trim_offset(); hpl_min = mHplTrimOffset; hpr_min = mHprTrimOffset; mdelay(10); hp_3pole_anaoffset.hpl_trimecode = trimcodel; hp_3pole_anaoffset.hpl_finetrim = finetriml; hp_3pole_anaoffset.hpr_trimecode = trimcoder; hp_3pole_anaoffset.hpr_finetrim = finetrimr; /* check trimcode is valid */ if ((trimcodel < 0 || trimcodel > 0xf) || (finetriml < 0 || finetriml > 0x3) || (trimcoder < 0 || trimcoder > 0xf) || (finetrimr < 0 || finetrimr > 0x3)) pr_info("%s(), [Warning], invalid trimcode(3pole), trimcodel = %d, finetriml = %d, trimcoder = %d, finetrimr = %d\n", __func__, trimcodel, finetriml, trimcoder, finetrimr); if ((hpl_min < 0) && (finetriml == 0x0)) { finetriml = 0x2; } else if ((hpl_min < 0) && (finetriml == 0x2)) { if ((trimcodel != 0) && (trimcodel != 0xf)) { finetriml = 0x0; trimcodel = trimcodel - ((trimcodel > 7) ? -1 : 1); } else { pr_debug("%s(), [Step4][bit-overflow!!], don't refine, trimcodel = %d, finetriml = %d\n", __func__, trimcodel, finetriml); } } if ((hpr_min < 0) && (finetrimr == 0x0)) { finetrimr = 0x2; } else if ((hpr_min < 0) && (finetrimr == 0x2)) { if ((trimcoder != 0) && (trimcoder != 0xf)) { finetrimr = 0x0; trimcoder = trimcoder - ((trimcoder > 7) ? -1 : 1); } else { pr_debug("%s(), [Step4][bit-overflow!!], don't refine, trimcoder = %d, finetrimr = %d\n", __func__, trimcoder, finetrimr); } } hp_4pole_anaoffset.hpl_trimecode = trimcodel; hp_4pole_anaoffset.hpl_finetrim = finetriml; hp_4pole_anaoffset.hpr_trimecode = trimcoder; hp_4pole_anaoffset.hpr_finetrim = finetrimr; /* check trimcode is valid */ if ((trimcodel < 0 || trimcodel > 0xf) || (finetriml < 0 || finetriml > 0x3) || (trimcoder < 0 || trimcoder > 0xf) || (finetrimr < 0 || finetrimr > 0x3)) pr_info("%s(), [Warning], invalid trimcode(4pole), trimcodel = %d, finetriml = %d, trimcoder = %d, finetrimr = %d\n", __func__, trimcodel, finetriml, trimcoder, finetrimr); hp_3_pole_trim_setting = (hp_3pole_anaoffset.enable << HPTRIM_EN_SHIFT) | (hp_3pole_anaoffset.hpr_finetrim << HPFINETRIM_R_SHIFT) | (hp_3pole_anaoffset.hpl_finetrim << HPFINETRIM_L_SHIFT) | (hp_3pole_anaoffset.hpr_trimecode << HPTRIM_R_SHIFT) | (hp_3pole_anaoffset.hpl_trimecode << HPTRIM_L_SHIFT); hp_4_pole_trim_setting = (hp_4pole_anaoffset.enable << HPTRIM_EN_SHIFT) | (hp_4pole_anaoffset.hpr_finetrim << HPFINETRIM_R_SHIFT) | (hp_4pole_anaoffset.hpl_finetrim << HPFINETRIM_L_SHIFT) | (hp_4pole_anaoffset.hpr_trimecode << HPTRIM_R_SHIFT) | (hp_4pole_anaoffset.hpl_trimecode << HPTRIM_L_SHIFT); pr_debug("%s(), Final result AUDDEC_ELR_0 = 0x%x, hp_3pole_anaoffset= 0x%x, hp_4pole_anaoffset= 0x%x\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0), hp_3_pole_trim_setting, hp_4_pole_trim_setting); pr_debug("%s(), get hp offset L:%d, R:%d\n", __func__, mHplTrimOffset, mHprTrimOffset); } static void set_lr_trim_code_spk(int channel) { int hpl_base = 0; int hpl_min = 0; int hpl_ceiling = 0; int hpl_floor = 0; int hpl_finetrim_2 = 0; int hpl_finetrim_3 = 0; int trimcode = 0; int trimcode_ceiling = 0; int trimcode_floor = 0; int finetrim = 0; int trimcode_tmp = 0; int trim_shift = 0, trim_mask = 0; int fine_shift = 0, fine_mask = 0; if (channel == AUDIO_OFFSET_TRIM_MUX_HPL) { trim_shift = HPTRIM_L_SHIFT; trim_mask = HPTRIM_L_MASK; fine_shift = HPFINETRIM_L_SHIFT; fine_mask = HPFINETRIM_L_MASK; } else if (channel == AUDIO_OFFSET_TRIM_MUX_HPR) { trim_shift = HPTRIM_R_SHIFT; trim_mask = HPTRIM_R_MASK; fine_shift = HPFINETRIM_R_SHIFT; fine_mask = HPFINETRIM_R_MASK; } pr_debug("%s(), Start DCtrim Calibrating, channel = %d, AUDDEC_ELR_0 = 0x%x\n", __func__, channel, Ana_Get_Reg(AUDDEC_ELR_0)); /* Step1: get trim code */ Ana_Set_Reg(AUDDEC_ELR_0, 0x1 << HPTRIM_EN_SHIFT, HPTRIM_EN_MASK); spk_3pole_anaoffset.enable = 0x1; spk_4pole_anaoffset.enable = 0x1; Ana_Set_Reg(AUDDEC_ELR_0, 0x0 << trim_shift, trim_mask); Ana_Set_Reg(AUDDEC_ELR_0, 0x0 << fine_shift, fine_mask); pr_debug("%s(), AUDDEC_ELR_0 = 0x%x\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0)); hpl_base = get_spk_trim_offset(channel); mdelay(10); if (hpl_base == 0) goto EXIT; if (hpl_base > 0) { Ana_Set_Reg(AUDDEC_ELR_0, 0x2 << trim_shift, trim_mask); pr_debug("%s(), step1 > 0 AUDDEC_ELR_0 = 0x%x trimcode = %d\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0), trimcode); hpl_min = get_spk_trim_offset(channel); mdelay(10); /* Check floor and ceiling value to avoid rounding error */ trimcode_floor = (abs(hpl_base)*3)/abs(hpl_base-hpl_min); trimcode_ceiling = trimcode_floor + 1; pr_debug("%s(), step1 > 0, get trim level trimcode_floor = %d, trimcode_ceiling = %d\n", __func__, trimcode_floor, trimcode_ceiling); } else { Ana_Set_Reg(AUDDEC_ELR_0, 0xa << trim_shift, trim_mask); pr_debug("%s(), step1 < 0 AUDDEC_ELR_0 = 0x%x trimcode = %d\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0), trimcode); hpl_min = get_spk_trim_offset(channel); mdelay(10); /* Check floor and ceiling value to avoid rounding error */ trimcode_floor = (abs(hpl_base)*3)/abs(hpl_base-hpl_min) + 8; trimcode_ceiling = trimcode_floor + 1; pr_debug("%s(), step1 < 0, get trim level trimcode_floor = %d, trimcode_ceiling = %d\n", __func__, trimcode_floor, trimcode_ceiling); } /* Get the best trim code from floor and ceiling value */ /* Get floor trim code */ Ana_Set_Reg(AUDDEC_ELR_0, trimcode_floor << trim_shift, trim_mask); pr_debug("%s(), step1 floor AUDDEC_ELR_0 = 0x%x trimcode_floor = %d\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0), trimcode_floor); hpl_floor = get_spk_trim_offset(channel); mdelay(10); /* Get ceiling trim code */ Ana_Set_Reg(AUDDEC_ELR_0, trimcode_ceiling << trim_shift, trim_mask); pr_debug("%s(), step1 floor AUDDEC_ELR_0 = 0x%x trimcode_ceiling = %d\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0), trimcode_ceiling); hpl_ceiling = get_spk_trim_offset(channel); mdelay(10); /* Choose the best */ if (abs(hpl_ceiling) < abs(hpl_floor)) { hpl_base = hpl_ceiling; trimcode = trimcode_ceiling; } else { hpl_base = hpl_floor; trimcode = trimcode_floor; } Ana_Set_Reg(AUDDEC_ELR_0, trimcode << trim_shift, trim_mask); pr_debug("%s(), step1 result AUDDEC_ELR_0 = 0x%x, hp_base = %d, trimcode = %d\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0), hpl_base, trimcode); /* Step2: Trim code refine +1/0/-1 */ hpl_base = get_spk_trim_offset(channel); mdelay(10); if (hpl_base == 0) goto EXIT; if (hpl_base > 0) { if ((trimcode != 0x7) && (trimcode != 0x8)) { trimcode_tmp = trimcode + ((trimcode > 7) ? -1 : 1); Ana_Set_Reg(AUDDEC_ELR_0, trimcode_tmp << trim_shift, trim_mask); pr_debug("%s(), step2 > 0 AUDDEC_ELR_0 = 0x%x trimcode_tmp = %d\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0), trimcode_tmp); hpl_min = get_spk_trim_offset(channel); mdelay(10); if (hpl_min >= 0 || abs(hpl_min) < abs(hpl_base)) { trimcode = trimcode_tmp; hpl_base = hpl_min; } } } else { if ((trimcode != 0) && (trimcode != 0xf)) { trimcode_tmp = trimcode - ((trimcode > 7) ? -1 : 1); Ana_Set_Reg(AUDDEC_ELR_0, trimcode_tmp << trim_shift, trim_mask); pr_debug("%s(), step2 < 0 AUDDEC_ELR_0 = 0x%x trimcode_tmp = %d\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0), trimcode_tmp); hpl_min = get_spk_trim_offset(channel); mdelay(10); if (hpl_min <= 0 || abs(hpl_min) < abs(hpl_base)) { trimcode = trimcode_tmp; hpl_base = hpl_min; } } } Ana_Set_Reg(AUDDEC_ELR_0, trimcode << trim_shift, trim_mask); pr_debug("%s(), step2 result AUDDEC_ELR_0 = 0x%x trimcode = %d\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0), trimcode); /* Step3: Trim code fine tune */ mdelay(10); if (hpl_base == 0) goto EXIT; if (hpl_base > 0) { Ana_Set_Reg(AUDDEC_ELR_0, 0x1 << fine_shift, fine_mask); pr_debug("%s(), step3 > 0 AUDDEC_ELR_0 = 0x%x\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0)); hpl_min = get_spk_trim_offset(channel); mdelay(10); if (hpl_min >= 0 || abs(hpl_min) < abs(hpl_base)) { finetrim = 0x1; hpl_base = hpl_min; } else { Ana_Set_Reg(AUDDEC_ELR_0, 0x3 << fine_shift, fine_mask); pr_debug("%s(), step3_2 > 0 AUDDEC_ELR_0 = 0x%x\n ", __func__, Ana_Get_Reg(AUDDEC_ELR_0)); hpl_min = get_spk_trim_offset(channel); mdelay(10); if (hpl_min >= 0 && abs(hpl_min) < abs(hpl_base)) { finetrim = 0x3; hpl_base = hpl_min; } } } else { /* SPK+HP finetrim=3 compensates positive DC value */ /* choose the best fine trim */ Ana_Set_Reg(AUDDEC_ELR_0, 0x2 << fine_shift, fine_mask); pr_debug("%s(), step3 < 0 AUDDEC_ELR_0 = 0x%x\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0)); hpl_finetrim_2 = get_spk_trim_offset(channel); mdelay(10); if (hpl_finetrim_2 <= 0 && abs(hpl_finetrim_2) < abs(hpl_base)) { finetrim = 0x2; hpl_base = hpl_finetrim_2; } else { /* base and finetrim=2 across zero */ /* Choose best from base, finetrim=2, and finetrim=3 */ Ana_Set_Reg(AUDDEC_ELR_0, 0x3 << fine_shift, fine_mask); pr_debug("%s(), step3_2 < 0 AUDDEC_ELR_0 = 0x%x\n ", __func__, Ana_Get_Reg(AUDDEC_ELR_0)); hpl_finetrim_3 = get_spk_trim_offset(channel); mdelay(10); finetrim = pick_spk_finetrim(hpl_base, hpl_finetrim_2, hpl_finetrim_3); if (finetrim == 0x2) hpl_base = hpl_finetrim_2; else if (finetrim == 0x3) hpl_base = hpl_finetrim_3; } } Ana_Set_Reg(AUDDEC_ELR_0, finetrim << fine_shift, fine_mask); EXIT: spk_3pole_anaoffset.hpl_trimecode = trimcode; spk_3pole_anaoffset.hpl_finetrim = finetrim; spk_3pole_anaoffset.hpr_trimecode = hp_3pole_anaoffset.hpr_trimecode; spk_3pole_anaoffset.hpr_finetrim = hp_3pole_anaoffset.hpr_finetrim; pr_debug("%s(), step3 result AUDDEC_ELR_0 = 0x%x, 3-pole trimcode = %d, finetrim = %d\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0), trimcode, finetrim); /* check trimcode is valid */ if ((trimcode < 0 || trimcode > 0xf) || (finetrim < 0 || finetrim > 0x3)) pr_info("%s(), [Warning], invalid trimcode(3pole), trimcode = %d, finetrim = %d\n", __func__, trimcode, finetrim); /* 4 pole fine trim */ hpl_base = get_spk_trim_offset(channel); mdelay(10); if ((hpl_base < 0) && (finetrim == 0x0)) { finetrim = 0x2; } else if ((hpl_base < 0) && (finetrim == 0x2)) { if ((trimcode != 0) && (trimcode != 0xf)) { finetrim = 0x0; trimcode = trimcode - ((trimcode > 7) ? -1 : 1); } } spk_4pole_anaoffset.hpl_trimecode = trimcode; spk_4pole_anaoffset.hpl_finetrim = finetrim; spk_4pole_anaoffset.hpr_trimecode = hp_4pole_anaoffset.hpr_trimecode; spk_4pole_anaoffset.hpr_finetrim = hp_4pole_anaoffset.hpr_finetrim; pr_debug("%s(), step4 result AUDDEC_ELR_0 = 0x%x, 4-pole trimcode = %d, finetrim = %d\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0), trimcode, finetrim); /* check trimcode is valid */ if ((trimcode < 0 || trimcode > 0xf) || (finetrim < 0 || finetrim > 0x3)) pr_info("%s(), [Warning], invalid trimcode(4pole), trimcode = %d, finetrim = %d\n", __func__, trimcode, finetrim); spk_hp_3_pole_trim_setting = (spk_3pole_anaoffset.enable << HPTRIM_EN_SHIFT) | (spk_3pole_anaoffset.hpr_finetrim << HPFINETRIM_R_SHIFT) | (spk_3pole_anaoffset.hpl_finetrim << HPFINETRIM_L_SHIFT) | (spk_3pole_anaoffset.hpr_trimecode << HPTRIM_R_SHIFT) | (spk_3pole_anaoffset.hpl_trimecode << HPTRIM_L_SHIFT); spk_hp_4_pole_trim_setting = (spk_4pole_anaoffset.enable << HPTRIM_EN_SHIFT) | (spk_4pole_anaoffset.hpr_finetrim << HPFINETRIM_R_SHIFT) | (spk_4pole_anaoffset.hpl_finetrim << HPFINETRIM_L_SHIFT) | (spk_4pole_anaoffset.hpr_trimecode << HPTRIM_R_SHIFT) | (spk_4pole_anaoffset.hpl_trimecode << HPTRIM_L_SHIFT); pr_debug("%s(), Final result AUDDEC_ELR_0 = 0x%x, spk_3pole_anaoffset= 0x%x, spk_4pole_anaoffset= 0x%x\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0), spk_hp_3_pole_trim_setting, spk_hp_4_pole_trim_setting); pr_debug("%s(), get spkl offset : %d\n", __func__, get_spk_trim_offset(channel)); } #endif static void get_hp_lr_trim_offset(void) { pr_debug("%s(), Start DCtrim Calibrating", __func__); #ifdef ANALOG_HPTRIM set_lr_trim_code(); hpl_dc_offset = mHplTrimOffset; hpr_dc_offset = mHprTrimOffset; pr_debug("%s(), hpl_dc_offset: %d, hpr_dc_offset: %d\n", __func__, hpl_dc_offset, hpr_dc_offset); set_lr_trim_code_spk(AUDIO_OFFSET_TRIM_MUX_HPL); spkl_dc_offset = get_spk_trim_offset(AUDIO_OFFSET_TRIM_MUX_HPL); pr_debug("%s(), spkl_dc_offset: %d\n", __func__, spkl_dc_offset); #else hpl_dc_offset = get_hp_trim_offset(AUDIO_OFFSET_TRIM_MUX_HPL); hpr_dc_offset = get_hp_trim_offset(AUDIO_OFFSET_TRIM_MUX_HPR); #endif udelay(1000); dctrim_calibrated = 2; pr_debug("%s(), End DCtrim Calibrating", __func__); } static int mt63xx_codec_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *Daiport) { if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) mBlockSampleRate[ANA_DEV_IN_ADC] = substream->runtime->rate; else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) mBlockSampleRate[ANA_DEV_OUT_DAC] = substream->runtime->rate; return 0; } static const struct snd_soc_dai_ops mt6323_aif1_dai_ops = { .prepare = mt63xx_codec_prepare, }; static struct snd_soc_dai_driver mtk_6358_dai_codecs[] = { { .name = MT_SOC_CODEC_TXDAI_NAME, .ops = &mt6323_aif1_dai_ops, .playback = { .stream_name = MT_SOC_DL1_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SND_SOC_ADV_MT_FMTS, }, }, { .name = MT_SOC_CODEC_RXDAI_NAME, .ops = &mt6323_aif1_dai_ops, .capture = { .stream_name = MT_SOC_UL1_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rates = SOC_HIGH_USE_RATE, .formats = SND_SOC_ADV_MT_FMTS, }, }, { .name = MT_SOC_CODEC_TDMRX_DAI_NAME, .ops = &mt6323_aif1_dai_ops, .capture = { .stream_name = MT_SOC_TDM_CAPTURE_STREAM_NAME, .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_BE | SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_U24_3LE | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3BE | SNDRV_PCM_FMTBIT_S24_3BE | SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_BE | SNDRV_PCM_FMTBIT_S32_BE), }, }, { .name = MT_SOC_CODEC_I2S0TXDAI_NAME, .ops = &mt6323_aif1_dai_ops, .playback = { .stream_name = MT_SOC_I2SDL1_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rate_min = 8000, .rate_max = 192000, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SND_SOC_ADV_MT_FMTS, } }, { .name = MT_SOC_CODEC_DEEPBUFFER_TX_DAI_NAME, .ops = &mt6323_aif1_dai_ops, .playback = { .stream_name = MT_SOC_DEEP_BUFFER_DL_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rate_min = 8000, .rate_max = 192000, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SND_SOC_ADV_MT_FMTS, } }, { .name = MT_SOC_CODEC_VOICE_MD1DAI_NAME, .ops = &mt6323_aif1_dai_ops, .playback = { .stream_name = MT_SOC_VOICE_MD1_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, .formats = SND_SOC_ADV_MT_FMTS, }, .capture = { .stream_name = MT_SOC_VOICE_MD1_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, .formats = SND_SOC_ADV_MT_FMTS, }, }, { .name = MT_SOC_CODEC_VOICE_MD2DAI_NAME, .ops = &mt6323_aif1_dai_ops, .playback = { .stream_name = MT_SOC_VOICE_MD2_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, .formats = SND_SOC_ADV_MT_FMTS, }, .capture = { .stream_name = MT_SOC_VOICE_MD2_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, .formats = SND_SOC_ADV_MT_FMTS, }, }, { .name = MT_SOC_CODEC_SPKSCPTXDAI_NAME, .ops = &mt6323_aif1_dai_ops, .playback = { .stream_name = MT_SOC_DL1SCPSPK_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rate_min = 8000, .rate_max = 192000, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SND_SOC_ADV_MT_FMTS, } }, #ifdef _NON_COMMON_FEATURE_READY { .name = MT_SOC_CODEC_VOICE_ULTRADAI_NAME, .ops = &mt6323_aif1_dai_ops, .playback = { .stream_name = MT_SOC_VOICE_ULTRA_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SND_SOC_ADV_MT_FMTS, }, .capture = { .stream_name = MT_SOC_VOICE_ULTRA_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SND_SOC_ADV_MT_FMTS, }, }, #endif { .name = MT_SOC_CODEC_VOICE_USBDAI_NAME, .ops = &mt6323_aif1_dai_ops, .playback = { .stream_name = MT_SOC_VOICE_USB_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SND_SOC_ADV_MT_FMTS, }, .capture = { .stream_name = MT_SOC_VOICE_USB_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SND_SOC_ADV_MT_FMTS, }, }, { .name = MT_SOC_CODEC_VOICE_USB_ECHOREF_DAI_NAME, .ops = &mt6323_aif1_dai_ops, .playback = { .stream_name = MT_SOC_VOICE_USB_ECHOREF_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SND_SOC_ADV_MT_FMTS, }, .capture = { .stream_name = MT_SOC_VOICE_USB_ECHOREF_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SND_SOC_ADV_MT_FMTS, }, }, { .name = MT_SOC_CODEC_FMI2S2RXDAI_NAME, .ops = &mt6323_aif1_dai_ops, .playback = { .stream_name = MT_SOC_FM_I2S2_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, .formats = SND_SOC_ADV_MT_FMTS, }, .capture = { .stream_name = MT_SOC_FM_I2S2_RECORD_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, .formats = SND_SOC_ADV_MT_FMTS, }, }, { .name = MT_SOC_CODEC_FMMRGTXDAI_DUMMY_DAI_NAME, .ops = &mt6323_aif1_dai_ops, .playback = { .stream_name = MT_SOC_FM_MRGTX_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, .formats = SND_SOC_ADV_MT_FMTS, }, }, { .name = MT_SOC_CODEC_ULDLLOOPBACK_NAME, .ops = &mt6323_aif1_dai_ops, .playback = { .stream_name = MT_SOC_ULDLLOOPBACK_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, .formats = SND_SOC_ADV_MT_FMTS, }, .capture = { .stream_name = MT_SOC_ULDLLOOPBACK_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, .formats = SND_SOC_ADV_MT_FMTS, }, }, { .name = MT_SOC_CODEC_STUB_NAME, .ops = &mt6323_aif1_dai_ops, .playback = { .stream_name = MT_SOC_ROUTING_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SND_SOC_ADV_MT_FMTS, }, }, { .name = MT_SOC_CODEC_RXDAI2_NAME, .capture = { .stream_name = MT_SOC_UL1DATA2_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SND_SOC_ADV_MT_FMTS, }, }, { .name = MT_SOC_CODEC_MRGRX_DAI_NAME, .ops = &mt6323_aif1_dai_ops, .playback = { .stream_name = MT_SOC_MRGRX_STREAM_NAME, .channels_min = 1, .channels_max = 8, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SND_SOC_ADV_MT_FMTS, }, .capture = { .stream_name = MT_SOC_MRGRX_STREAM_NAME, .channels_min = 1, .channels_max = 8, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SND_SOC_ADV_MT_FMTS, }, }, { .name = MT_SOC_CODEC_HP_IMPEDANCE_NAME, .ops = &mt6323_aif1_dai_ops, .playback = { .stream_name = MT_SOC_HP_IMPEDANCE_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SND_SOC_ADV_MT_FMTS, }, }, { .name = MT_SOC_CODEC_FM_I2S_DAI_NAME, .ops = &mt6323_aif1_dai_ops, .playback = { .stream_name = MT_SOC_FM_I2S_PLAYBACK_STREAM_NAME, .channels_min = 1, .channels_max = 8, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SND_SOC_ADV_MT_FMTS, }, }, { .name = MT_SOC_CODEC_TXDAI2_NAME, .ops = &mt6323_aif1_dai_ops, .playback = { .stream_name = MT_SOC_DL2_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SND_SOC_ADV_MT_FMTS, }, }, { .name = MT_SOC_CODEC_OFFLOAD_NAME, .ops = &mt6323_aif1_dai_ops, .playback = { .stream_name = MT_SOC_OFFLOAD_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SND_SOC_ADV_MT_FMTS, }, }, #ifdef _NON_COMMON_FEATURE_READY { .name = MT_SOC_CODEC_ANC_NAME, .ops = &mt6323_aif1_dai_ops, .playback = { .stream_name = MT_SOC_ANC_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, .formats = SND_SOC_ADV_MT_FMTS, }, } #endif }; static void TurnOnDacPower(int device) { pr_debug("%s()\n", __func__); /* gpio mosi mode */ set_playback_gpio(true); /* Enable AUDGLB */ NvregEnable(true); if (mIsNeedPullDown) { /* Pull-down HPL/R to AVSS28_AUD */ hp_pull_down(true); } /* release HP CMFB gate rstb */ Ana_Set_Reg(AUDDEC_ANA_CON4, 0x1 << 6, 0x1 << 6); /* XO_AUDIO_EN_M Enable */ audckbufEnable(true); /* Enable CLKSQ */ ClsqEnable(true); /* Turn on AUDNCP_CLKDIV engine clock, Turn on AUD 26M*/ Topck_Enable(true); usleep_range(250, 270); /* Audio system digital clock power down release */ Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x0000, 0x00c5); usleep_range(250, 270); /* sdm audio fifo clock power on */ Ana_Set_Reg(AFUNC_AUD_CON2, 0x0006, 0xffff); /* scrambler clock on enable */ Ana_Set_Reg(AFUNC_AUD_CON0, 0xCBA1, 0xffff); /* sdm power on */ Ana_Set_Reg(AFUNC_AUD_CON2, 0x0003, 0xffff); /* sdm fifo enable */ Ana_Set_Reg(AFUNC_AUD_CON2, 0x000B, 0xffff); /* afe enable, dl_lr_swap = 0 */ Ana_Set_Reg(AFE_UL_DL_CON0, 0x0001, 0x4001); setDlMtkifSrc(true); } static void TurnOffDacPower(void) { pr_debug("%s()\n", __func__); setDlMtkifSrc(false); /* DL scrambler disabling sequence */ Ana_Set_Reg(AFUNC_AUD_CON2, 0x0000, 0xffff); Ana_Set_Reg(AFUNC_AUD_CON0, 0xcba0, 0xffff); if (GetAdcStatus() == false) { Ana_Set_Reg(AFE_UL_DL_CON0, 0x0000, 0x0001); /* turn off afe */ /* all power down */ Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x00ff, 0x00ff); } else { /* down-link power down */ Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x0040, 0x0040); } usleep_range(250, 270); set_playback_gpio(false); Topck_Enable(false); ClsqEnable(false); /* Set HP CMFB gate rstb */ Ana_Set_Reg(AUDDEC_ANA_CON4, 0x0, 0x1 << 6); if (mIsNeedPullDown) { /* disable Pull-down HPL/R to AVSS28_AUD */ hp_pull_down(false); } NvregEnable(false); audckbufEnable(false); } static void setDlMtkifSrc(bool enable) { pr_debug("%s(), enable = %d, freq = %d\n", __func__, enable, mBlockSampleRate[ANA_DEV_OUT_DAC]); if (enable) { Ana_Set_Reg(AFE_DL_SRC2_CON0_L, 0x0001, 0xffff); /* turn on dl */ Ana_Set_Reg(PMIC_AFE_TOP_CON0, 0x0000, 0xffff); /* set DL in normal path, not from sine gen table */ } else { Ana_Set_Reg(AFE_DL_SRC2_CON0_L, 0x0000, 0xffff); /* bit0, Turn off down-link */ } } static void Audio_Amp_Change(int channels, bool enable) { pr_debug("%s(), enable %d, HSL %d, HSR %d\n", __func__, enable, mCodec_data->dev_power[ANA_DEV_OUT_HEADSETL], mCodec_data->dev_power[ANA_DEV_OUT_HEADSETR]); #ifdef ANALOG_HPTRIM pr_debug("%s(), mic_vinp_mv = %d, dc_compensation_disabled = %d, old trim_setting = 0x%x\n", __func__, mic_vinp_mv, dc_compensation_disabled, Ana_Get_Reg(AUDDEC_ELR_0)); if (!dc_compensation_disabled) { if (mic_vinp_mv > MIC_VINP_4POLE_THRES_MV && ((codec_debug_enable & DBG_DCTRIM_BYPASS_4POLE) == 0)) { Ana_Set_Reg(AUDDEC_ELR_0, hp_4_pole_trim_setting, 0xffff); pr_debug("%s(), set hp_4_pole_trim_setting = 0x%x\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0)); } else { Ana_Set_Reg(AUDDEC_ELR_0, hp_3_pole_trim_setting, 0xffff); pr_debug("%s(), set hp_3_pole_trim_setting = 0x%x\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0)); } } else { Ana_Set_Reg(AUDDEC_ELR_0, 0x0, 0xffff); pr_debug("%s(), dc_compensation_disabled, set trim_setting = 0x%x\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0)); } #endif if (enable) { if (GetDLStatus() == false) TurnOnDacPower(ANA_DEV_OUT_HEADSETL); /* here pmic analog control */ if (mCodec_data->dev_power[ANA_DEV_OUT_HEADSETL] == false && mCodec_data->dev_power[ANA_DEV_OUT_HEADSETR] == false) { /* Disable headphone short-circuit protection */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x3000, 0xffff); /* Reduce ESD resistance of AU_REFN */ Ana_Set_Reg(AUDDEC_ANA_CON2, 0xc000, 0xffff); /* Set HPR/HPL gain to -10dB */ Ana_Set_Reg(ZCD_CON2, DL_GAIN_N_10DB_REG, 0xffff); /* Turn on DA_600K_NCP_VA18 */ Ana_Set_Reg(AUDNCP_CLKDIV_CON1, 0x0001, 0xffff); /* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */ Ana_Set_Reg(AUDNCP_CLKDIV_CON2, 0x002c, 0xffff); /* Toggle RG_DIVCKS_CHG */ Ana_Set_Reg(AUDNCP_CLKDIV_CON0, 0x0001, 0xffff); /* Set NCP soft start mode as default mode: 150us */ Ana_Set_Reg(AUDNCP_CLKDIV_CON4, 0x0002, 0xffff); /* Enable NCP */ Ana_Set_Reg(AUDNCP_CLKDIV_CON3, 0x0000, 0xffff); usleep_range(250, 270); /* Enable cap-less LDOs (1.5V) */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x1055, 0x1055); /* Enable NV regulator (-1.2V) */ Ana_Set_Reg(AUDDEC_ANA_CON15, 0x0001, 0xffff); usleep_range(100, 120); /* Disable AUD_ZCD */ Hp_Zcd_Enable(false); /* Enable IBIST */ Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0055, 0xffff); /* Set HP DR bias current optimization, 010: 6uA */ Ana_Set_Reg(AUDDEC_ANA_CON11, 0x4900, 0xffff); /* Set HP & ZCD bias current optimization */ /* 01: ZCD: 4uA, HP/HS/LO: 5uA */ Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0055, 0xffff); /* Set HPP/N STB enhance circuits */ Ana_Set_Reg(AUDDEC_ANA_CON2, 0xc033, 0xffff); /* Enable HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x000c, 0xffff); /* Enable HP aux feedback loop */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x003c, 0xffff); /* Enable HP aux CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0c00, 0xffff); /* Enable HP driver bias circuits */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x30c0, 0xffff); /* Enable HP driver core circuits */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x30f0, 0xffff); /* Short HP main output to HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x00fc, 0x00ff); /* Enable HP main CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0e00, 0xffff); /* Disable HP aux CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0200, 0xffff); /* Select CMFB resistor bulk to AC mode */ /* Selec HS/LO cap size (6.5pF default) */ Ana_Set_Reg(AUDDEC_ANA_CON10, 0x0000, 0xffff); /* Enable HS driver bias circuits */ /* Disable HS main output stage */ Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0010, 0xffff); /* Enable LO driver bias circuits */ /* Disable LO main output stage */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0010, 0xffff); /* Enable HP main output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x00ff, 0x00ff); /* Enable HPR/L main output stage step by step */ hp_main_output_ramp(true); /* Reduce HP aux feedback loop gain */ hp_aux_feedback_loop_gain_ramp(true); /* Disable HP aux feedback loop */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x3fcf, 0xffff); /* apply volume setting */ headset_volume_ramp(DL_GAIN_N_10DB, mCodec_data->ana_gain[ANA_GAIN_HPOUTL]); /* Disable HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x3fc3, 0xffff); /* Unshort HP main output to HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x3f03, 0xffff); usleep_range(100, 120); /* Enable AUD_CLK */ Ana_Set_Reg(AUDDEC_ANA_CON13, 0x1, 0x1); /* Enable Audio DAC */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0xf, 0xf); /* Enable low-noise mode of DAC */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x1, 0x1); usleep_range(100, 120); /* Switch HPL MUX to audio DAC */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0200, 0x0f00); /* Switch HPR MUX to audio DAC */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0a00, 0x0f00); #ifndef ANALOG_HPTRIM /* Apply digital DC compensation value to DAC */ SetDcCompenSation(true); #endif /* Disable Pull-down HPL/R to AVSS28_AUD */ hp_pull_down(false); } } else { if (mCodec_data->dev_power[ANA_DEV_OUT_HEADSETL] == false && mCodec_data->dev_power[ANA_DEV_OUT_HEADSETR] == false) { /* Pull-down HPL/R to AVSS28_AUD */ hp_pull_down(true); #ifndef ANALOG_HPTRIM SetDcCompenSation(false); #endif /* HPR/HPL mux to open */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0000, 0x0f00); /* Disable low-noise mode of DAC */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0000, 0x0001); /* Disable Audio DAC */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0000, 0x000f); /* Disable AUD_CLK */ Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0, 0x1); /* Short HP main output to HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x3fc3, 0xffff); /* Enable HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x3fcf, 0xffff); /* decrease HPL/R gain to normal gain step by step */ headset_volume_ramp( mCodec_data->ana_gain[ANA_GAIN_HPOUTL], DL_GAIN_N_10DB); /* Enable HP aux feedback loop */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x3fff, 0xffff); /* Reduce HP aux feedback loop gain */ hp_aux_feedback_loop_gain_ramp(false); /* decrease HPR/L main output stage step by step */ hp_main_output_ramp(false); /* Disable HP main output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0, 0x3); /* Enable HP aux CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0e00, 0x0f00); /* Disable HP main CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0c00, 0x0f00); /* Unshort HP main output to HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0, 0x3 << 6); /* Disable HP driver core circuits */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0, 0x3 << 4); /* Disable HP driver bias circuits */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0, 0x3 << 6); /* Disable HP aux CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0000, 0xffff); /* Disable HP aux feedback loop */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0, 0x3 << 4); /* Disable HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0, 0xffff); /* Disable IBIST */ Ana_Set_Reg(AUDDEC_ANA_CON12, 0x1 << 8, 0x1 << 8); /* Disable NV regulator (-1.2V) */ Ana_Set_Reg(AUDDEC_ANA_CON15, 0x0, 0x1); /* Disable cap-less LDOs (1.5V) */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x0, 0x1055); /* Disable NCP */ Ana_Set_Reg(AUDNCP_CLKDIV_CON3, 0x1, 0x1); /* Set HPL/HPR gain to mute */ Ana_Set_Reg(ZCD_CON2, DL_GAIN_N_10DB_REG, 0xffff); /* Increase ESD resistance of AU_REFN */ Ana_Set_Reg(AUDDEC_ANA_CON2, 0x0, 0x1 << 14); if (GetDLStatus() == false) TurnOffDacPower(); } } } static int Audio_AmpL_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = mCodec_data->dev_power[ANA_DEV_OUT_HEADSETL]; return 0; } static int Audio_AmpL_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { mutex_lock(&Ana_Ctrl_Mutex); pr_debug("%s(): enable = %ld, dev_power[ANA_DEV_OUT_HEADSETL] = %d\n", __func__, ucontrol->value.integer.value[0], mCodec_data->dev_power[ANA_DEV_OUT_HEADSETL]); if ((ucontrol->value.integer.value[0] == true) && (mCodec_data->dev_power[ANA_DEV_OUT_HEADSETL] == false)) { Audio_Amp_Change(AUDIO_ANALOG_CHANNELS_LEFT1, true); mCodec_data->dev_power[ANA_DEV_OUT_HEADSETL] = ucontrol->value.integer.value[0]; } else if ((ucontrol->value.integer.value[0] == false) && (mCodec_data->dev_power[ANA_DEV_OUT_HEADSETL] == true)) { mCodec_data->dev_power[ANA_DEV_OUT_HEADSETL] = ucontrol->value.integer.value[0]; Audio_Amp_Change(AUDIO_ANALOG_CHANNELS_LEFT1, false); } mutex_unlock(&Ana_Ctrl_Mutex); return 0; } static int Audio_AmpR_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = mCodec_data->dev_power[ANA_DEV_OUT_HEADSETR]; return 0; } static int Audio_AmpR_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { mutex_lock(&Ana_Ctrl_Mutex); pr_debug("%s(): enable = %ld, dev_power[ANA_DEV_OUT_HEADSETR] = %d\n", __func__, ucontrol->value.integer.value[0], mCodec_data->dev_power[ANA_DEV_OUT_HEADSETR]); if ((ucontrol->value.integer.value[0] == true) && (mCodec_data->dev_power[ANA_DEV_OUT_HEADSETR] == false)) { Audio_Amp_Change(AUDIO_ANALOG_CHANNELS_RIGHT1, true); mCodec_data->dev_power[ANA_DEV_OUT_HEADSETR] = ucontrol->value.integer.value[0]; } else if ((ucontrol->value.integer.value[0] == false) && (mCodec_data->dev_power[ANA_DEV_OUT_HEADSETR] == true)) { mCodec_data->dev_power[ANA_DEV_OUT_HEADSETR] = ucontrol->value.integer.value[0]; Audio_Amp_Change(AUDIO_ANALOG_CHANNELS_RIGHT1, false); } mutex_unlock(&Ana_Ctrl_Mutex); return 0; } static int PMIC_REG_CLEAR_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s()\n", __func__); /* receiver downlink */ set_playback_gpio(true); Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0, 0x1 << 4); /* Pull-down HPL/R to AVSS28_AUD */ hp_pull_down(true); /* release HP CMFB gate rstb */ Ana_Set_Reg(AUDDEC_ANA_CON4, 0x1 << 6, 0x1 << 6); Ana_Set_Reg(DCXO_CW14, 0x1 << 13, 0x1 << 13); Ana_Set_Reg(AUDENC_ANA_CON6, 0x0001, 0x0003); Ana_Set_Reg(AUD_TOP_CKPDN_CON0, 0x0, 0x66); usleep_range(250, 270); /* Audio system digital clock power down release */ Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x0000, 0x00c5); usleep_range(250, 270); /* sdm audio fifo clock power on */ Ana_Set_Reg(AFUNC_AUD_CON2, 0x0006, 0xffff); /* scrambler clock on enable */ Ana_Set_Reg(AFUNC_AUD_CON0, 0xCBA1, 0xffff); /* sdm power on */ Ana_Set_Reg(AFUNC_AUD_CON2, 0x0003, 0xffff); /* sdm fifo enable */ Ana_Set_Reg(AFUNC_AUD_CON2, 0x000B, 0xffff); /* afe enable, dl_lr_swap = 0 */ Ana_Set_Reg(AFE_UL_DL_CON0, 0x0001, 0x4001); setDlMtkifSrc(true); /* Reduce ESD resistance of AU_REFN */ Ana_Set_Reg(AUDDEC_ANA_CON2, 0x4000, 0xffff); /* Turn on DA_600K_NCP_VA18 */ Ana_Set_Reg(AUDNCP_CLKDIV_CON1, 0x0001, 0xffff); /* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */ Ana_Set_Reg(AUDNCP_CLKDIV_CON2, 0x002c, 0xffff); /* Toggle RG_DIVCKS_CHG */ Ana_Set_Reg(AUDNCP_CLKDIV_CON0, 0x0001, 0xffff); /* Set NCP soft start mode as default mode: 100us */ Ana_Set_Reg(AUDNCP_CLKDIV_CON4, 0x0003, 0xffff); /* Enable NCP */ Ana_Set_Reg(AUDNCP_CLKDIV_CON3, 0x0000, 0xffff); usleep_range(250, 270); /* Enable cap-less LDOs (1.5V) */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x1055, 0x1055); /* Enable NV regulator (-1.2V) */ Ana_Set_Reg(AUDDEC_ANA_CON15, 0x0001, 0xffff); usleep_range(100, 120); /* Disable AUD_ZCD */ Hp_Zcd_Enable(false); /* Disable handset short-circuit protection */ Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0010, 0xffff); /* Enable IBIST */ Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0055, 0xffff); /* Set HP DR bias current optimization, 010: 6uA */ Ana_Set_Reg(AUDDEC_ANA_CON11, 0x4900, 0xffff); /* Set HP & ZCD bias current optimization */ /* 01: ZCD: 4uA, HP/HS/LO: 5uA */ Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0055, 0xffff); /* Set HS STB enhance circuits */ Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0090, 0xffff); /* Disable HP main CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0000, 0xffff); /* Select CMFB resistor bulk to AC mode */ /* Selec HS/LO cap size (6.5pF default) */ Ana_Set_Reg(AUDDEC_ANA_CON10, 0x0000, 0xffff); /* Enable HS driver bias circuits */ Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0092, 0xffff); /* Enable HS driver core circuits */ Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0093, 0xffff); /* Set HS gain to normal gain step by step */ Ana_Set_Reg(ZCD_CON3, mCodec_data->ana_gain[ANA_GAIN_HSOUTL], 0xffff); /* Enable AUD_CLK */ Ana_Set_Reg(AUDDEC_ANA_CON13, 0x1, 0x1); /* Enable Audio DAC */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0009, 0xffff); /* Enable low-noise mode of DAC */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0001, 0xffff); /* Switch HS MUX to audio DAC */ Ana_Set_Reg(AUDDEC_ANA_CON6, 0x009b, 0xffff); /* phone mic dcc */ /* Enable audio ADC CLKGEN */ Ana_Set_Reg(AUDDEC_ANA_CON13, 0x1 << 5, 0x1 << 5); /* ADC CLK from CLKGEN (13MHz) */ Ana_Set_Reg(AUDENC_ANA_CON3, 0x0000, 0xffff); /* Enable LCLDO_ENC 1P8V */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x0100, 0x2500); /* LCLDO_ENC remote sense */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x2500, 0x2500); Ana_Set_Reg(AFE_DCCLK_CFG0, 0x2062, 0xffff); Ana_Set_Reg(AFE_DCCLK_CFG0, 0x2062, 0xffff); Ana_Set_Reg(AFE_DCCLK_CFG0, 0x2060, 0xffff); Ana_Set_Reg(AFE_DCCLK_CFG0, 0x2061, 0xffff); Ana_Set_Reg(AFE_DCCLK_CFG1, 0x0100, 0xffff); /* phone mic */ /* Enable MICBIAS0, MISBIAS0 = 1P9V */ Ana_Set_Reg(AUDENC_ANA_CON9, 0x0021, 0xffff); Ana_Set_Reg(AUDENC_ANA_CON0, 0x4 << 8, 0x0700); Ana_Set_Reg(AUDENC_ANA_CON1, 0x4 << 8, 0x0700); /* Audio L preamplifier DCC precharge */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x0004, 0xf8ff); /* "ADC1", main_mic */ /* Audio L preamplifier input sel : AIN0. Enable audio L PGA */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x0045, 0xf0ff); /* Audio L preamplifier DCCEN */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x1 << 1, 0x1 << 1); /* Audio L ADC input sel : L PGA. Enable audio L ADC */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x5047, 0xf000); usleep_range(100, 150); /* Audio L preamplifier DCC precharge off */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x0, 0x1 << 2); /* Audio R preamplifier DCC precharge */ Ana_Set_Reg(AUDENC_ANA_CON1, 0x0004, 0xf8ff); /* ref mic */ /* Audio R preamplifier input sel : AIN2. Enable audio R PGA */ Ana_Set_Reg(AUDENC_ANA_CON1, 0x00c5, 0xf0ff); /* Audio R preamplifier DCCEN */ Ana_Set_Reg(AUDENC_ANA_CON1, 0x1 << 1, 0x1 << 1); /* Audio R ADC input sel : R PGA. Enable audio R ADC */ Ana_Set_Reg(AUDENC_ANA_CON1, 0x50c7, 0xf000); usleep_range(100, 150); /* Audio R preamplifier DCC precharge off */ Ana_Set_Reg(AUDENC_ANA_CON1, 0x0, 0x1 << 2); /* Short body to ground in PGA */ Ana_Set_Reg(AUDENC_ANA_CON3, 0x0, 0x1 << 12); /* here to set digital part */ /* set gpio miso mode */ set_capture_gpio(true); /* power on clock */ Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x0000, 0x00bf); /* configure ADC setting */ Ana_Set_Reg(PMIC_AFE_TOP_CON0, 0x0000, 0xffff); /* [0] afe enable */ Ana_Set_Reg(AFE_UL_DL_CON0, 0x0001, 0x0001); /* MTKAIF TX format setting */ Ana_Set_Reg(PMIC_AFE_ADDA_MTKAIF_CFG0, 0x0000, 0xffff); /* enable aud_pad TX fifos */ Ana_Set_Reg(AFE_AUD_PAD_TOP, 0x3100, 0xff00); /* UL dmic setting */ Ana_Set_Reg(AFE_UL_SRC_CON0_H, 0x0000, 0xffff); /* UL turn on */ Ana_Set_Reg(AFE_UL_SRC_CON0_L, 0x0001, 0xffff); return 0; } static int PMIC_REG_CLEAR_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s(), not support\n", __func__); return 0; } #if 0 /* not used */ static void SetVoiceAmpVolume(void) { int index; pr_debug("%s\n", __func__); index = mCodec_data->ana_gain[ANA_GAIN_HSOUTL]; Ana_Set_Reg(ZCD_CON3, index, 0x001f); } #endif static void Voice_Amp_Change(bool enable) { if (enable) { if (GetDLStatus() == false) { TurnOnDacPower(ANA_DEV_OUT_EARPIECEL); pr_debug("%s(), amp on\n", __func__); /* Reduce ESD resistance of AU_REFN */ Ana_Set_Reg(AUDDEC_ANA_CON2, 0x4000, 0xffff); /* Turn on DA_600K_NCP_VA18 */ Ana_Set_Reg(AUDNCP_CLKDIV_CON1, 0x0001, 0xffff); /* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */ Ana_Set_Reg(AUDNCP_CLKDIV_CON2, 0x002c, 0xffff); /* Toggle RG_DIVCKS_CHG */ Ana_Set_Reg(AUDNCP_CLKDIV_CON0, 0x0001, 0xffff); /* Set NCP soft start mode as default mode: 100us */ Ana_Set_Reg(AUDNCP_CLKDIV_CON4, 0x0003, 0xffff); /* Enable NCP */ Ana_Set_Reg(AUDNCP_CLKDIV_CON3, 0x0000, 0xffff); usleep_range(250, 270); /* Enable cap-less LDOs (1.5V) */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x1055, 0x1055); /* Enable NV regulator (-1.2V) */ Ana_Set_Reg(AUDDEC_ANA_CON15, 0x0001, 0xffff); usleep_range(100, 120); /* Disable AUD_ZCD */ Hp_Zcd_Enable(false); /* Disable handset short-circuit protection */ Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0010, 0xffff); /* Enable IBIST */ Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0055, 0xffff); /* Set HP DR bias current optimization, 010: 6uA */ Ana_Set_Reg(AUDDEC_ANA_CON11, 0x4900, 0xffff); /* Set HP & ZCD bias current optimization */ /* 01: ZCD: 4uA, HP/HS/LO: 5uA */ Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0055, 0xffff); /* Set HS STB enhance circuits */ Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0090, 0xffff); /* Disable HP main CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0000, 0xffff); /* Select CMFB resistor bulk to AC mode */ /* Selec HS/LO cap size (6.5pF default) */ Ana_Set_Reg(AUDDEC_ANA_CON10, 0x0000, 0xffff); /* Enable HS driver bias circuits */ Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0092, 0xffff); /* Enable HS driver core circuits */ Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0093, 0xffff); /* Set HS gain to normal gain step by step */ Ana_Set_Reg(ZCD_CON3, mCodec_data->ana_gain[ANA_GAIN_HSOUTL], 0xffff); /* Enable AUD_CLK */ Ana_Set_Reg(AUDDEC_ANA_CON13, 0x1, 0x1); /* Enable Audio DAC */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0009, 0xffff); /* Enable low-noise mode of DAC */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0001, 0xffff); /* Switch HS MUX to audio DAC */ Ana_Set_Reg(AUDDEC_ANA_CON6, 0x009b, 0xffff); } } else { pr_debug("%s(), amp off\n", __func__); /* HS mux to open */ Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0000, 0x3 << 2); if (GetDLStatus() == false) { /* Disable Audio DAC */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0000, 0x000f); /* Disable AUD_CLK */ Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0, 0x1); /* decrease HS gain to minimum gain step by step */ Ana_Set_Reg(ZCD_CON3, DL_GAIN_N_40DB, 0xffff); /* Disable HS driver core circuits */ Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0, 0x1); /* Disable HS driver bias circuits */ Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0000, 0x1 << 1); /* Disable HP aux CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0, 0xff << 8); /* Enable HP main CMFB Switch */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x2 << 8, 0xff << 8); /* Disable IBIST */ Ana_Set_Reg(AUDDEC_ANA_CON12, 0x1 << 8, 0x1 << 8); /* Disable NV regulator (-1.2V) */ Ana_Set_Reg(AUDDEC_ANA_CON15, 0x0, 0x1); /* Disable cap-less LDOs (1.5V) */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x0, 0x1055); /* Disable NCP */ Ana_Set_Reg(AUDNCP_CLKDIV_CON3, 0x1, 0x1); TurnOffDacPower(); } } } static int Voice_Amp_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s = %d\n", __func__, mCodec_data->dev_power[ANA_DEV_OUT_EARPIECEL]); ucontrol->value.integer.value[0] = mCodec_data->dev_power[ANA_DEV_OUT_EARPIECEL]; return 0; } static int Voice_Amp_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { mutex_lock(&Ana_Ctrl_Mutex); pr_debug("%s()\n", __func__); if ((ucontrol->value.integer.value[0] == true) && (mCodec_data->dev_power[ANA_DEV_OUT_EARPIECEL] == false)) { Voice_Amp_Change(true); mCodec_data->dev_power[ANA_DEV_OUT_EARPIECEL] = ucontrol->value.integer.value[0]; } else if ((ucontrol->value.integer.value[0] == false) && (mCodec_data->dev_power[ANA_DEV_OUT_EARPIECEL] == true)) { mCodec_data->dev_power[ANA_DEV_OUT_EARPIECEL] = ucontrol->value.integer.value[0]; Voice_Amp_Change(false); } mutex_unlock(&Ana_Ctrl_Mutex); return 0; } static void Speaker_Amp_Change(bool enable) { if (enable) { if (GetDLStatus() == false) TurnOnDacPower(ANA_DEV_OUT_SPEAKERL); pr_debug("%s(), enable %d\n", __func__, enable); /* Reduce ESD resistance of AU_REFN */ Ana_Set_Reg(AUDDEC_ANA_CON2, 0x4000, 0xffff); /* Turn on DA_600K_NCP_VA18 */ Ana_Set_Reg(AUDNCP_CLKDIV_CON1, 0x0001, 0xffff); /* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */ Ana_Set_Reg(AUDNCP_CLKDIV_CON2, 0x002c, 0xffff); /* Toggle RG_DIVCKS_CHG */ Ana_Set_Reg(AUDNCP_CLKDIV_CON0, 0x0001, 0xffff); /* Set NCP soft start mode as default mode: 100us */ Ana_Set_Reg(AUDNCP_CLKDIV_CON4, 0x0003, 0xffff); /* Enable NCP */ Ana_Set_Reg(AUDNCP_CLKDIV_CON3, 0x0000, 0xffff); usleep_range(250, 270); /* Enable cap-less LDOs (1.5V) */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x1055, 0x1055); /* Enable NV regulator (-1.2V) */ Ana_Set_Reg(AUDDEC_ANA_CON15, 0x0001, 0xffff); usleep_range(100, 120); /* Disable AUD_ZCD */ Hp_Zcd_Enable(false); /* Disable linout short-circuit protection */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0010, 0xffff); /* Enable IBIST */ Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0055, 0xffff); /* Set HP DR bias current optimization, 010: 6uA */ Ana_Set_Reg(AUDDEC_ANA_CON11, 0x4900, 0xffff); /* Set HP & ZCD bias current optimization */ /* 01: ZCD: 4uA, HP/HS/LO: 5uA */ Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0055, 0xffff); /* Set LO STB enhance circuits */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0110, 0xffff); /* Disable HP main CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0000, 0xffff); /* Select CMFB resistor bulk to AC mode */ /* Selec HS/LO cap size (6.5pF default) */ Ana_Set_Reg(AUDDEC_ANA_CON10, 0x0000, 0xffff); /* Enable LO driver bias circuits */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0112, 0xffff); /* Enable LO driver core circuits */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0113, 0xffff); /* Set LOL gain to normal gain step by step */ Apply_Speaker_Gain( mCodec_data->ana_gain[ANA_GAIN_LINEOUTR]); /* Enable AUD_CLK */ Ana_Set_Reg(AUDDEC_ANA_CON13, 0x1, 0x1); /* Enable Audio DAC */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0009, 0xffff); /* Enable low-noise mode of DAC */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0001, 0xffff); /* Switch LOL MUX to audio DAC */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x011b, 0xffff); } else { pr_debug("%s(), enable %d\n", __func__, enable); /* LOL mux to open */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0000, 0x3 << 2); if (GetDLStatus() == false) { /* Disable Audio DAC */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0000, 0x000f); /* Disable AUD_CLK */ Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0, 0x1); /* decrease LOL gain to minimum gain step by step */ Ana_Set_Reg(ZCD_CON1, DL_GAIN_N_40DB_REG, 0xffff); /* Disable LO driver core circuits */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0, 0x1); /* Disable LO driver bias circuits */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0000, 0x1 << 1); /* Disable HP aux CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0, 0xff << 8); /* Disable IBIST */ Ana_Set_Reg(AUDDEC_ANA_CON12, 0x1 << 8, 0x1 << 8); /* Disable NV regulator (-1.2V) */ Ana_Set_Reg(AUDDEC_ANA_CON15, 0x0, 0x1); /* Disable cap-less LDOs (1.5V) */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x0, 0x1055); /* Disable NCP */ Ana_Set_Reg(AUDNCP_CLKDIV_CON3, 0x1, 0x1); TurnOffDacPower(); } } } static int Speaker_Amp_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = mCodec_data->dev_power[ANA_DEV_OUT_SPEAKERL]; return 0; } static int Speaker_Amp_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s() value = %ld\n ", __func__, ucontrol->value.integer.value[0]); if ((ucontrol->value.integer.value[0] == true) && (mCodec_data->dev_power[ANA_DEV_OUT_SPEAKERL] == false)) { Speaker_Amp_Change(true); mCodec_data->dev_power[ANA_DEV_OUT_SPEAKERL] = ucontrol->value.integer.value[0]; } else if ((ucontrol->value.integer.value[0] == false) && (mCodec_data->dev_power[ANA_DEV_OUT_SPEAKERL] == true)) { mCodec_data->dev_power[ANA_DEV_OUT_SPEAKERL] = ucontrol->value.integer.value[0]; Speaker_Amp_Change(false); } return 0; } static void Ext_Speaker_Amp_Change(bool enable) { #define SPK_WARM_UP_TIME (25) /* unit is ms */ if (enable) { pr_debug("%s() ON+\n", __func__); AudDrv_GPIO_EXTAMP_Select(false, 3); /*udelay(1000); */ usleep_range(1 * 1000, 20 * 1000); AudDrv_GPIO_EXTAMP_Select(true, 3); msleep(SPK_WARM_UP_TIME); pr_debug("%s() ON-\n", __func__); } else { pr_debug("%s(), OFF+\n", __func__); AudDrv_GPIO_EXTAMP_Select(false, 3); udelay(500); pr_debug("%s(), OFF-\n", __func__); } } static int Ext_Speaker_Amp_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = mCodec_data->dev_power[ANA_DEV_OUT_EXTSPKAMP]; return 0; } static int Ext_Speaker_Amp_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { if (ucontrol->value.integer.value[0]) { Ext_Speaker_Amp_Change(true); mCodec_data->dev_power[ANA_DEV_OUT_EXTSPKAMP] = ucontrol->value.integer.value[0]; } else { mCodec_data->dev_power[ANA_DEV_OUT_EXTSPKAMP] = ucontrol->value.integer.value[0]; Ext_Speaker_Amp_Change(false); } return 0; } static void Receiver_Speaker_Switch_Change(bool enable) { #ifndef CONFIG_FPGA_EARLY_PORTING #ifdef CONFIG_OF pr_debug("%s\n", __func__); if (enable) AudDrv_GPIO_RCVSPK_Select(true); else AudDrv_GPIO_RCVSPK_Select(false); #endif #endif } static int Receiver_Speaker_Switch_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s() : %d\n", __func__, mCodec_data->dev_power[ANA_DEV_RECEIVER_SPEAKER_SWITCH]); ucontrol->value.integer.value[0] = mCodec_data->dev_power[ANA_DEV_RECEIVER_SPEAKER_SWITCH]; return 0; } static int Receiver_Speaker_Switch_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s()\n", __func__); if ((ucontrol->value.integer.value[0] == true) && (mCodec_data->dev_power [ANA_DEV_RECEIVER_SPEAKER_SWITCH] == false)) { Receiver_Speaker_Switch_Change(true); mCodec_data->dev_power [ANA_DEV_RECEIVER_SPEAKER_SWITCH] = ucontrol->value.integer.value[0]; } else if ((ucontrol->value.integer.value[0] == false) && (mCodec_data->dev_power [ANA_DEV_RECEIVER_SPEAKER_SWITCH] == true)) { mCodec_data->dev_power [ANA_DEV_RECEIVER_SPEAKER_SWITCH] = ucontrol->value.integer.value[0]; Receiver_Speaker_Switch_Change(false); } return 0; } static void Headset_Speaker_Amp_Change(bool enable) { #ifdef ANALOG_HPTRIM if (apply_n12db_gain) { pr_debug("%s(), current AUDDEC_ELR_0 = 0x%x, mic_vinp_mv %d\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0), mic_vinp_mv); if (mic_vinp_mv > MIC_VINP_4POLE_THRES_MV && ((codec_debug_enable & DBG_DCTRIM_BYPASS_4POLE) == 0)) { Ana_Set_Reg(AUDDEC_ELR_0, spk_4pole_anaoffset.enable << 12 | spk_4pole_anaoffset.hpr_finetrim << 10 | spk_4pole_anaoffset.hpl_finetrim << 8 | spk_4pole_anaoffset.hpr_trimecode << 4 | spk_4pole_anaoffset.hpl_trimecode << 0, 0xffff); } else { Ana_Set_Reg(AUDDEC_ELR_0, spk_3pole_anaoffset.enable << 12 | spk_3pole_anaoffset.hpr_finetrim << 10 | spk_3pole_anaoffset.hpl_finetrim << 8 | spk_3pole_anaoffset.hpr_trimecode << 4 | spk_3pole_anaoffset.hpl_trimecode << 0, 0xffff); } pr_debug("%s(), new AUDDEC_ELR_0 0x%x\n", __func__, Ana_Get_Reg(AUDDEC_ELR_0)); } #endif if (enable) { if (GetDLStatus() == false) TurnOnDacPower(ANA_DEV_OUT_SPEAKER_HEADSET_L); pr_debug("%s(), enable %d\n", __func__, enable); if (apply_n12db_gain) Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0004, 0xff); /* Audio left headphone input multiplexor selection : LOL*/ set_input_mux(1); /* Disable headphone short-circuit protection */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x3000, 0xf0ff); /* Disable lineout short-ckt protection */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x1 << 4, 0x1 << 4); /* Reduce ESD resistance of AU_REFN */ Ana_Set_Reg(AUDDEC_ANA_CON2, 0xc000, 0xffff); /* Set HPL/HPR gain to -10dB*/ Ana_Set_Reg(ZCD_CON2, DL_GAIN_N_10DB_REG, 0xffff); /* Set LOLR/LOLL gain to -10dB */ Ana_Set_Reg(ZCD_CON1, DL_GAIN_N_10DB_REG, 0xffff); /* Turn on DA_600K_NCP_VA18 */ Ana_Set_Reg(AUDNCP_CLKDIV_CON1, 0x0001, 0xffff); /* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */ Ana_Set_Reg(AUDNCP_CLKDIV_CON2, 0x002c, 0xffff); /* Toggle RG_DIVCKS_CHG */ Ana_Set_Reg(AUDNCP_CLKDIV_CON0, 0x0001, 0xffff); /* Set NCP soft start mode as default mode: 150us */ Ana_Set_Reg(AUDNCP_CLKDIV_CON4, 0x0002, 0xffff); /* Enable NCP */ Ana_Set_Reg(AUDNCP_CLKDIV_CON3, 0x0000, 0xffff); udelay(250); /* Enable cap-less LDOs (1.5V), LCLDO local sense */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x1055, 0x1055); /* Enable NV regulator (-1.2V) */ Ana_Set_Reg(AUDDEC_ANA_CON15, 0x0001, 0xffff); udelay(100); /* Disable AUD_ZCD */ Hp_Zcd_Enable(false); /* Enable IBIST */ Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0055, 0xffff); /* Set HP DR bias current optimization, 010: 6uA */ Ana_Set_Reg(AUDDEC_ANA_CON11, 0x4900, 0xffff); /* Set HP & ZCD bias current optimization */ /* 01: ZCD: 4uA, HP/HS/LO: 5uA */ Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0055, 0xffff); /* Set HPP/N STB enhance circuits */ Ana_Set_Reg(AUDDEC_ANA_CON2, 0xc033, 0xffff); if (apply_n12db_gain) { /* HP IVBUF (Vin path) de-gain enable: -12dB */ Ana_Set_Reg(AUDDEC_ANA_CON10, 0x04, 0xff); } /* Set LO STB enhance circuits */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x1 << 8, 0x1 << 8); /* Enable LO driver bias circuits */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x1 << 1, 0x1 << 1); /* Enable LO driver core circuits */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x1, 0x1); /* Set LOL gain to normal gain step by step */ Ana_Set_Reg(ZCD_CON1, DL_GAIN_N_10DB_REG, 0xffff); /* Switch HPL MUX to Line-out */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x01 << 8, 0x3 << 8); /* Switch HPR MUX to DAC-R */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x2 << 10, 0x3 << 10); /* Enable HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0c, 0xff); /* Enable HP aux feedback loop */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x3c, 0xff); /* Enable HP aux CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0c00, 0xff00); /* Enable HP driver bias circuits */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0xc0, 0xf0); /* Enable HP driver core circuits */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0xf0, 0xf0); /* Short HP main output to HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0xfc, 0xff); /* Enable HP main CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0e00, 0xff00); /* Disable HP aux CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0200, 0xff00); /* Select CMFB resistor bulk to AC mode */ /* Selec HS/LO cap size (6.5pF default) */ Ana_Set_Reg(AUDDEC_ANA_CON10, 0x0000, 0xffff); /* Enable HS driver bias circuits */ /* Disable HS main output stage */ Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0010, 0xffff); /* Enable LO driver bias circuits */ /* Disable LO main output stage */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0010, 0xffff); /* Enable LO main output stage */ enable_lo_buffer(true); Apply_Speaker_Gain(DL_GAIN_0DB); /* Enable HP main output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x00ff, 0x00ff); /* Enable HPR/L main output stage step by step */ hp_main_output_ramp(true); /* Reduce HP aux feedback loop gain step by step */ hp_aux_feedback_loop_gain_ramp(true); /* Disable HP aux feedback loop */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x00cf, 0x00ff); /* Increase HPL/HPR gain to normal gain step by step */ headset_volume_ramp(DL_GAIN_N_10DB, mCodec_data->ana_gain[ANA_GAIN_HPOUTL]); /* Disable HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x00c3, 0x00ff); /* Unshort HP main output to HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0003, 0x00ff); udelay(1000); /* HP ESD resistor @AU_REFN short enable */ Ana_Set_Reg(AUDDEC_ANA_CON2, 0xc033, 0xffff); /* Enable AUD_CLK */ Ana_Set_Reg(AUDDEC_ANA_CON13, 0x1, 0x1); /* Enable Audio DAC */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0xf, 0xf); /* Enable low-noise mode of DAC */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x1, 0x1); udelay(100); /* Switch LOL MUX to audio DAC */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x2 << 2, 0x3 << 2); /* Disable Pull-down HPL/R to AVSS28_AUD */ hp_pull_down(false); } else { pr_debug("%s(), enable %d\n", __func__, enable); if (GetDLStatus() == false) { /* Pull-down HPL/R to AVSS28_AUD */ hp_pull_down(true); /* Disable low-noise mode of DAC */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0, 0x1); /* Disable Audio DAC */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0, 0xf); /* Disable AUD_CLK */ Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0, 0x1); /* Short HP main output to HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x3fc3, 0xffff); /* Enable HP aux output stage*/ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x3fcf, 0xffff); /* decrease HPL/R gain to normal gain step by step */ headset_volume_ramp( mCodec_data->ana_gain[ANA_GAIN_HPOUTL], DL_GAIN_N_10DB); Ana_Set_Reg(ZCD_CON1, DL_GAIN_N_10DB_REG, 0xffff); /* set HP aux feedback loop gain to max */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0xf200, 0xff00); /* Enable HP aux feedback loop */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0xff, 0xff); /* Reduce HP aux feedback loop gain */ hp_aux_feedback_loop_gain_ramp(false); /* decrease HPR/L main output stage step by step */ hp_main_output_ramp(false); /* Switch HPL/HPR MUX to open */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0 << 8, 0xf << 8); /* Switch LOL MUX to open */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0 << 2, 0x3 << 2); /* Disable HP main output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0, 0x3); /* Enable HP aux CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0e00, 0x0f00); /* Disable HP main CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0c00, 0x0f00); /* Unshort HP main output to HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0, 0x3 << 6); /* Disable HP driver core circuits */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x30c0, 0xffff); /* Disable HP driver bias circuits */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x3000, 0xffff); /* Disable HP aux CMFB loop */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x0, 0xffff); /* Open HP aux feedback loop */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0xc, 0xffff); /* Disable HP aux output stage */ Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0, 0xffff); /* decrease LOL gain to minimum gain step by step */ Ana_Set_Reg(ZCD_CON1, DL_GAIN_N_40DB_REG, 0xffff); /* Disable LO driver core circuits */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0, 0x1); /* Disable LO driver bias circuits */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0 << 1, 0x1 << 1); /* Disable IBIST */ Ana_Set_Reg(AUDDEC_ANA_CON12, 0x1 << 8, 0x1 << 8); /* Disable NV regulator (-1.2V) */ Ana_Set_Reg(AUDDEC_ANA_CON15, 0x0, 0x1); /* Disable cap-less LDOs (1.5V) */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x0, 0x1055); /* Disable NCP */ Ana_Set_Reg(AUDNCP_CLKDIV_CON3, 0x1, 0x1); /* Set HPL/HPR gain to mute */ Ana_Set_Reg(ZCD_CON2, DL_GAIN_N_40DB_REG, 0xffff); /* Increase ESD resistance of AU_REFN */ Ana_Set_Reg(AUDDEC_ANA_CON2, 0x0, 0x1 << 14); TurnOffDacPower(); } } } static int Headset_Speaker_Amp_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s()\n", __func__); ucontrol->value.integer.value[0] = mCodec_data->dev_power[ANA_DEV_OUT_SPEAKER_HEADSET_R]; return 0; } static int Headset_Speaker_Amp_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); */ pr_debug("%s() gain = %lu\n ", __func__, ucontrol->value.integer.value[0]); if ((ucontrol->value.integer.value[0] == true) && (mCodec_data->dev_power [ANA_DEV_OUT_SPEAKER_HEADSET_R] == false)) { Headset_Speaker_Amp_Change(true); mCodec_data->dev_power [ANA_DEV_OUT_SPEAKER_HEADSET_R] = ucontrol->value.integer.value[0]; } else if ((ucontrol->value.integer.value[0] == false) && (mCodec_data->dev_power [ANA_DEV_OUT_SPEAKER_HEADSET_R] == true)) { mCodec_data->dev_power [ANA_DEV_OUT_SPEAKER_HEADSET_R] = ucontrol->value.integer.value[0]; Headset_Speaker_Amp_Change(false); } return 0; } static int Audio_AuxAdcData_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = 0; pr_debug("%s dMax = 0x%lx\n", __func__, ucontrol->value.integer.value[0]); return 0; } static int Audio_AuxAdcData_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { dAuxAdcChannel = ucontrol->value.integer.value[0]; pr_debug("%s dAuxAdcChannel = 0x%x\n", __func__, dAuxAdcChannel); return 0; } static const struct snd_kcontrol_new Audio_snd_auxadc_controls[] = { SOC_SINGLE_EXT("Audio AUXADC Data", SND_SOC_NOPM, 0, 0x80000, 0, Audio_AuxAdcData_Get, Audio_AuxAdcData_Set), }; static const char *const amp_function[] = { "Off", "On" }; static const char *const aud_clk_buf_function[] = { "Off", "On" }; static const char *const DAC_DL_PGA_Headset_GAIN[] = { "8Db", "7Db", "6Db", "5Db", "4Db", "3Db", "2Db", "1Db", "0Db", "-1Db", "-2Db", "-3Db", "-4Db", "-5Db", "-6Db", "-7Db", "-8Db", "-9Db", "-10Db", "-40Db" }; static const char *const DAC_DL_PGA_Handset_GAIN[] = { "8Db", "7Db", "6Db", "5Db", "4Db", "3Db", "2Db", "1Db", "0Db", "-1Db", "-2Db", "-3Db", "-4Db", "-5Db", "-6Db", "-7Db", "-8Db", "-9Db", "-10Db", "-40Db" }; static const char *const DAC_DL_PGA_Speaker_GAIN[] = { "8Db", "7Db", "6Db", "5Db", "4Db", "3Db", "2Db", "1Db", "0Db", "-1Db", "-2Db", "-3Db", "-4Db", "-5Db", "-6Db", "-7Db", "-8Db", "-9Db", "-10Db", "-40Db" }; /* static const char *Voice_Mux_function[] = {"Voice", "Speaker"}; */ static int Lineout_PGAL_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = mCodec_data->ana_gain[ANA_GAIN_LINEOUTL]; if (ucontrol->value.integer.value[0] == DL_GAIN_N_40DB) ucontrol->value.integer.value[0] = ARRAY_SIZE(DAC_DL_PGA_Speaker_GAIN) - 1; return 0; } static int Lineout_PGAL_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int index = ucontrol->value.integer.value[0]; if (index >= ARRAY_SIZE(DAC_DL_PGA_Speaker_GAIN)) { pr_warn("return -EINVAL\n"); return -EINVAL; } if (index == (ARRAY_SIZE(DAC_DL_PGA_Speaker_GAIN) - 1)) index = DL_GAIN_N_40DB; Ana_Set_Reg(ZCD_CON1, index, 0x001f); mCodec_data->ana_gain[ANA_GAIN_LINEOUTL] = index; return 0; } static int Lineout_PGAR_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = mCodec_data->ana_gain[ANA_GAIN_LINEOUTR]; if (ucontrol->value.integer.value[0] == DL_GAIN_N_40DB) ucontrol->value.integer.value[0] = ARRAY_SIZE(DAC_DL_PGA_Speaker_GAIN) - 1; return 0; } static int Lineout_PGAR_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int index = ucontrol->value.integer.value[0]; if (index >= ARRAY_SIZE(DAC_DL_PGA_Speaker_GAIN)) { pr_warn("return -EINVAL\n"); return -EINVAL; } if (index == (ARRAY_SIZE(DAC_DL_PGA_Speaker_GAIN) - 1)) index = DL_GAIN_N_40DB; Ana_Set_Reg(ZCD_CON1, index << 7, 0x0f80); mCodec_data->ana_gain[ANA_GAIN_LINEOUTR] = index; return 0; } static int Handset_PGA_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = mCodec_data->ana_gain[ANA_GAIN_HSOUTL]; if (ucontrol->value.integer.value[0] == DL_GAIN_N_40DB) ucontrol->value.integer.value[0] = ARRAY_SIZE(DAC_DL_PGA_Handset_GAIN) - 1; return 0; } static int Handset_PGA_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int index = ucontrol->value.integer.value[0]; if (index >= ARRAY_SIZE(DAC_DL_PGA_Handset_GAIN)) { pr_warn("return -EINVAL\n"); return -EINVAL; } if (index == (ARRAY_SIZE(DAC_DL_PGA_Handset_GAIN) - 1)) index = DL_GAIN_N_40DB; Ana_Set_Reg(ZCD_CON3, index, 0x001f); mCodec_data->ana_gain[ANA_GAIN_HSOUTL] = index; return 0; } static int Headset_PGAL_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s() = %d\n", __func__, mCodec_data->ana_gain[ANA_GAIN_HPOUTL]); ucontrol->value.integer.value[0] = mCodec_data->ana_gain[ANA_GAIN_HPOUTL]; if (ucontrol->value.integer.value[0] == DL_GAIN_N_40DB) ucontrol->value.integer.value[0] = ARRAY_SIZE(DAC_DL_PGA_Headset_GAIN) - 1; return 0; } static int Headset_PGAL_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int index = ucontrol->value.integer.value[0]; int old_idx = mCodec_data->ana_gain[ANA_GAIN_HPOUTL]; if (index >= ARRAY_SIZE(DAC_DL_PGA_Headset_GAIN)) { pr_warn("return -EINVAL\n"); return -EINVAL; } if (index == (ARRAY_SIZE(DAC_DL_PGA_Headset_GAIN) - 1)) index = DL_GAIN_N_40DB; mCodec_data->ana_gain[ANA_GAIN_HPOUTL] = index; mCodec_data->ana_gain[ANA_GAIN_HPOUTR] = index; if (mCodec_data->dev_power[ANA_DEV_OUT_HEADSETL]) { headset_volume_ramp(old_idx, index); #ifndef ANALOG_HPTRIM SetDcCompenSation(true); #endif } return 0; } static int Headset_PGAR_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = mCodec_data->ana_gain[ANA_GAIN_HPOUTR]; if (ucontrol->value.integer.value[0] == DL_GAIN_N_40DB) ucontrol->value.integer.value[0] = ARRAY_SIZE(DAC_DL_PGA_Headset_GAIN) - 1; return 0; } static int Headset_PGAR_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int index = ucontrol->value.integer.value[0]; int old_idx = mCodec_data->ana_gain[ANA_GAIN_HPOUTR]; pr_debug("%s(), index = %d\n", __func__, index); if (index >= ARRAY_SIZE(DAC_DL_PGA_Headset_GAIN)) { pr_warn("return -EINVAL\n"); return -EINVAL; } if (index == (ARRAY_SIZE(DAC_DL_PGA_Headset_GAIN) - 1)) index = DL_GAIN_N_40DB; mCodec_data->ana_gain[ANA_GAIN_HPOUTL] = index; mCodec_data->ana_gain[ANA_GAIN_HPOUTR] = index; if (mCodec_data->dev_power[ANA_DEV_OUT_HEADSETR]) { headset_volume_ramp(old_idx, index); #ifndef ANALOG_HPTRIM SetDcCompenSation(true); #endif } return 0; } static int codec_adc_sample_rate_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s mBlockSampleRate[ANA_DEV_IN_ADC] = %d\n", __func__, mBlockSampleRate[ANA_DEV_IN_ADC]); ucontrol->value.integer.value[0] = mBlockSampleRate[ANA_DEV_IN_ADC]; return 0; } static int codec_adc_sample_rate_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { mBlockSampleRate[ANA_DEV_IN_ADC] = ucontrol->value.integer.value[0]; pr_debug("%s mBlockSampleRate[ANA_DEV_IN_ADC] = %d\n", __func__, mBlockSampleRate[ANA_DEV_IN_ADC]); return 0; } static int codec_dac_sample_rate_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s mBlockSampleRate[ANA_DEV_OUT_DAC] = %d\n", __func__, mBlockSampleRate[ANA_DEV_OUT_DAC]); ucontrol->value.integer.value[0] = mBlockSampleRate[ANA_DEV_OUT_DAC]; return 0; } static int codec_dac_sample_rate_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { mBlockSampleRate[ANA_DEV_OUT_DAC] = ucontrol->value.integer.value[0]; pr_debug("%s mBlockSampleRate[ANA_DEV_OUT_DAC] = %d\n", __func__, mBlockSampleRate[ANA_DEV_OUT_DAC]); return 0; } static int Aud_Clk_Buf_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = audck_buf_Count; return 0; } static int Aud_Clk_Buf_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { if (ucontrol->value.integer.value[0]) audckbufEnable(true); else audckbufEnable(false); return 0; } static int pmic_dc_offset_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s(), %d, %d\n", __func__, hpl_dc_offset, hpr_dc_offset); pr_debug("%s(), hp_trim(3pole/4pole) = 0x%x/0x%x, hp+spk_trim(3pole/4pole) = 0x%x/0x%x\n", __func__, hp_3_pole_trim_setting, hp_4_pole_trim_setting, spk_hp_3_pole_trim_setting, spk_hp_4_pole_trim_setting); ucontrol->value.integer.value[0] = hpl_dc_offset; ucontrol->value.integer.value[1] = hpr_dc_offset; return 0; } static int pmic_dc_offset_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s(), %ld, %ld\n", __func__, ucontrol->value.integer.value[0], ucontrol->value.integer.value[1]); hpl_dc_offset = ucontrol->value.integer.value[0]; hpr_dc_offset = ucontrol->value.integer.value[1]; return 0; } #ifdef ANALOG_HPTRIM static int disable_pmic_dctrim_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s(), dc_compensation_disabled: %d\n", __func__, dc_compensation_disabled); ucontrol->value.integer.value[0] = dc_compensation_disabled; return 0; } static int disable_pmic_dctrim_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s(), dc_compensation_disabled: %ld\n", __func__, ucontrol->value.integer.value[0]); dc_compensation_disabled = ucontrol->value.integer.value[0]; return 0; } #endif static const char * const dctrim_control_state[] = { "Not_Yet", "Calibrating", "Calibrated", "Reset" }; static int pmic_dctrim_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s(), dctrim_calibrated = %d\n", __func__, dctrim_calibrated); ucontrol->value.integer.value[0] = dctrim_calibrated; return 0; } static int pmic_dctrim_control_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { if (ucontrol->value.enumerated.item[0] > ARRAY_SIZE(dctrim_control_state)) { pr_warn("%s(), return -EINVAL\n", __func__); return -EINVAL; } pr_debug("%s()+, dctrim_calibrated = %d\n", __func__, dctrim_calibrated); if (ucontrol->value.integer.value[0] == 1) { get_hp_lr_trim_offset(); } else if (ucontrol->value.integer.value[0] == 3) { memset(&hp_3pole_anaoffset, 0, sizeof(hp_3pole_anaoffset)); memset(&hp_4pole_anaoffset, 0, sizeof(hp_4pole_anaoffset)); memset(&spk_3pole_anaoffset, 0, sizeof(spk_3pole_anaoffset)); memset(&spk_4pole_anaoffset, 0, sizeof(spk_4pole_anaoffset)); dctrim_calibrated = ucontrol->value.integer.value[0]; } else { dctrim_calibrated = ucontrol->value.integer.value[0]; } pr_debug("%s()-, dctrim_calibrated = %d\n", __func__, dctrim_calibrated); return 0; } /* * Temp solution, query gpio of PCB_ID of board */ enum AUDIO_MIC_MODE { AUDIO_MIC_MODE_ACC = 1, AUDIO_MIC_MODE_DCC, AUDIO_MIC_MODE_DMIC, AUDIO_MIC_MODE_DMIC_LP, AUDIO_MIC_MODE_DCCECMDIFF, AUDIO_MIC_MODE_DCCECMSINGLE, }; #ifndef CONFIG_MT8183_QUERY_PCB_ID_METHOD enum pcb_id_index { PCD_ID_1 = 0, /* GPIO175 */ PCD_ID_2 = 1, /* GPIO111 */ PCD_ID_NUM = 2, }; static int get_pcb_id_state(int pcd_id) { struct device_node *node = NULL; int gpionum; int ret = -1; pr_debug("%s\n", __func__); node = of_find_compatible_node(NULL, NULL, "mediatek,mt_soc_codec_63xx"); if (!node) { pr_debug("%s(), cannot find dts node!\n", __func__); return ret; } gpionum = of_get_named_gpio(node, "pcbinfo", pcd_id); if (gpionum < 0) { pr_debug("%s(), cannot find pcbinfo node!\n", __func__); return ret; } ret = gpio_request(gpionum, "info"); if (ret) { pr_debug("%s(), request pcbinfo failed!\n", __func__); return ret; } ret = gpio_get_value(gpionum); pr_debug("%s(), gpio(%d) value = %d\n", __func__, gpionum, ret); gpio_free(gpionum); return ret; } #endif static int get_mic_mode(void) { int ret = -1; #ifdef CONFIG_MT8183_QUERY_PCB_ID_METHOD int data[4]; int rawdata; ret = IMM_GetOneChannelValue(2, data, &rawdata); /* * Mapping rule: * * AUXIN2 PCB_ID Mic_Mode * 0~0.5V SMT1 DCC * 0.7~1.1V SMT2 ACC * */ if (ret < 0 || rawdata < 0) { pr_debug("%s(), get auxadc channel value error %d %d\n", __func__, ret, rawdata); return -1; } if ((rawdata >= 0) && (rawdata <= 1366)) ret = AUDIO_MIC_MODE_DCC; else if ((rawdata >= 1911) && (rawdata <= 3004)) ret = AUDIO_MIC_MODE_ACC; else ret = AUDIO_MIC_MODE_ACC; #else int gpioval_1 = 0, gpioval_2 = 0; gpioval_1 = get_pcb_id_state(PCD_ID_1); if (gpioval_1 < 0) { pr_debug("%s(), gpioval_1(%d) invalid\n", __func__, gpioval_1); return ret; } gpioval_2 = get_pcb_id_state(PCD_ID_2); if (gpioval_2 < 0) { pr_debug("%s(), gpioval_2(%d) invalid\n", __func__, gpioval_2); return ret; } /* * Mapping rule: * * PCB_ID2 PCB_ID1 Mic_Mode * 0 0 EVB_DCC * 0 1 Phone_DCC * 1 0 Phone_ACC * 1 1 Reserved * */ if ((gpioval_2 == 0) && (gpioval_1 == 0)) ret = AUDIO_MIC_MODE_DCC; else if ((gpioval_2 == 0) && (gpioval_1 == 1)) ret = AUDIO_MIC_MODE_DCC; else if ((gpioval_2 == 1) && (gpioval_1 == 0)) ret = AUDIO_MIC_MODE_ACC; else ret = AUDIO_MIC_MODE_ACC; #endif pr_debug("%s(), return mic_mode = %d\n", __func__, ret); return ret; } static int Audio_MIC_Mode_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int mic_mode = AUDIO_MIC_MODE_ACC; pr_debug("%s()\n", __func__); mic_mode = get_mic_mode(); if (mic_mode != -1) ucontrol->value.integer.value[0] = mic_mode; else ucontrol->value.integer.value[0] = AUDIO_MIC_MODE_ACC; pr_info("%s(), return MIC_MODE: %ld\n", __func__, ucontrol->value.integer.value[0]); return 0; } static int Audio_MIC_Mode_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s(), not support\n", __func__); return 0; } static int hp_impedance_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { if (!set_hp_impedance_ctl) { pr_warn("%s(), set_hp_impedance_ctl == NULL\n", __func__); return 0; } set_hp_impedance_ctl(true); if (OpenHeadPhoneImpedanceSetting(true)) { hp_impedance = detect_impedance(); OpenHeadPhoneImpedanceSetting(false); } else pr_warn("%s(), pmic dl busy, do nothing\n", __func__); set_hp_impedance_ctl(false); ucontrol->value.integer.value[0] = hp_impedance; pr_debug("%s(), hp_impedance = %d, efuse = %d\n", __func__, hp_impedance, efuse_current_calibrate); return 0; } static int hp_impedance_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s(), hp_impedance = %ld\n", __func__, ucontrol->value.integer.value[0]); return 0; } static int hp_plugged; static int hp_plugged_in_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s(), hp_plugged = %d\n", __func__, hp_plugged); ucontrol->value.integer.value[0] = hp_plugged; return 0; } static int hp_plugged_in_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { if (ucontrol->value.enumerated.item[0] > ARRAY_SIZE(amp_function)) { pr_warn("%s(), return -EINVAL\n", __func__); return -EINVAL; } if (ucontrol->value.integer.value[0] == 1) { mic_vinp_mv = get_accdet_auxadc(); pr_info("%s(), mic_vinp_mv = %d\n", __func__, mic_vinp_mv); } hp_plugged = ucontrol->value.integer.value[0]; return 0; } static const struct soc_enum Audio_DL_Enum[] = { SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(amp_function), amp_function), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(amp_function), amp_function), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(amp_function), amp_function), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(amp_function), amp_function), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(amp_function), amp_function), /* here comes pga gain setting */ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(DAC_DL_PGA_Headset_GAIN), DAC_DL_PGA_Headset_GAIN), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(DAC_DL_PGA_Headset_GAIN), DAC_DL_PGA_Headset_GAIN), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(DAC_DL_PGA_Handset_GAIN), DAC_DL_PGA_Handset_GAIN), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(DAC_DL_PGA_Speaker_GAIN), DAC_DL_PGA_Speaker_GAIN), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(DAC_DL_PGA_Speaker_GAIN), DAC_DL_PGA_Speaker_GAIN), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(aud_clk_buf_function), aud_clk_buf_function), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(amp_function), amp_function), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(amp_function), amp_function), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dctrim_control_state), dctrim_control_state) }; static const struct snd_kcontrol_new mt6358_snd_controls[] = { SOC_ENUM_EXT("Audio_Amp_R_Switch", Audio_DL_Enum[0], Audio_AmpR_Get, Audio_AmpR_Set), SOC_ENUM_EXT("Audio_Amp_L_Switch", Audio_DL_Enum[1], Audio_AmpL_Get, Audio_AmpL_Set), SOC_ENUM_EXT("Voice_Amp_Switch", Audio_DL_Enum[2], Voice_Amp_Get, Voice_Amp_Set), SOC_ENUM_EXT("Speaker_Amp_Switch", Audio_DL_Enum[3], Speaker_Amp_Get, Speaker_Amp_Set), SOC_ENUM_EXT("Headset_Speaker_Amp_Switch", Audio_DL_Enum[4], Headset_Speaker_Amp_Get, Headset_Speaker_Amp_Set), SOC_ENUM_EXT("Headset_PGAL_GAIN", Audio_DL_Enum[5], Headset_PGAL_Get, Headset_PGAL_Set), SOC_ENUM_EXT("Headset_PGAR_GAIN", Audio_DL_Enum[6], Headset_PGAR_Get, Headset_PGAR_Set), SOC_ENUM_EXT("Handset_PGA_GAIN", Audio_DL_Enum[7], Handset_PGA_Get, Handset_PGA_Set), SOC_ENUM_EXT("Lineout_PGAR_GAIN", Audio_DL_Enum[8], Lineout_PGAR_Get, Lineout_PGAR_Set), SOC_ENUM_EXT("Lineout_PGAL_GAIN", Audio_DL_Enum[9], Lineout_PGAL_Get, Lineout_PGAL_Set), SOC_ENUM_EXT("AUD_CLK_BUF_Switch", Audio_DL_Enum[10], Aud_Clk_Buf_Get, Aud_Clk_Buf_Set), SOC_ENUM_EXT("Ext_Speaker_Amp_Switch", Audio_DL_Enum[11], Ext_Speaker_Amp_Get, Ext_Speaker_Amp_Set), SOC_ENUM_EXT("Receiver_Speaker_Switch", Audio_DL_Enum[11], Receiver_Speaker_Switch_Get, Receiver_Speaker_Switch_Set), SOC_ENUM_EXT("PMIC_REG_CLEAR", Audio_DL_Enum[12], PMIC_REG_CLEAR_Get, PMIC_REG_CLEAR_Set), SOC_SINGLE_EXT("Codec_ADC_SampleRate", SND_SOC_NOPM, 0, MAX_UL_SAMPLE_RATE, 0, codec_adc_sample_rate_get, codec_adc_sample_rate_set), SOC_SINGLE_EXT("Codec_DAC_SampleRate", SND_SOC_NOPM, 0, MAX_DL_SAMPLE_RATE, 0, codec_dac_sample_rate_get, codec_dac_sample_rate_set), SOC_DOUBLE_EXT("DcTrim_DC_Offset", SND_SOC_NOPM, 0, 1, 0x20000, 0, pmic_dc_offset_get, pmic_dc_offset_set), SOC_ENUM_EXT("Dctrim_Control_Switch", Audio_DL_Enum[13], pmic_dctrim_control_get, pmic_dctrim_control_set), SOC_SINGLE_EXT("Audio HP ImpeDance Setting", SND_SOC_NOPM, 0, 0x10000, 0, hp_impedance_get, hp_impedance_set), SOC_ENUM_EXT("Headphone Plugged In", Audio_DL_Enum[0], hp_plugged_in_get, hp_plugged_in_set), SOC_SINGLE_EXT("Audio_MIC_Mode", SND_SOC_NOPM, 0, 6, 0, Audio_MIC_Mode_Get, Audio_MIC_Mode_Set), #ifdef ANALOG_HPTRIM SOC_ENUM_EXT("Disable Analog DC Compensation", Audio_DL_Enum[0], disable_pmic_dctrim_get, disable_pmic_dctrim_set), #endif }; void SetMicPGAGain(void) { int index = 0; index = mCodec_data->ana_gain[ANA_GAIN_MICAMP1]; pr_debug("%s ANA_GAIN_MICAMP1 index =%d\n", __func__, index); Ana_Set_Reg(AUDENC_ANA_CON0, index << 8, 0x0700); index = mCodec_data->ana_gain[ANA_GAIN_MICAMP2]; Ana_Set_Reg(AUDENC_ANA_CON1, index << 8, 0x0700); } static bool GetAdcStatus(void) { int i = 0; for (i = ANA_DEV_IN_ADC1; i < ANA_DEV_MAX; i++) { if ((mCodec_data->dev_power[i] == true) && (i != ANA_DEV_RECEIVER_SPEAKER_SWITCH)) return true; } return false; } static bool TurnOnADcPowerACC(int ADCType, bool enable) { pr_debug("%s ADCType = %d enable = %d\n", __func__, ADCType, enable); if (enable) { if (GetAdcStatus() == false) { audckbufEnable(true); /* Enable audio globe bias */ NvregEnable(true); /* Enable CLKSQ 26MHz */ ClsqEnable(true); /* Enable audio ADC CLKGEN */ Ana_Set_Reg(AUDDEC_ANA_CON13, 0x1 << 5, 0x1 << 5); /* ADC CLK from CLKGEN (13MHz) */ Ana_Set_Reg(AUDENC_ANA_CON3, 0x0000, 0xffff); /* Enable LCLDO_ENC 1P8V */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x0100, 0x2500); /* LCLDO_ENC remote sense */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x2500, 0x2500); /* mic bias */ if (mCodec_data->ana_mux[MICSOURCE_MUX_IN_1] == 0) { /* phone mic */ /* Enable MICBIAS0, MISBIAS0 = 1P9V */ Ana_Set_Reg(AUDENC_ANA_CON9, 0x0021, 0xffff); } else if (mCodec_data->ana_mux[MICSOURCE_MUX_IN_1] == 1) { /* headset mic */ /* Enable MICBIAS1, MISBIAS1 = 2P6V */ Ana_Set_Reg(AUDENC_ANA_CON10, 0x0061, 0xffff); } SetMicPGAGain(); } if (ADCType == ANA_DEV_IN_ADC1) { if (mCodec_data->ana_mux[MICSOURCE_MUX_IN_1] == 0) { /* "ADC1", main_mic */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x0041, 0xf0ff); Ana_Set_Reg(AUDENC_ANA_CON0, 0x5041, 0xf000); } else if (mCodec_data->ana_mux[MICSOURCE_MUX_IN_1] == 1) { /* "ADC2", headset mic */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x0081, 0xf0ff); Ana_Set_Reg(AUDENC_ANA_CON0, 0x5081, 0xf000); } } else if (ADCType == ANA_DEV_IN_ADC2) { /* ref mic */ Ana_Set_Reg(AUDENC_ANA_CON1, 0x00c1, 0xf0ff); /* Audio R ADC input sel : R PGA. Enable audio R ADC */ Ana_Set_Reg(AUDENC_ANA_CON1, 0x50c1, 0xf000); } if (GetAdcStatus() == false) { /* set gpio miso mode */ set_capture_gpio(true); /* here to set digital part */ Topck_Enable(true); /* power on clock */ Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x0000, 0x00bf); /* configure ADC setting */ Ana_Set_Reg(PMIC_AFE_TOP_CON0, 0x0000, 0xffff); /* [0] afe enable */ Ana_Set_Reg(AFE_UL_DL_CON0, 0x0001, 0x0001); /* MTKAIF TX format setting */ Ana_Set_Reg(PMIC_AFE_ADDA_MTKAIF_CFG0, 0x0000, 0xffff); /* enable aud_pad TX fifos */ Ana_Set_Reg(AFE_AUD_PAD_TOP, 0x3100, 0xff00); /* UL dmic setting */ Ana_Set_Reg(AFE_UL_SRC_CON0_H, 0x0000, 0xffff); /* UL turn on */ Ana_Set_Reg(AFE_UL_SRC_CON0_L, 0x0001, 0xffff); } } else { if (GetAdcStatus() == false) { /* UL turn off */ Ana_Set_Reg(AFE_UL_SRC_CON0_L, 0x0000, 0x0001); /* disable aud_pad TX fifos */ Ana_Set_Reg(AFE_AUD_PAD_TOP, 0x3000, 0xff00); if (GetDLStatus() == false) { /* afe disable */ Ana_Set_Reg(AFE_UL_DL_CON0, 0x0000, 0x0001); /* afe power down and total audio clk disable */ Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x00ff, 0x00ff); } /* up-link power down */ Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x0020, 0x0020); set_capture_gpio(false); } if (ADCType == ANA_DEV_IN_ADC1) { Ana_Set_Reg(AUDENC_ANA_CON0, 0x0000, 0xf000); /* Audio L ADC input sel : off, disable audio L ADC */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x0000, 0x0fff); /* Disable audio L PGA */ } else if (ADCType == ANA_DEV_IN_ADC2) { Ana_Set_Reg(AUDENC_ANA_CON1, 0x0000, 0xf000); /* Audio R ADC input sel : off, disable audio R ADC */ Ana_Set_Reg(AUDENC_ANA_CON1, 0x0000, 0x0fff); /* Disable audio R PGA */ } if (GetAdcStatus() == false) { /* mic bias */ if (mCodec_data->ana_mux[MICSOURCE_MUX_IN_1] == 0) { /* phone mic */ /* Disable MICBIAS0, MISBIAS0 = 1P7V */ Ana_Set_Reg(AUDENC_ANA_CON9, 0x0000, 0xffff); } else if (mCodec_data->ana_mux[MICSOURCE_MUX_IN_1] == 1) { /* headset mic */ /* Disable MICBIAS1 */ Ana_Set_Reg(AUDENC_ANA_CON10, 0x0000, 0x0001); } /* LCLDO_ENC remote sense off */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x0100, 0x2500); /* disable LCLDO_ENC 1P8V */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x0000, 0x2500); /* ADC CLK from CLKGEN (13MHz) */ Ana_Set_Reg(AUDENC_ANA_CON3, 0x0000, 0xffff); /* disable audio ADC CLKGEN */ Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0 << 5, 0x1 << 5); /* AdcClockEnable(false); */ Topck_Enable(false); /* ClsqAuxEnable(false); */ ClsqEnable(false); NvregEnable(false); audckbufEnable(false); } } return true; } static bool TurnOnADcPowerDmic(int ADCType, bool enable) { pr_debug("%s(), ADCType = %d enable = %d\n", __func__, ADCType, enable); if (enable) { if (GetAdcStatus() == false) { if (set_ap_dmic != NULL) set_ap_dmic(true); else pr_warn("%s(), set_ap_dmic == NULL\n", __func__); audckbufEnable(true); /* Enable audio globe bias */ NvregEnable(true); /* Enable CLKSQ 26MHz */ ClsqEnable(true); /* mic bias */ /* Enable MICBIAS0, MISBIAS0 = 1P9V */ Ana_Set_Reg(AUDENC_ANA_CON9, 0x0021, 0xffff); /* RG_BANDGAPGEN=1'b0 */ Ana_Set_Reg(AUDENC_ANA_CON10, 0x0, 0x1 << 12); /* DMIC enable */ Ana_Set_Reg(AUDENC_ANA_CON8, 0x0005, 0xffff); /* here to set digital part */ /* set gpio miso mode */ set_capture_gpio(true); /* AdcClockEnable(true); */ Topck_Enable(true); /* power on clock */ Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x0000, 0x00bf); /* configure ADC setting */ Ana_Set_Reg(PMIC_AFE_TOP_CON0, 0x0000, 0xffff); /* [0] afe enable */ Ana_Set_Reg(AFE_UL_DL_CON0, 0x0001, 0x0001); /* MTKAIF TX format setting */ Ana_Set_Reg(PMIC_AFE_ADDA_MTKAIF_CFG0, 0x0000, 0xffff); /* enable aud_pad TX fifos */ Ana_Set_Reg(AFE_AUD_PAD_TOP, 0x3100, 0xff00); /* UL dmic setting */ Ana_Set_Reg(AFE_UL_SRC_CON0_H, 0x0080, 0xffff); /* UL turn on */ Ana_Set_Reg(AFE_UL_SRC_CON0_L, 0x0003, 0xffff); } } else { if (GetAdcStatus() == false) { /* UL turn off */ Ana_Set_Reg(AFE_UL_SRC_CON0_L, 0x0000, 0x0003); /* disable aud_pad TX fifos */ Ana_Set_Reg(AFE_AUD_PAD_TOP, 0x3000, 0xff00); if (GetDLStatus() == false) { /* afe disable */ Ana_Set_Reg(AFE_UL_DL_CON0, 0x0000, 0x0001); /* afe power down and total audio clk disable */ Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x00ff, 0x00ff); } /* up-link power down */ Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x0020, 0x0020); set_capture_gpio(false); /* DMIC disable */ Ana_Set_Reg(AUDENC_ANA_CON8, 0x0000, 0xffff); /* mic bias */ /* MISBIAS0 = 1P7V */ Ana_Set_Reg(AUDENC_ANA_CON9, 0x0001, 0xffff); /* RG_BANDGAPGEN=1'b0 */ Ana_Set_Reg(AUDENC_ANA_CON10, 0x0, 0x1 << 12); /* MICBIA0 disable */ Ana_Set_Reg(AUDENC_ANA_CON9, 0x0000, 0xffff); /* AdcClockEnable(false); */ Topck_Enable(false); /* ClsqAuxEnable(false); */ ClsqEnable(false); NvregEnable(false); audckbufEnable(false); } } return true; } static bool TurnOnADcPowerDCC(int ADCType, bool enable, int ECMmode) { pr_debug("%s(), enable %d, ADCType %d, MICSOURCE_MUX_IN_1 %d, ECMmode %d\n", __func__, enable, ADCType, mCodec_data->ana_mux[MICSOURCE_MUX_IN_1], ECMmode); if (enable) { if (GetAdcStatus() == false) { audckbufEnable(true); /* Enable audio globe bias */ NvregEnable(true); /* Enable CLKSQ 26MHz */ ClsqEnable(true); /* Enable audio ADC CLKGEN */ Ana_Set_Reg(AUDDEC_ANA_CON13, 0x1 << 5, 0x1 << 5); /* ADC CLK from CLKGEN (13MHz) */ Ana_Set_Reg(AUDENC_ANA_CON3, 0x0000, 0xffff); /* Enable LCLDO_ENC 1P8V */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x0100, 0x2500); /* LCLDO_ENC remote sense */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x2500, 0x2500); /* AdcClockEnable(true); */ Topck_Enable(true); Ana_Set_Reg(AFE_DCCLK_CFG0, 0x2062, 0xffff); Ana_Set_Reg(AFE_DCCLK_CFG0, 0x2062, 0xffff); Ana_Set_Reg(AFE_DCCLK_CFG0, 0x2060, 0xffff); Ana_Set_Reg(AFE_DCCLK_CFG0, 0x2061, 0xffff); Ana_Set_Reg(AFE_DCCLK_CFG1, 0x0100, 0xffff); /* mic bias */ if (mCodec_data->ana_mux[MICSOURCE_MUX_IN_1] == 0) { /* phone mic */ switch (ECMmode) { case 1: /* AUDIO_MIC_MODE_DCCECMDIFF */ Ana_Set_Reg(AUDENC_ANA_CON9, 0x7700, 0xff00); break; case 2:/* AUDIO_MIC_MODE_DCCECMSINGLE */ Ana_Set_Reg(AUDENC_ANA_CON9, 0x1100, 0xff00); break; default: Ana_Set_Reg(AUDENC_ANA_CON9, 0x0000, 0xff00); break; } /* Enable MICBIAS0, MISBIAS0 = 1P9V */ Ana_Set_Reg(AUDENC_ANA_CON9, 0x0021, 0x00ff); } else if (mCodec_data->ana_mux[MICSOURCE_MUX_IN_1] == 1) { /* headset mic */ /* Enable MICBIAS1, MISBIAS1 = 2P6V */ if (ECMmode == 2) Ana_Set_Reg(AUDENC_ANA_CON10, 0x0161, 0xffff); else Ana_Set_Reg(AUDENC_ANA_CON10, 0x0061, 0xffff); } SetMicPGAGain(); } if (ADCType == ANA_DEV_IN_ADC1) { /* Audio L preamplifier DCC precharge */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x0004, 0xf8ff); if (mCodec_data->ana_mux[MICSOURCE_MUX_IN_1] == 0) { /* "ADC1", main_mic */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x0045, 0xf0ff); /* Audio L preamplifier DCCEN */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x1 << 1, 0x1 << 1); Ana_Set_Reg(AUDENC_ANA_CON0, 0x5047, 0xf000); } else if (mCodec_data->ana_mux[MICSOURCE_MUX_IN_1] == 1) { /* "ADC2", headset mic */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x0085, 0xf0ff); /* Audio L preamplifier DCCEN */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x1 << 1, 0x1 << 1); Ana_Set_Reg(AUDENC_ANA_CON0, 0x5087, 0xf000); } usleep_range(100, 150); /* Audio L preamplifier DCC precharge off */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x0, 0x1 << 2); } else if (ADCType == ANA_DEV_IN_ADC2) { /* Audio R preamplifier DCC precharge */ Ana_Set_Reg(AUDENC_ANA_CON1, 0x0004, 0xf8ff); /* ref mic */ Ana_Set_Reg(AUDENC_ANA_CON1, 0x00c5, 0xf0ff); /* Audio R preamplifier DCCEN */ Ana_Set_Reg(AUDENC_ANA_CON1, 0x1 << 1, 0x1 << 1); /* Audio R ADC input sel : R PGA. Enable audio R ADC */ Ana_Set_Reg(AUDENC_ANA_CON1, 0x50c7, 0xf000); usleep_range(100, 150); /* Audio R preamplifier DCC precharge off */ Ana_Set_Reg(AUDENC_ANA_CON1, 0x0, 0x1 << 2); } if (GetAdcStatus() == false) { /* Short body to ground in PGA */ Ana_Set_Reg(AUDENC_ANA_CON3, 0x0, 0x1 << 12); /* here to set digital part */ /* set gpio miso mode */ set_capture_gpio(true); /* power on clock */ Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x0000, 0x00bf); /* configure ADC setting */ Ana_Set_Reg(PMIC_AFE_TOP_CON0, 0x0000, 0xffff); /* [0] afe enable */ Ana_Set_Reg(AFE_UL_DL_CON0, 0x0001, 0x0001); /* MTKAIF TX format setting */ Ana_Set_Reg(PMIC_AFE_ADDA_MTKAIF_CFG0, 0x0000, 0xffff); /* enable aud_pad TX fifos */ Ana_Set_Reg(AFE_AUD_PAD_TOP, 0x3100, 0xff00); /* UL dmic setting */ Ana_Set_Reg(AFE_UL_SRC_CON0_H, 0x0000, 0xffff); /* UL turn on */ Ana_Set_Reg(AFE_UL_SRC_CON0_L, 0x0001, 0xffff); } } else { if (GetAdcStatus() == false) { /* UL turn off */ Ana_Set_Reg(AFE_UL_SRC_CON0_L, 0x0000, 0x0001); /* disable aud_pad TX fifos */ Ana_Set_Reg(AFE_AUD_PAD_TOP, 0x3000, 0xff00); if (GetDLStatus() == false) { /* afe disable */ Ana_Set_Reg(AFE_UL_DL_CON0, 0x0000, 0x0001); /* afe power down and total audio clk disable */ Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x00ff, 0x00ff); } /* up-link power down */ Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x0020, 0x0020); set_capture_gpio(false); } if (ADCType == ANA_DEV_IN_ADC1) { /* Audio L ADC input sel : off, disable audio L ADC */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x0000, 0xf000); /* Audio L preamplifier DCCEN */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x0 << 1, 0x1 << 1); Ana_Set_Reg(AUDENC_ANA_CON0, 0x0000, 0xfffb); /* Disable audio L PGA */ /* disable Audio L preamplifier DCC precharge */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x0, 0x1 << 2); } else if (ADCType == ANA_DEV_IN_ADC2) { /* Audio R ADC input sel : off, disable audio R ADC */ Ana_Set_Reg(AUDENC_ANA_CON1, 0x0000, 0xf000); /* Audio r preamplifier DCCEN */ Ana_Set_Reg(AUDENC_ANA_CON1, 0x0 << 1, 0x1 << 1); Ana_Set_Reg(AUDENC_ANA_CON1, 0x0000, 0x0ffb); /* Disable audio R PGA */ /* disable Audio R preamplifier DCC precharge */ Ana_Set_Reg(AUDENC_ANA_CON1, 0x0, 0x1 << 2); } if (GetAdcStatus() == false) { /* mic bias */ if (mCodec_data->ana_mux[MICSOURCE_MUX_IN_1] == 0) { /* phone mic */ /* Disable MICBIAS0, MISBIAS0 = 1P7V */ Ana_Set_Reg(AUDENC_ANA_CON9, 0x0000, 0xffff); } else if (mCodec_data->ana_mux[MICSOURCE_MUX_IN_1] == 1) { /* headset mic */ /* Disable MICBIAS1 */ Ana_Set_Reg(AUDENC_ANA_CON10, 0x0000, 0x0001); } /* dcclk_gen_on=1'b0 */ Ana_Set_Reg(AFE_DCCLK_CFG0, 0x2060, 0xffff); /* dcclk_pdn=1'b1 */ Ana_Set_Reg(AFE_DCCLK_CFG0, 0x2062, 0xffff); /* dcclk_ref_ck_sel=2'b00 */ Ana_Set_Reg(AFE_DCCLK_CFG0, 0x2062, 0xffff); /* dcclk_div=11'b00100000011 */ Ana_Set_Reg(AFE_DCCLK_CFG0, 0x2062, 0xffff); /* LCLDO_ENC remote sense off */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x0100, 0x2500); /* disable LCLDO_ENC 1P8V */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x0000, 0x2500); /* ADC CLK from CLKGEN (13MHz) */ Ana_Set_Reg(AUDENC_ANA_CON3, 0x0000, 0xffff); /* disable audio ADC CLKGEN */ Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0 << 5, 0x1 << 5); /* AdcClockEnable(false); */ Topck_Enable(false); /* ClsqAuxEnable(false); */ ClsqEnable(false); NvregEnable(false); audckbufEnable(false); } } return true; } static bool TurnOnVOWDigitalHW(bool enable) { #ifdef CONFIG_MTK_VOW_SUPPORT pr_debug("%s enable = %d\n", __func__, enable); if (enable) { /*move to vow driver*/ #ifdef VOW_STANDALONE_CONTROL if (mAudio_VOW_Mic_type == VOW_MIC_TYPE_Handset_DMIC) Ana_Set_Reg(AFE_VOW_TOP, 0x6850, 0xffff); else Ana_Set_Reg(AFE_VOW_TOP, 0x4810, 0xffff); #endif } else { /*disable VOW interrupt here*/ #ifdef VOW_STANDALONE_CONTROL /*move to vow driver*/ Ana_Set_Reg(AFE_VOW_TOP, 0x4010, 0xffff); /*VOW disable*/ Ana_Set_Reg(AFE_VOW_TOP, 0xC010, 0xffff); #endif } #endif return true; } #ifdef CONFIG_MTK_VOW_SUPPORT static void TurnOnVOWPeriodicOnOff(int MicType, int On_period, int enable) { int i = 0; const unsigned short (*pBuf)[22]; /* give a default value */ pBuf = Handset_AMIC_DCC_PeriodicOnOff; if ((MicType == VOW_MIC_TYPE_Headset_MIC) || (MicType == VOW_MIC_TYPE_Handset_AMIC) || (MicType == VOW_MIC_TYPE_Handset_DMIC) || (MicType == VOW_MIC_TYPE_Handset_DMIC_800K) || (MicType == VOW_MIC_TYPE_Handset_DMIC_VENDOR01) || (MicType >= VOW_MIC_TYPE_NUM) || (MicType < 0)) { pr_debug("MicType:%d, No support periodic On/Off\n", MicType); return; } if (enable == 0) { VOW32KCK_Enable(false); Ana_Set_Reg(AFE_VOW_PERIODIC_CFG13, 0x8000, 0x8000); Ana_Set_Reg(AFE_VOW_PERIODIC_CFG14, 0x0000, 0x8000); for (i = 0; i < 22; i++) Ana_Set_Reg(AFE_VOW_PERIODIC_CFG2 + (i<<1), 0x0000, 0xFFFF); /* Set Period */ Ana_Set_Reg(AFE_VOW_PERIODIC_CFG0, 0x0000, 0xFFFF); } else { pr_debug("%s, On_period:%d\n", __func__, 100 - (On_period * 10)); VOW32KCK_Enable(true); switch (MicType) { case VOW_MIC_TYPE_Handset_AMIC_DCC: case VOW_MIC_TYPE_Handset_AMIC_DCCECM: pBuf = Handset_AMIC_DCC_PeriodicOnOff; break; case VOW_MIC_TYPE_Headset_MIC_DCC: case VOW_MIC_TYPE_Headset_MIC_DCCECM: pBuf = Headset_MIC_DCC_PeriodicOnOff; break; default: break; } if (On_period > 0) { /* */ /* 32k_switch, [15]=0 */ Ana_Set_Reg(AFE_VOW_PERIODIC_CFG13, 0x0000, 0x8000); /* vow_snrdet_periodic_cfg = 1 */ Ana_Set_Reg(AFE_VOW_PERIODIC_CFG14, 0x8000, 0x8000); for (i = 0; i < 22; i++) { Ana_Set_Reg(AFE_VOW_PERIODIC_CFG2 + (i<<1), pBuf[On_period - 1][i], 0xFFFF); } } else { Ana_Set_Reg(AFE_VOW_PERIODIC_CFG13, 0x8000, 0x8000); Ana_Set_Reg(AFE_VOW_PERIODIC_CFG14, 0x0000, 0x8000); for (i = 0; i < 22; i++) Ana_Set_Reg(AFE_VOW_PERIODIC_CFG2 + (i<<1), 0x0000, 0xFFFF); } /* Set Period */ Ana_Set_Reg(AFE_VOW_PERIODIC_CFG0, 0x999A, 0xFFFF); pr_debug("AFE_VOW_PERIODIC_CFG0:%x\n", Ana_Get_Reg(AFE_VOW_PERIODIC_CFG0)); } } static void VOW_GPIO_Enable(bool enable) { pr_debug("%s():%x\n", __func__, enable); if (enable == true) { /* set AP side GPIO */ /* Enable AUD_DAT_MISO1 */ /* Enable AUD_DAT_MISO0 */ AudDrv_GPIO_Request(true, Soc_Aud_Digital_Block_ADDA_VOW); /* set PMIC side GPIO */ Ana_Set_Reg(GPIO_MODE3, 0x0120, 0x01F8); /* GPIO Set to VOW data */ } else { /* set AP side GPIO */ /* Disable AUD_DAT_MISO1 */ /* Disable AUD_DAT_MISO0 */ AudDrv_GPIO_Request(false, Soc_Aud_Digital_Block_ADDA_VOW); /* set PMIC GPIO */ Ana_Set_Reg(GPIO_MODE3, 0x0240, 0x01F8); /* GPIO Set to VOW data */ } } static void VOW_Pwr_Enable(int MicType, bool enable) { if ((MicType >= VOW_MIC_TYPE_NUM) || (MicType < 0)) { pr_debug("%s(),Not support this Mic Type\n", __func__); return; } if (enable == true) { NvregEnable(true); /* 0x0D04 Enable audio globe bias */ if ((MicType != VOW_MIC_TYPE_Handset_DMIC) && (MicType != VOW_MIC_TYPE_Handset_DMIC_800K)) { /* Enable Audio ADC flash Audio ADC flash */ Ana_Set_Reg(AUDENC_ANA_CON2, 0x003F, 0x0039); } /* XO_AUDIO_EN_M Enable */ Ana_Set_Reg(DCXO_CW14, 0xA25B, 0x2000); /* Enable audio ADC CLKGEN */ Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0020, 0x0020); /* Enable XO_AUDIO_VOW */ Ana_Set_Reg(AUDENC_ANA_CON1, 0x0800, 0x0800); /* Enable XO_VOW */ Ana_Set_Reg(DCXO_CW13, 0x9929, 0x0100); if ((MicType != VOW_MIC_TYPE_Handset_DMIC) && (MicType != VOW_MIC_TYPE_Handset_DMIC_800K)) { /* Enable VOW CLKSQ */ Ana_Set_Reg(AUDENC_ANA_CON1, 0x8800, 0x8000); /* Enable LCLDO_ENC 1P8V */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x0100, 0x0100); /* LCLDO_ENC remote sense */ Ana_Set_Reg(AUDDEC_ANA_CON14, 0x2500, 0x2400); } } else { if ((MicType != VOW_MIC_TYPE_Handset_DMIC) && (MicType != VOW_MIC_TYPE_Handset_DMIC_800K)) { Ana_Set_Reg(AUDDEC_ANA_CON14, 0x0100, 0x2400); Ana_Set_Reg(AUDENC_ANA_CON3, 0x0000, 0x000C); /* Disable VOW CLKSQ */ Ana_Set_Reg(AUDENC_ANA_CON1, 0x0800, 0x8000); } /* Disable XO_VOW */ Ana_Set_Reg(DCXO_CW13, 0x9829, 0x0100); /* Disable XO_AUDIO_VOW */ Ana_Set_Reg(AUDENC_ANA_CON1, 0x0000, 0x0800); /* XO_AUDIO_EN_M Enable, [13] xo_audio_en_m */ Ana_Set_Reg(DCXO_CW14, 0xA2B5, 0x2000); if ((MicType != VOW_MIC_TYPE_Handset_DMIC) && (MicType != VOW_MIC_TYPE_Handset_DMIC_800K)) { /* Disable Audio ADC flash Audio ADC flash */ Ana_Set_Reg(AUDENC_ANA_CON2, 0x0000, 0x0039); } NvregEnable(false); /* 0x0D04 Disable audio globe bias */ } } static void VOW_DCC_CLK_Enable(bool enable) { unsigned int pmic_version = Ana_Get_Reg(SWCID); if (enable == true) { VOW13MCK_Enable(true); /* 0x0258 VOW13M_CK power on */ /* DCC mode MT6358 E1 and E2 work around */ if ((pmic_version == 0x5810) || (pmic_version == 0x5820)) ClsqEnable(true); /* PGA DCC CLK divider */ Ana_Set_Reg(AFE_DCCLK_CFG0, 0x2062, 0xFFE0); /* DCC power down control: DCC clk output */ Ana_Set_Reg(AFE_DCCLK_CFG0, 0x2060, 0x0002); /* DCC generate enable*/ Ana_Set_Reg(AFE_DCCLK_CFG0, 0x2061, 0x0001); /* DCCLK resync bypass */ Ana_Set_Reg(AFE_DCCLK_CFG1, 0x0100, 0x0100); } else { /* Disable PGA DCC CLK */ Ana_Set_Reg(AFE_DCCLK_CFG0, 0x2060, 0x0001); /* VOW source clock power off */ Ana_Set_Reg(AFE_DCCLK_CFG0, 0x2062, 0x0002); /* PGA DCC CLK divider */ Ana_Set_Reg(AFE_DCCLK_CFG0, 0x2062, 0xFFE0); /* DCC mode MT6358 E1 and E2 work around */ if ((pmic_version == 0x5810) || (pmic_version == 0x5820)) ClsqEnable(false); VOW13MCK_Enable(false); /*VOW clock power down enable*/ } } static void VOW_ACC_CLK_Enable(bool enable) { unsigned int pmic_version = Ana_Get_Reg(SWCID); if (enable == true) { VOW13MCK_Enable(true); /* VOW13M_CK power on */ /* DCC mode MT6358 E1 work around */ if (pmic_version == 0x5810) ClsqEnable(true); /* VOW source clock power on, vow_1p6m_800k_sel=1.6m */ Ana_Set_Reg(AFE_VOW_TOP, 0x4000, 0x8000); } else { Ana_Set_Reg(AFE_VOW_TOP, 0xC000, 0x8000); /* DCC mode MT6358 E1 work around */ if (pmic_version == 0x5810) ClsqEnable(false); VOW13MCK_Enable(false); /*VOW clock power down enable*/ } } static void VOW_DMIC_CLK_Enable(bool enable) { if (enable == true) { VOW13MCK_Enable(true); /* 0x0258 VOW13M_CK power on */ /* 0x2070 VOW source clock power on, vow_1p6m_800k_sel=1.6m */ Ana_Set_Reg(AFE_VOW_TOP, 0x4000, 0x8000); } else { Ana_Set_Reg(AFE_VOW_TOP, 0xC000, 0x8000); /*0x2070*/ VOW13MCK_Enable(false); /*VOW clock power down enable*/ } } static void VOW_MIC_DCC_Enable(int MicType, bool enable) { if ((MicType >= VOW_MIC_TYPE_NUM) || (MicType < 0)) { pr_debug("%s(),Not support this Mic Type\n", __func__); return; } if (enable == true) { Ana_Set_Reg(AUDENC_ANA_CON3, 0x0009, 0X000D); /* for little signal be broken issue */ Ana_Set_Reg(AUDENC_ANA_CON5, 0x0030, 0xFFFF); switch (MicType) { case VOW_MIC_TYPE_Handset_AMIC_DCC: case VOW_MIC_TYPE_Handset_AMIC_DCCECM: Ana_Set_Reg(AUDENC_ANA_CON9, 0x0025, 0x0075); if (MicType == VOW_MIC_TYPE_Handset_AMIC_DCCECM) Ana_Set_Reg(AUDENC_ANA_CON9, 0x0700, 0x0700); else Ana_Set_Reg(AUDENC_ANA_CON9, 0x0000, 0x0700); /* 0x0D08 Enable audio L PGA */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x0347, 0x07C7); break; case VOW_MIC_TYPE_Headset_MIC_DCC: case VOW_MIC_TYPE_Headset_MIC_DCCECM: Ana_Set_Reg(AUDENC_ANA_CON11, 0x00F1, 0x00F1); if (MicType == VOW_MIC_TYPE_Headset_MIC_DCCECM) Ana_Set_Reg(AUDENC_ANA_CON11, 0x0002, 0x0006); else Ana_Set_Reg(AUDENC_ANA_CON11, 0x0000, 0x0006); /* 0x0D08 Enable audio L PGA */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x0387, 0x07C7); break; default: break; } /* 0x0D08 Audio L ADC input sel : L PGA, Enable audio L ADC */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x5347, 0x7000); msleep(20);/* delay */ /* 0x0D08 Audio L PGA DCC precharge off */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x5343, 0x0004); } else { /* Audio L ADC input sel : off, Disable audio L ADC */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x0343, 0x7000); /* Disable audio L PGA */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x0000, 0x07C7); switch (MicType) { case VOW_MIC_TYPE_Handset_AMIC_DCC: case VOW_MIC_TYPE_Handset_AMIC_DCCECM: Ana_Set_Reg(AUDENC_ANA_CON9, 0x0000, 0x0075); break; case VOW_MIC_TYPE_Headset_MIC_DCC: case VOW_MIC_TYPE_Headset_MIC_DCCECM: /* Disable MICBIAS1 */ Ana_Set_Reg(AUDENC_ANA_CON11, 0x0000, 0x00F7); break; default: break; } Ana_Set_Reg(AUDENC_ANA_CON3, 0x0000, 0X000D); /* for little signal be broken issue */ Ana_Set_Reg(AUDENC_ANA_CON5, 0x1515, 0xFFFF); } } static void VOW_MIC_ACC_Enable(int MicType, bool enable) { if ((MicType >= VOW_MIC_TYPE_NUM) || (MicType < 0)) { pr_debug("%s(),Not support this Mic Type\n", __func__); return; } if (enable == true) { /* for little signal be broken issue */ Ana_Set_Reg(AUDENC_ANA_CON5, 0x0030, 0xFFFF); switch (MicType) { case VOW_MIC_TYPE_Handset_AMIC: Ana_Set_Reg(AUDENC_ANA_CON3, 0x0009, 0x000D); Ana_Set_Reg(AUDENC_ANA_CON9, 0x0025, 0x0075); Ana_Set_Reg(AUDENC_ANA_CON0, 0x5000, 0x7000); Ana_Set_Reg(AUDENC_ANA_CON0, 0x5041, 0x00C1); /* Short body to ground in PGA */ Ana_Set_Reg(AUDENC_ANA_CON3, 0x0009, 0x1000); /* Audio L PGA 18 dB gain */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x5341, 0x0700); break; case VOW_MIC_TYPE_Headset_MIC: Ana_Set_Reg(AUDENC_ANA_CON3, 0x0009, 0x000D); Ana_Set_Reg(AUDENC_ANA_CON9, 0x0025, 0x0075); Ana_Set_Reg(AUDENC_ANA_CON0, 0x5000, 0x7000); Ana_Set_Reg(AUDENC_ANA_CON0, 0x5081, 0x00C1); /* Short body to ground in PGA */ Ana_Set_Reg(AUDENC_ANA_CON3, 0x0009, 0x1000); /* Audio L PGA 18 dB gain */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x5381, 0x0700); break; default: break; } } else { /* Audio L ADC input sel : off, Disable audio L ADC */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x0341, 0x7000); /* Disable audio L PGA */ Ana_Set_Reg(AUDENC_ANA_CON0, 0x0000, 0x07C7); switch (MicType) { case VOW_MIC_TYPE_Handset_AMIC: /* Disable MICBIAS0 */ Ana_Set_Reg(AUDENC_ANA_CON9, 0x0000, 0x0075); break; case VOW_MIC_TYPE_Headset_MIC: /* Disable MICBIAS0 */ Ana_Set_Reg(AUDENC_ANA_CON9, 0x0000, 0x0075); break; default: break; } Ana_Set_Reg(AUDENC_ANA_CON3, 0x0000, 0x000D); /* for little signal be broken issue */ Ana_Set_Reg(AUDENC_ANA_CON5, 0x1515, 0xFFFF); } } #endif static bool TurnOnVOWADcPower(int MicType, bool enable) { #ifdef CONFIG_MTK_VOW_SUPPORT pr_debug("%s MicType = %d enable = %d, mIsVOWOn=%d, mAudio_VOW_Mic_type=%d\n", __func__, MicType, enable, mIsVOWOn, mAudio_VOW_Mic_type); if ((MicType >= VOW_MIC_TYPE_NUM) || (MicType < 0)) { pr_debug("%s(),Not support this Mic Type\n", __func__); return false; } /*already on, no need to set again*/ if (enable == mIsVOWOn) return true; if (enable) { mIsVOWOn = true; /* SetVOWStatus(mIsVOWOn); */ if (GetMicbias == 0) { /* save current micbias ref set by accdet */ MicbiasRef = Ana_Get_Reg(AUDENC_ANA_CON9) & 0x0700; pr_debug("MicbiasRef=0x%x\n", MicbiasRef); GetMicbias = 1; } VOW_Pwr_Enable(MicType, true); switch (MicType) { /* for ACC Mic */ case VOW_MIC_TYPE_Handset_AMIC: /* AMIC_ACC */ case VOW_MIC_TYPE_Headset_MIC: /* Earphone_ACC */ VOW_ACC_CLK_Enable(true); VOW_MIC_ACC_Enable(MicType, true); break; /* for DCC Mic */ case VOW_MIC_TYPE_Handset_AMIC_DCC: /* AMIC_DCC */ case VOW_MIC_TYPE_Handset_AMIC_DCCECM: case VOW_MIC_TYPE_Headset_MIC_DCC: /* Earphone_DCC */ case VOW_MIC_TYPE_Headset_MIC_DCCECM: VOW_DCC_CLK_Enable(true); VOW_MIC_DCC_Enable(MicType, true); break; /* for Digital Mic */ case VOW_MIC_TYPE_Handset_DMIC: /* DMIC */ case VOW_MIC_TYPE_Handset_DMIC_800K: VOW_DMIC_CLK_Enable(true); Ana_Set_Reg(AUDENC_ANA_CON9, 0x0025, 0x0075); Ana_Set_Reg(AUDENC_ANA_CON8, 0x0005, 0x0007); /* 0xD18 Enable DMIC*/ break; case VOW_MIC_TYPE_Handset_DMIC_VENDOR01: VOW_DMIC_CLK_Enable(true); Ana_Set_Reg(AUDENC_ANA_CON9, 0x0025, 0x0075); Ana_Set_Reg(AUDENC_ANA_CON8, 0x0005, 0x0007); /* 0xD18 Enable DMIC*/ /* Set Eint GPIO */ VowDrv_SetSmartDevice_GPIO(true); break; default: break; } VOW_GPIO_Enable(true); /* VOW AMPREF Setting, set by MD32 after DC calibration */ Ana_Set_Reg(AFE_VOW_CFG0, reg_AFE_VOW_CFG0, 0xffff); /* 0xffff */ Ana_Set_Reg(AFE_VOW_CFG1, reg_AFE_VOW_CFG1, 0xffff); /*VOW A,B timeout initial value 0x0200*/ Ana_Set_Reg(AFE_VOW_CFG2, reg_AFE_VOW_CFG2, 0xffff); /*VOW A,B value setting 0x2424*/ Ana_Set_Reg(AFE_VOW_CFG3, reg_AFE_VOW_CFG3, 0xffff); Ana_Set_Reg(AFE_VOW_CFG4, reg_AFE_VOW_CFG4, 0x000f); /*gamma K value setting 0x029E*/ Ana_Set_Reg(AFE_VOW_CFG5, reg_AFE_VOW_CFG5, 0xffff);/*N mini value setting 0x0000*/ if (MicType == VOW_MIC_TYPE_Handset_DMIC_VENDOR01) { Ana_Set_Reg(AFE_VOW_CFG4, 0x024E, 0xfff0); /* 16k */ Ana_Set_Reg(AFE_VOW_POSDIV_CFG0, 0x0C0A, 0xffff); /* 812.5k */ } else if (MicType == VOW_MIC_TYPE_Handset_DMIC_800K) { /* gamma K value and vow mtkaif tx setting */ Ana_Set_Reg(AFE_VOW_CFG4, 0x024E, 0xfff0); /* 16k */ /* vow posdiv and cic mode configure */ Ana_Set_Reg(AFE_VOW_POSDIV_CFG0, 0x0C0A, 0xffff); /* 812.5k */ } else if (MicType == VOW_MIC_TYPE_Handset_DMIC) { /* gamma K value and vow mtkaif tx setting */ Ana_Set_Reg(AFE_VOW_CFG4, 0x029E, 0xfff0); /* 16k */ /* vow posdiv and cic mode configure */ Ana_Set_Reg(AFE_VOW_POSDIV_CFG0, 0x0C00, 0xffff); /* 1625k */ } else { /* gamma K value and vow mtkaif tx setting */ Ana_Set_Reg(AFE_VOW_CFG4, 0x029E, 0xfff0); /* 16k */ /* vow posdiv and cic mode configure */ Ana_Set_Reg(AFE_VOW_POSDIV_CFG0, 0x0C00, 0xffff); /* 1.6m */ } TurnOnVOWPeriodicOnOff(MicType, reg_AFE_VOW_PERIODIC, true); #ifndef VOW_STANDALONE_CONTROL if (MicType == VOW_MIC_TYPE_Handset_DMIC) { /* VowDrv_SetDmicLowPower(false); */ VowDrv_SetMtkifType(2); /* 2: DMIC */ Ana_Set_Reg(AFE_VOW_TOP, 0x20C0, 0x20C0); /*VOW enable, with bit7*/ } else if (MicType == VOW_MIC_TYPE_Handset_DMIC_800K) { /* VowDrv_SetDmicLowPower(true); */ VowDrv_SetMtkifType(3); /* 3: DMIC_LP */ Ana_Set_Reg(AFE_VOW_TOP, 0x20C0, 0x20C0); /*VOW enable, with bit7*/ } else if (MicType == VOW_MIC_TYPE_Handset_DMIC_VENDOR01) { /* same as VOW_MIC_TYPE_Handset_DMIC_800K */ VowDrv_SetMtkifType(3); /* 3: DMIC_LP */ } else { /* Normal */ /* VowDrv_SetDmicLowPower(false); */ VowDrv_SetMtkifType(1); /* 1: AMIC */ } #endif /* #ifndef VOW_STANDALONE_CONTROL */ /*VOW enable, set AFE_VOW_TOP in VOW kernel driver*/ /*need to inform VOW driver mic type*/ VowDrv_EnableHW(true); VowDrv_ChangeStatus(); } else { /* disable VOW */ TurnOnVOWPeriodicOnOff(MicType, reg_AFE_VOW_PERIODIC, false); VowDrv_EnableHW(false); VowDrv_ChangeStatus(); msleep(20); VOW_GPIO_Enable(false); VowDrv_SetMtkifType(0); /* 0: NONE */ if ((MicType == VOW_MIC_TYPE_Handset_DMIC) || (MicType == VOW_MIC_TYPE_Handset_DMIC_800K)) { /* VowDrv_SetDmicLowPower(false); */ Ana_Set_Reg(AFE_VOW_TOP, 0x0000, 0x20C0); /*VOW disable, with bit7*/ } switch (MicType) { /* for ACC Mic */ case VOW_MIC_TYPE_Handset_AMIC: case VOW_MIC_TYPE_Headset_MIC: /*turn off analog part*/ VOW_MIC_ACC_Enable(MicType, false); VOW_ACC_CLK_Enable(false); break; /* for DCC Mic */ case VOW_MIC_TYPE_Handset_AMIC_DCC: case VOW_MIC_TYPE_Handset_AMIC_DCCECM: case VOW_MIC_TYPE_Headset_MIC_DCC: case VOW_MIC_TYPE_Headset_MIC_DCCECM: /*turn off analog part*/ VOW_MIC_DCC_Enable(MicType, false); VOW_DCC_CLK_Enable(false); break; /* for Digital Mic */ case VOW_MIC_TYPE_Handset_DMIC: case VOW_MIC_TYPE_Handset_DMIC_800K: /* Disable DMIC */ Ana_Set_Reg(AUDENC_ANA_CON8, 0x0004, 0x0007); /*0x0D08*/ Ana_Set_Reg(AUDENC_ANA_CON9, 0x0000, 0x0075); /*0x0D1A*/ VOW_DMIC_CLK_Enable(false); break; case VOW_MIC_TYPE_Handset_DMIC_VENDOR01: /* Set Eint GPIO */ VowDrv_SetSmartDevice_GPIO(false); Ana_Set_Reg(AUDENC_ANA_CON9, 0x0000, 0x0075); /*0x0D1A*/ Ana_Set_Reg(AFE_VOW_TOP, 0x0000, 0x0080); /* bit7 , clock select */ VOW_DMIC_CLK_Enable(false); break; default: break; } VOW_Pwr_Enable(MicType, false); mIsVOWOn = false; /* SetVOWStatus(mIsVOWOn); */ GetMicbias = 0; } #endif /* #ifdef CONFIG_MTK_VOW_SUPPORT */ return true; } static const char *const Audio_VOW_ADC_Function[] = { "Off", "On" }; static const char *const Audio_VOW_Digital_Function[] = { "Off", "On" }; static const char *const Audio_VOW_MIC_Type[] = { "HandsetAMIC", "HeadsetMIC", "HandsetDMIC", "HandsetDMIC_800K", "HandsetAMIC_DCC", "HeadsetMIC_DCC", "HandsetAMIC_DCCECM", "HeadsetMIC_DCCECM", "HandsetDMIC_VENDOR01" }; /* here start uplink power function */ static const char *const ADC_function[] = { "Off", "On" }; static const char *const ADC_power_mode[] = { "normal", "lowpower" }; static const char *const PreAmp_Mux_function[] = { "OPEN", "IN_ADC1", "IN_ADC2", "IN_ADC3" }; enum preamp_input_select { PREAMP_INPUT_SELECT_NONE = 0, PREAMP_INPUT_SELECT_AIN0, PREAMP_INPUT_SELECT_AIN1, PREAMP_INPUT_SELECT_AIN2, NUM_PREAMP_INPUT_SELECT, }; /* OPEN:0, IN_ADC1: 1, IN_ADC2:2, IN_ADC3:3 */ static const char *const ADC_UL_PGA_GAIN[] = { "0Db", "6Db", "12Db", "18Db", "24Db", "30Db" }; static const char *const Pmic_Digital_Mux[] = { "ADC1", "ADC2", "ADC3", "ADC4" }; static const char *const Adc_Input_Sel[] = { "idle", "AIN", "Preamp" }; static const char *const Audio_AnalogMic_Mode[] = { "ACCMODE", "DCCMODE", "DMIC", "DCCECMDIFFMODE", "DCCECMSINGLEMODE" }; /* here start uplink power function */ static const char * const Pmic_Test_function[] = { "Off", "On" }; static const char * const Pmic_LPBK_function[] = { "Off", "LPBK3" }; static const struct soc_enum Audio_UL_Enum[] = { SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ADC_function), ADC_function), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ADC_function), ADC_function), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ADC_function), ADC_function), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ADC_function), ADC_function), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(PreAmp_Mux_function), PreAmp_Mux_function), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(Adc_Input_Sel), Adc_Input_Sel), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(Adc_Input_Sel), Adc_Input_Sel), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(Adc_Input_Sel), Adc_Input_Sel), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(Adc_Input_Sel), Adc_Input_Sel), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ADC_UL_PGA_GAIN), ADC_UL_PGA_GAIN), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ADC_UL_PGA_GAIN), ADC_UL_PGA_GAIN), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ADC_UL_PGA_GAIN), ADC_UL_PGA_GAIN), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ADC_UL_PGA_GAIN), ADC_UL_PGA_GAIN), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(Pmic_Digital_Mux), Pmic_Digital_Mux), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(Pmic_Digital_Mux), Pmic_Digital_Mux), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(Pmic_Digital_Mux), Pmic_Digital_Mux), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(Pmic_Digital_Mux), Pmic_Digital_Mux), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(Audio_AnalogMic_Mode), Audio_AnalogMic_Mode), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(Audio_AnalogMic_Mode), Audio_AnalogMic_Mode), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(Audio_AnalogMic_Mode), Audio_AnalogMic_Mode), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(Audio_AnalogMic_Mode), Audio_AnalogMic_Mode), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ADC_power_mode), ADC_power_mode), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(PreAmp_Mux_function), PreAmp_Mux_function), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ADC_function), ADC_function), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(Audio_VOW_ADC_Function), Audio_VOW_ADC_Function), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(Audio_VOW_Digital_Function), Audio_VOW_Digital_Function), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(Audio_VOW_MIC_Type), Audio_VOW_MIC_Type), }; static int Audio_ADC1_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = mCodec_data->dev_power[ANA_DEV_IN_ADC1]; return 0; } static int Audio_ADC1_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s()\n", __func__); mutex_lock(&Ana_Power_Mutex); if (ucontrol->value.integer.value[0]) { if (mAudio_Analog_Mic1_mode == ANA_UL_MODE_ACC) TurnOnADcPowerACC(ANA_DEV_IN_ADC1, true); else if (mAudio_Analog_Mic1_mode == ANA_UL_MODE_DCC) TurnOnADcPowerDCC(ANA_DEV_IN_ADC1, true, 0); else if (mAudio_Analog_Mic1_mode == ANA_UL_MODE_DMIC) TurnOnADcPowerDmic(ANA_DEV_IN_ADC1, true); else if (mAudio_Analog_Mic1_mode == ANA_UL_MODE_DCCECMDIFF) TurnOnADcPowerDCC(ANA_DEV_IN_ADC1, true, 1); else if (mAudio_Analog_Mic1_mode == ANA_UL_MODE_DCCECMSINGLE) TurnOnADcPowerDCC(ANA_DEV_IN_ADC1, true, 2); mCodec_data->dev_power[ANA_DEV_IN_ADC1] = ucontrol->value.integer.value[0]; } else { mCodec_data->dev_power[ANA_DEV_IN_ADC1] = ucontrol->value.integer.value[0]; if (mAudio_Analog_Mic1_mode == ANA_UL_MODE_ACC) TurnOnADcPowerACC(ANA_DEV_IN_ADC1, false); else if (mAudio_Analog_Mic1_mode == ANA_UL_MODE_DCC) TurnOnADcPowerDCC(ANA_DEV_IN_ADC1, false, 0); else if (mAudio_Analog_Mic1_mode == ANA_UL_MODE_DMIC) TurnOnADcPowerDmic(ANA_DEV_IN_ADC1, false); else if (mAudio_Analog_Mic1_mode == ANA_UL_MODE_DCCECMDIFF) TurnOnADcPowerDCC(ANA_DEV_IN_ADC1, false, 1); else if (mAudio_Analog_Mic1_mode == ANA_UL_MODE_DCCECMSINGLE) TurnOnADcPowerDCC(ANA_DEV_IN_ADC1, false, 2); } mutex_unlock(&Ana_Power_Mutex); return 0; } static int Audio_ADC2_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = mCodec_data->dev_power[ANA_DEV_IN_ADC2]; return 0; } static int Audio_ADC2_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s()\n", __func__); mutex_lock(&Ana_Power_Mutex); if (ucontrol->value.integer.value[0]) { if (mAudio_Analog_Mic2_mode == ANA_UL_MODE_ACC) TurnOnADcPowerACC(ANA_DEV_IN_ADC2, true); else if (mAudio_Analog_Mic2_mode == ANA_UL_MODE_DCC) TurnOnADcPowerDCC(ANA_DEV_IN_ADC2, true, 0); else if (mAudio_Analog_Mic2_mode == ANA_UL_MODE_DMIC) TurnOnADcPowerDmic(ANA_DEV_IN_ADC2, true); else if (mAudio_Analog_Mic2_mode == ANA_UL_MODE_DCCECMDIFF) TurnOnADcPowerDCC(ANA_DEV_IN_ADC2, true, 1); else if (mAudio_Analog_Mic2_mode == ANA_UL_MODE_DCCECMSINGLE) TurnOnADcPowerDCC(ANA_DEV_IN_ADC2, true, 2); mCodec_data->dev_power[ANA_DEV_IN_ADC2] = ucontrol->value.integer.value[0]; } else { mCodec_data->dev_power[ANA_DEV_IN_ADC2] = ucontrol->value.integer.value[0]; if (mAudio_Analog_Mic2_mode == ANA_UL_MODE_ACC) TurnOnADcPowerACC(ANA_DEV_IN_ADC2, false); else if (mAudio_Analog_Mic2_mode == ANA_UL_MODE_DCC) TurnOnADcPowerDCC(ANA_DEV_IN_ADC2, false, 0); else if (mAudio_Analog_Mic2_mode == ANA_UL_MODE_DMIC) TurnOnADcPowerDmic(ANA_DEV_IN_ADC2, false); else if (mAudio_Analog_Mic2_mode == ANA_UL_MODE_DCCECMDIFF) TurnOnADcPowerDCC(ANA_DEV_IN_ADC2, false, 1); else if (mAudio_Analog_Mic2_mode == ANA_UL_MODE_DCCECMSINGLE) TurnOnADcPowerDCC(ANA_DEV_IN_ADC2, false, 2); } mutex_unlock(&Ana_Power_Mutex); return 0; } static int Audio_ADC3_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* 6752 removed */ return 0; } static int Audio_ADC3_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* 6752 removed */ return 0; } static int Audio_ADC4_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* 6752 removed */ return 0; } static int Audio_ADC4_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* 6752 removed */ return 0; } static int Audio_ADC1_Sel_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s() = %d\n", __func__, mCodec_data->ana_mux[AUDIO_ANALOG_MUX_IN_MIC1]); ucontrol->value.integer.value[0] = mCodec_data->ana_mux[AUDIO_ANALOG_MUX_IN_MIC1]; return 0; } static int Audio_ADC1_Sel_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s()\n", __func__); if (ucontrol->value.enumerated.item[0] > ARRAY_SIZE(Adc_Input_Sel)) { pr_warn("return -EINVAL\n"); return -EINVAL; } if (ucontrol->value.integer.value[0] == 0) Ana_Set_Reg(AUDENC_ANA_CON0, (0x00 << 13), 0x6000); /* pinumx sel */ else if (ucontrol->value.integer.value[0] == 1) Ana_Set_Reg(AUDENC_ANA_CON0, (0x01 << 13), 0x6000); /* AIN0 */ else if (ucontrol->value.integer.value[0] == 2) Ana_Set_Reg(AUDENC_ANA_CON0, (0x02 << 13), 0x6000); /* Left preamp */ else pr_warn("%s() [AudioWarn]\n ", __func__); pr_debug("%s() done\n", __func__); mCodec_data->ana_mux[AUDIO_ANALOG_MUX_IN_MIC1] = ucontrol->value.integer.value[0]; return 0; } static int Audio_ADC2_Sel_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s() = %d\n", __func__, mCodec_data->ana_mux[AUDIO_ANALOG_MUX_IN_MIC2]); ucontrol->value.integer.value[0] = mCodec_data->ana_mux[AUDIO_ANALOG_MUX_IN_MIC2]; return 0; } static int Audio_ADC2_Sel_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s()\n", __func__); if (ucontrol->value.enumerated.item[0] > ARRAY_SIZE(Adc_Input_Sel)) { pr_warn("return -EINVAL\n"); return -EINVAL; } if (ucontrol->value.integer.value[0] == 0) Ana_Set_Reg(AUDENC_ANA_CON1, (0x00 << 13), 0x6000); /* pinumx sel */ else if (ucontrol->value.integer.value[0] == 1) Ana_Set_Reg(AUDENC_ANA_CON1, (0x01 << 13), 0x6000); /* AIN0 */ else if (ucontrol->value.integer.value[0] == 2) Ana_Set_Reg(AUDENC_ANA_CON1, (0x02 << 13), 0x6000); /* Right preamp */ else pr_warn("%s() [AudioWarn]\n ", __func__); pr_debug("%s() done\n", __func__); mCodec_data->ana_mux[AUDIO_ANALOG_MUX_IN_MIC2] = ucontrol->value.integer.value[0]; return 0; } static int Audio_ADC3_Sel_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* 6752 removed */ return 0; } static int Audio_ADC3_Sel_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* 6752 removed */ return 0; } static int Audio_ADC4_Sel_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* 6752 removed */ return 0; } static int Audio_ADC4_Sel_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* 6752 removed */ return 0; } static bool AudioPreAmp1_Sel(int Mul_Sel) { if (Mul_Sel >= 0 && Mul_Sel < NUM_PREAMP_INPUT_SELECT) Ana_Set_Reg(AUDENC_ANA_CON0, Mul_Sel << 6, 0x3 << 6); else pr_warn("%s(), error, Mul_Sel = %d", __func__, Mul_Sel); return true; } static int Audio_PreAmp1_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = mCodec_data->ana_mux[AUDIO_ANALOG_MUX_IN_PREAMP_1]; return 0; } static int Audio_PreAmp1_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s()\n", __func__); if (ucontrol->value.enumerated.item[0] > ARRAY_SIZE(PreAmp_Mux_function)) { pr_warn("return -EINVAL\n"); return -EINVAL; } mCodec_data->ana_mux[AUDIO_ANALOG_MUX_IN_PREAMP_1] = ucontrol->value.integer.value[0]; AudioPreAmp1_Sel(mCodec_data->ana_mux[AUDIO_ANALOG_MUX_IN_PREAMP_1]); return 0; } static bool AudioPreAmp2_Sel(int Mul_Sel) { pr_debug("%s Mul_Sel = %d ", __func__, Mul_Sel); if (Mul_Sel >= 0 && Mul_Sel < NUM_PREAMP_INPUT_SELECT) Ana_Set_Reg(AUDENC_ANA_CON1, Mul_Sel << 6, 0x3 << 6); else pr_warn("%s(), error, Mul_Sel = %d", __func__, Mul_Sel); return true; } static int Audio_PreAmp2_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = mCodec_data->ana_mux[AUDIO_ANALOG_MUX_IN_PREAMP_2]; return 0; } static int Audio_PreAmp2_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s()\n", __func__); if (ucontrol->value.enumerated.item[0] > ARRAY_SIZE(PreAmp_Mux_function)) { pr_warn("return -EINVAL\n"); return -EINVAL; } mCodec_data->ana_mux[AUDIO_ANALOG_MUX_IN_PREAMP_2] = ucontrol->value.integer.value[0]; AudioPreAmp2_Sel(mCodec_data->ana_mux[AUDIO_ANALOG_MUX_IN_PREAMP_2]); return 0; } /* PGA1: PGA_L */ static int Audio_PGA1_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = mCodec_data->ana_gain[ANA_GAIN_MICAMP1]; return 0; } static int Audio_PGA1_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int index = 0; pr_debug("%s()\n", __func__); if (ucontrol->value.enumerated.item[0] > ARRAY_SIZE(ADC_UL_PGA_GAIN)) { pr_warn("return -EINVAL\n"); return -EINVAL; } index = ucontrol->value.integer.value[0]; Ana_Set_Reg(AUDENC_ANA_CON0, (index << 8), 0x0700); mCodec_data->ana_gain[ANA_GAIN_MICAMP1] = ucontrol->value.integer.value[0]; return 0; } /* PGA2: PGA_R */ static int Audio_PGA2_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = mCodec_data->ana_gain[ANA_GAIN_MICAMP2]; return 0; } static int Audio_PGA2_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int index = 0; pr_debug("%s()\n", __func__); if (ucontrol->value.enumerated.item[0] > ARRAY_SIZE(ADC_UL_PGA_GAIN)) { pr_warn("return -EINVAL\n"); return -EINVAL; } index = ucontrol->value.integer.value[0]; Ana_Set_Reg(AUDENC_ANA_CON1, index << 8, 0x0700); mCodec_data->ana_gain[ANA_GAIN_MICAMP2] = ucontrol->value.integer.value[0]; return 0; } static int Audio_PGA3_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* 6752 removed */ return 0; } static int Audio_PGA3_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* 6752 removed */ return 0; } static int Audio_PGA4_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* 6752 removed */ return 0; } static int Audio_PGA4_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* 6752 removed */ return 0; } static int Audio_MicSource1_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = mCodec_data->ana_mux[MICSOURCE_MUX_IN_1]; return 0; } static int Audio_MicSource1_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* ADC1 Mic source selection, * "ADC1" is main_mic, "ADC2" is headset_mic */ int index = 0; if (ucontrol->value.enumerated.item[0] > ARRAY_SIZE(Pmic_Digital_Mux)) { pr_warn("return -EINVAL\n"); return -EINVAL; } index = ucontrol->value.integer.value[0]; pr_debug("%s() index = %d done\n", __func__, index); mCodec_data->ana_mux[MICSOURCE_MUX_IN_1] = ucontrol->value.integer.value[0]; return 0; } static int Audio_MicSource2_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* 6752 removed */ return 0; } static int Audio_MicSource2_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* 6752 removed */ return 0; } static int Audio_MicSource3_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* 6752 removed */ return 0; } static int Audio_MicSource3_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* 6752 removed */ return 0; } static int Audio_MicSource4_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* 6752 removed */ return 0; } static int Audio_MicSource4_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* 6752 removed */ return 0; } /* Mic ACC/DCC Mode Setting */ static int Audio_Mic1_Mode_Select_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = mAudio_Analog_Mic1_mode; return 0; } static int Audio_Mic1_Mode_Select_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { if (ucontrol->value.enumerated.item[0] > ARRAY_SIZE(Audio_AnalogMic_Mode)) { pr_warn("return -EINVAL\n"); return -EINVAL; } mAudio_Analog_Mic1_mode = ucontrol->value.integer.value[0]; pr_debug("%s() mAudio_Analog_Mic1_mode = %d\n", __func__, mAudio_Analog_Mic1_mode); return 0; } static int Audio_Mic2_Mode_Select_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = mAudio_Analog_Mic2_mode; return 0; } static int Audio_Mic2_Mode_Select_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { if (ucontrol->value.enumerated.item[0] > ARRAY_SIZE(Audio_AnalogMic_Mode)) { pr_warn("return -EINVAL\n"); return -EINVAL; } mAudio_Analog_Mic2_mode = ucontrol->value.integer.value[0]; pr_debug("%s() mAudio_Analog_Mic2_mode = %d\n", __func__, mAudio_Analog_Mic2_mode); return 0; } static int Audio_Mic3_Mode_Select_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = mAudio_Analog_Mic3_mode; return 0; } static int Audio_Mic3_Mode_Select_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { if (ucontrol->value.enumerated.item[0] > ARRAY_SIZE(Audio_AnalogMic_Mode)) { pr_warn("return -EINVAL\n"); return -EINVAL; } mAudio_Analog_Mic3_mode = ucontrol->value.integer.value[0]; pr_debug("%s() mAudio_Analog_Mic3_mode = %d\n", __func__, mAudio_Analog_Mic3_mode); return 0; } static int Audio_Mic4_Mode_Select_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = mAudio_Analog_Mic4_mode; return 0; } static int Audio_Mic4_Mode_Select_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { if (ucontrol->value.enumerated.item[0] > ARRAY_SIZE(Audio_AnalogMic_Mode)) { pr_warn("return -EINVAL\n"); return -EINVAL; } mAudio_Analog_Mic4_mode = ucontrol->value.integer.value[0]; pr_debug("%s() mAudio_Analog_Mic4_mode = %d\n", __func__, mAudio_Analog_Mic4_mode); return 0; } static int Audio_Adc_Power_Mode_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s() = %d\n", __func__, mAdc_Power_Mode); ucontrol->value.integer.value[0] = mAdc_Power_Mode; return 0; } static int Audio_Adc_Power_Mode_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s()\n", __func__); if (ucontrol->value.enumerated.item[0] > ARRAY_SIZE(ADC_power_mode)) { pr_warn("return -EINVAL\n"); return -EINVAL; } mAdc_Power_Mode = ucontrol->value.integer.value[0]; pr_debug("%s() mAdc_Power_Mode = %d\n", __func__, mAdc_Power_Mode); return 0; } static int Audio_Vow_ADC_Func_Switch_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s() = %d\n", __func__, mAudio_Vow_Analog_Func_Enable); ucontrol->value.integer.value[0] = mAudio_Vow_Analog_Func_Enable; return 0; } static int Audio_Vow_ADC_Func_Switch_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { if (ucontrol->value.enumerated.item[0] > ARRAY_SIZE(Audio_VOW_ADC_Function)) { pr_debug("return -EINVAL\n"); return -EINVAL; } if (ucontrol->value.integer.value[0]) TurnOnVOWADcPower(mAudio_VOW_Mic_type, true); else TurnOnVOWADcPower(mAudio_VOW_Mic_type, false); mAudio_Vow_Analog_Func_Enable = ucontrol->value.integer.value[0]; return 0; } static int Audio_Vow_Digital_Func_Switch_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s() = %d\n", __func__, mAudio_Vow_Digital_Func_Enable); ucontrol->value.integer.value[0] = mAudio_Vow_Digital_Func_Enable; return 0; } static int Audio_Vow_Digital_Func_Switch_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { if (ucontrol->value.enumerated.item[0] > ARRAY_SIZE( Audio_VOW_Digital_Function)) { pr_debug("return -EINVAL\n"); return -EINVAL; } if (ucontrol->value.integer.value[0]) TurnOnVOWDigitalHW(true); else TurnOnVOWDigitalHW(false); mAudio_Vow_Digital_Func_Enable = ucontrol->value.integer.value[0]; return 0; } static int VOW_MIC_TYPE_Select_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s() = %d\n", __func__, mAudio_VOW_Mic_type); ucontrol->value.integer.value[0] = mAudio_VOW_Mic_type; return 0; } static int VOW_MIC_TYPE_Select_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { if (ucontrol->value.enumerated.item[0] > ARRAY_SIZE(Audio_VOW_MIC_Type)) { pr_debug("return -EINVAL\n"); return -EINVAL; } mAudio_VOW_Mic_type = ucontrol->value.integer.value[0]; pr_debug("%s() mAudio_VOW_Mic_type = %d\n", __func__, mAudio_VOW_Mic_type); return 0; } static int Audio_Vow_Cfg0_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int value = reg_AFE_VOW_CFG0; pr_debug("%s() = %d\n", __func__, value); ucontrol->value.integer.value[0] = value; return 0; } static int Audio_Vow_Cfg0_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s() = %d\n", __func__, (int)(ucontrol->value.integer.value[0])); reg_AFE_VOW_CFG0 = ucontrol->value.integer.value[0]; return 0; } static int Audio_Vow_Cfg1_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int value = reg_AFE_VOW_CFG1; pr_debug("%s() = %d\n", __func__, value); ucontrol->value.integer.value[0] = value; return 0; } static int Audio_Vow_Cfg1_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s() = %ld\n", __func__, ucontrol->value.integer.value[0]); reg_AFE_VOW_CFG1 = ucontrol->value.integer.value[0]; return 0; } static int Audio_Vow_Cfg2_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int value = reg_AFE_VOW_CFG2; pr_debug("%s() = %d\n", __func__, value); ucontrol->value.integer.value[0] = value; return 0; } static int Audio_Vow_Cfg2_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s() = %ld\n", __func__, ucontrol->value.integer.value[0]); reg_AFE_VOW_CFG2 = ucontrol->value.integer.value[0]; return 0; } static int Audio_Vow_Cfg3_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int value = reg_AFE_VOW_CFG3; pr_debug("%s() = %d\n", __func__, value); ucontrol->value.integer.value[0] = value; return 0; } static int Audio_Vow_Cfg3_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s() = %ld\n", __func__, ucontrol->value.integer.value[0]); reg_AFE_VOW_CFG3 = ucontrol->value.integer.value[0]; return 0; } static int Audio_Vow_Cfg4_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int value = reg_AFE_VOW_CFG4; pr_debug("%s() = %d\n", __func__, value); ucontrol->value.integer.value[0] = value; return 0; } static int Audio_Vow_Cfg4_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s() = %ld\n", __func__, ucontrol->value.integer.value[0]); reg_AFE_VOW_CFG4 = ucontrol->value.integer.value[0]; return 0; } static int Audio_Vow_Cfg5_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int value = reg_AFE_VOW_CFG5; pr_debug("%s() = %d\n", __func__, value); ucontrol->value.integer.value[0] = value; return 0; } static int Audio_Vow_Cfg5_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s() = %ld\n", __func__, ucontrol->value.integer.value[0]); reg_AFE_VOW_CFG5 = ucontrol->value.integer.value[0]; return 0; } static int Audio_Vow_State_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int value = mIsVOWOn; pr_debug("%s() = %d\n", __func__, value); ucontrol->value.integer.value[0] = value; return 0; } static int Audio_Vow_State_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { return 0; } static int Audio_Vow_Periodic_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int value = reg_AFE_VOW_PERIODIC; pr_debug("%s() = %d\n", __func__, value); ucontrol->value.integer.value[0] = value; return 0; } static int Audio_Vow_Periodic_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s() = %ld\n", __func__, ucontrol->value.integer.value[0]); reg_AFE_VOW_PERIODIC = ucontrol->value.integer.value[0]; return 0; } static bool ul_lr_swap_enable; static int Audio_UL_LR_Swap_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = ul_lr_swap_enable; return 0; } static int Audio_UL_LR_Swap_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ul_lr_swap_enable = ucontrol->value.integer.value[0]; Ana_Set_Reg(AFE_UL_DL_CON0, ul_lr_swap_enable << 15, 0x1 << 15); return 0; } static bool SineTable_DAC_HP_flag; static bool SineTable_UL2_flag; static int SineTable_UL2_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { if (ucontrol->value.integer.value[0]) { Ana_Set_Reg(PMIC_AFE_TOP_CON0, 0x0002, 0x2); /* set UL from sinetable */ Ana_Set_Reg(AFE_SGEN_CFG0, 0x0080, 0xffff); Ana_Set_Reg(AFE_SGEN_CFG1, 0x0101, 0xffff); } else { Ana_Set_Reg(PMIC_AFE_TOP_CON0, 0x0000, 0x2); /* set UL from normal path */ Ana_Set_Reg(AFE_SGEN_CFG0, 0x0000, 0xffff); Ana_Set_Reg(AFE_SGEN_CFG1, 0x0101, 0xffff); } SineTable_UL2_flag = ucontrol->value.integer.value[0]; return 0; } static int SineTable_UL2_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s()\n", __func__); ucontrol->value.integer.value[0] = SineTable_UL2_flag; return 0; } static int Pmic_Loopback_Type; static int Pmic_Loopback_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = Pmic_Loopback_Type; return 0; } static int Pmic_Loopback_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { if (ucontrol->value.enumerated.item[0] > ARRAY_SIZE(Pmic_LPBK_function)) { pr_warn("return -EINVAL\n"); return -EINVAL; } if (ucontrol->value.integer.value[0] == 0) { /* disable pmic lpbk */ Ana_Set_Reg(AFE_UL_SRC_CON0_L, 0x0000, 0x0001); /* power off uplink */ Ana_Set_Reg(PMIC_AFE_ADDA_MTKAIF_CFG0, 0x0, 0xffff); /* disable new lpbk 2 */ Ana_Set_Reg(AFE_UL_DL_CON0, 0x0000, 0x0001); /* turn off afe UL & DL */ /* disable aud_pad RX & TX fifos */ Ana_Set_Reg(AFE_AUD_PAD_TOP, 0x0, 0x101); set_capture_gpio(false); TurnOffDacPower(); } else if (ucontrol->value.integer.value[0] > 0) { /* enable pmic lpbk */ pr_debug("set PMIC LPBK3, DLSR=%d, ULSR=%d\n", mBlockSampleRate[ANA_DEV_OUT_DAC], mBlockSampleRate[ANA_DEV_IN_ADC]); /* set dl part */ TurnOnDacPower(ANA_DEV_OUT_HEADSETL); set_capture_gpio(true); Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x8000, 0xffff); /* power on clock */ /* enable aud_pad TX fifos */ Ana_Set_Reg(AFE_AUD_PAD_TOP, 0x3100, 0xff00); /* Set UL Part */ Ana_Set_Reg(PMIC_AFE_ADDA_MTKAIF_CFG0, 0x2, 0xffff); /* enable new lpbk 2 */ Ana_Set_Reg(AFE_UL_SRC_CON0_L, 0x0001, 0xffff); /* power on uplink */ Ana_Set_Reg(PMIC_AFE_TOP_CON0, 0x0000, 0x0002); /* configure ADC setting */ Ana_Set_Reg(AFE_UL_DL_CON0, 0x0001, 0xffff); /* turn on afe */ } /* remember to set, AP side 0xe00 [1] = 1, for new lpbk2 */ pr_debug("%s() done\n", __func__); Pmic_Loopback_Type = ucontrol->value.integer.value[0]; return 0; } static int SineTable_DAC_HP_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = SineTable_DAC_HP_flag; return 0; } static int SineTable_DAC_HP_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* 6752 TODO? */ return 0; } static void ADC_LOOP_DAC_Func(int command) { /* 6752 TODO? */ } static bool DAC_LOOP_DAC_HS_flag; static int ADC_LOOP_DAC_HS_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s()\n", __func__); ucontrol->value.integer.value[0] = DAC_LOOP_DAC_HS_flag; return 0; } static int ADC_LOOP_DAC_HS_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s()\n", __func__); if (ucontrol->value.integer.value[0]) { DAC_LOOP_DAC_HS_flag = ucontrol->value.integer.value[0]; ADC_LOOP_DAC_Func(AUDIO_ANALOG_DAC_LOOP_DAC_HS_ON); } else { DAC_LOOP_DAC_HS_flag = ucontrol->value.integer.value[0]; ADC_LOOP_DAC_Func(AUDIO_ANALOG_DAC_LOOP_DAC_HS_OFF); } return 0; } static bool DAC_LOOP_DAC_HP_flag; static int ADC_LOOP_DAC_HP_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s()\n", __func__); ucontrol->value.integer.value[0] = DAC_LOOP_DAC_HP_flag; return 0; } static int ADC_LOOP_DAC_HP_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s()\n", __func__); if (ucontrol->value.integer.value[0]) { DAC_LOOP_DAC_HP_flag = ucontrol->value.integer.value[0]; ADC_LOOP_DAC_Func(AUDIO_ANALOG_DAC_LOOP_DAC_HP_ON); } else { DAC_LOOP_DAC_HP_flag = ucontrol->value.integer.value[0]; ADC_LOOP_DAC_Func(AUDIO_ANALOG_DAC_LOOP_DAC_HP_OFF); } return 0; } static bool Voice_Call_DAC_DAC_HS_flag; static int Voice_Call_DAC_DAC_HS_Get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s()\n", __func__); ucontrol->value.integer.value[0] = Voice_Call_DAC_DAC_HS_flag; return 0; } static int Voice_Call_DAC_DAC_HS_Set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { return 0; } static int codec_debug_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = codec_debug_enable; return 0; } static int codec_debug_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { codec_debug_enable = ucontrol->value.integer.value[0]; return 0; } static const struct soc_enum Pmic_Test_Enum[] = { SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(Pmic_Test_function), Pmic_Test_function), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(Pmic_Test_function), Pmic_Test_function), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(Pmic_Test_function), Pmic_Test_function), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(Pmic_Test_function), Pmic_Test_function), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(Pmic_Test_function), Pmic_Test_function), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(Pmic_LPBK_function), Pmic_LPBK_function), }; static const struct snd_kcontrol_new mt6358_pmic_Test_controls[] = { SOC_ENUM_EXT("SineTable_DAC_HP", Pmic_Test_Enum[0], SineTable_DAC_HP_Get, SineTable_DAC_HP_Set), SOC_ENUM_EXT("DAC_LOOP_DAC_HS", Pmic_Test_Enum[1], ADC_LOOP_DAC_HS_Get, ADC_LOOP_DAC_HS_Set), SOC_ENUM_EXT("DAC_LOOP_DAC_HP", Pmic_Test_Enum[2], ADC_LOOP_DAC_HP_Get, ADC_LOOP_DAC_HP_Set), SOC_ENUM_EXT("Voice_Call_DAC_DAC_HS", Pmic_Test_Enum[3], Voice_Call_DAC_DAC_HS_Get, Voice_Call_DAC_DAC_HS_Set), SOC_ENUM_EXT("SineTable_UL2", Pmic_Test_Enum[4], SineTable_UL2_Get, SineTable_UL2_Set), SOC_ENUM_EXT("Pmic_Loopback", Pmic_Test_Enum[5], Pmic_Loopback_Get, Pmic_Loopback_Set), SOC_SINGLE_EXT("Codec_Debug_Enable", SND_SOC_NOPM, 0, 0xffffffff, 0, codec_debug_get, codec_debug_set), }; static const struct snd_kcontrol_new mt6358_UL_Codec_controls[] = { SOC_ENUM_EXT("Audio_ADC_1_Switch", Audio_UL_Enum[0], Audio_ADC1_Get, Audio_ADC1_Set), SOC_ENUM_EXT("Audio_ADC_2_Switch", Audio_UL_Enum[1], Audio_ADC2_Get, Audio_ADC2_Set), SOC_ENUM_EXT("Audio_ADC_3_Switch", Audio_UL_Enum[2], Audio_ADC3_Get, Audio_ADC3_Set), SOC_ENUM_EXT("Audio_ADC_4_Switch", Audio_UL_Enum[3], Audio_ADC4_Get, Audio_ADC4_Set), SOC_ENUM_EXT("Audio_Preamp1_Switch", Audio_UL_Enum[4], Audio_PreAmp1_Get, Audio_PreAmp1_Set), SOC_ENUM_EXT("Audio_ADC_1_Sel", Audio_UL_Enum[5], Audio_ADC1_Sel_Get, Audio_ADC1_Sel_Set), SOC_ENUM_EXT("Audio_ADC_2_Sel", Audio_UL_Enum[6], Audio_ADC2_Sel_Get, Audio_ADC2_Sel_Set), SOC_ENUM_EXT("Audio_ADC_3_Sel", Audio_UL_Enum[7], Audio_ADC3_Sel_Get, Audio_ADC3_Sel_Set), SOC_ENUM_EXT("Audio_ADC_4_Sel", Audio_UL_Enum[8], Audio_ADC4_Sel_Get, Audio_ADC4_Sel_Set), SOC_ENUM_EXT("Audio_PGA1_Setting", Audio_UL_Enum[9], Audio_PGA1_Get, Audio_PGA1_Set), SOC_ENUM_EXT("Audio_PGA2_Setting", Audio_UL_Enum[10], Audio_PGA2_Get, Audio_PGA2_Set), SOC_ENUM_EXT("Audio_PGA3_Setting", Audio_UL_Enum[11], Audio_PGA3_Get, Audio_PGA3_Set), SOC_ENUM_EXT("Audio_PGA4_Setting", Audio_UL_Enum[12], Audio_PGA4_Get, Audio_PGA4_Set), SOC_ENUM_EXT("Audio_MicSource1_Setting", Audio_UL_Enum[13], Audio_MicSource1_Get, Audio_MicSource1_Set), SOC_ENUM_EXT("Audio_MicSource2_Setting", Audio_UL_Enum[14], Audio_MicSource2_Get, Audio_MicSource2_Set), SOC_ENUM_EXT("Audio_MicSource3_Setting", Audio_UL_Enum[15], Audio_MicSource3_Get, Audio_MicSource3_Set), SOC_ENUM_EXT("Audio_MicSource4_Setting", Audio_UL_Enum[16], Audio_MicSource4_Get, Audio_MicSource4_Set), SOC_ENUM_EXT("Audio_MIC1_Mode_Select", Audio_UL_Enum[17], Audio_Mic1_Mode_Select_Get, Audio_Mic1_Mode_Select_Set), SOC_ENUM_EXT("Audio_MIC2_Mode_Select", Audio_UL_Enum[18], Audio_Mic2_Mode_Select_Get, Audio_Mic2_Mode_Select_Set), SOC_ENUM_EXT("Audio_MIC3_Mode_Select", Audio_UL_Enum[19], Audio_Mic3_Mode_Select_Get, Audio_Mic3_Mode_Select_Set), SOC_ENUM_EXT("Audio_MIC4_Mode_Select", Audio_UL_Enum[20], Audio_Mic4_Mode_Select_Get, Audio_Mic4_Mode_Select_Set), SOC_ENUM_EXT("Audio_Mic_Power_Mode", Audio_UL_Enum[21], Audio_Adc_Power_Mode_Get, Audio_Adc_Power_Mode_Set), SOC_ENUM_EXT("Audio_Preamp2_Switch", Audio_UL_Enum[22], Audio_PreAmp2_Get, Audio_PreAmp2_Set), SOC_ENUM_EXT("Audio_UL_LR_Swap", Audio_UL_Enum[23], Audio_UL_LR_Swap_Get, Audio_UL_LR_Swap_Set), SOC_ENUM_EXT("Audio_Vow_ADC_Func_Switch", Audio_UL_Enum[24], Audio_Vow_ADC_Func_Switch_Get, Audio_Vow_ADC_Func_Switch_Set), SOC_ENUM_EXT("Audio_Vow_Digital_Func_Switch", Audio_UL_Enum[25], Audio_Vow_Digital_Func_Switch_Get, Audio_Vow_Digital_Func_Switch_Set), SOC_ENUM_EXT("VOW_MIC_TYPE_Select", Audio_UL_Enum[26], VOW_MIC_TYPE_Select_Get, VOW_MIC_TYPE_Select_Set), SOC_SINGLE_EXT("Audio VOWCFG0 Data", SND_SOC_NOPM, 0, 0x80000, 0, Audio_Vow_Cfg0_Get, Audio_Vow_Cfg0_Set), SOC_SINGLE_EXT("Audio VOWCFG1 Data", SND_SOC_NOPM, 0, 0x80000, 0, Audio_Vow_Cfg1_Get, Audio_Vow_Cfg1_Set), SOC_SINGLE_EXT("Audio VOWCFG2 Data", SND_SOC_NOPM, 0, 0x80000, 0, Audio_Vow_Cfg2_Get, Audio_Vow_Cfg2_Set), SOC_SINGLE_EXT("Audio VOWCFG3 Data", SND_SOC_NOPM, 0, 0x80000, 0, Audio_Vow_Cfg3_Get, Audio_Vow_Cfg3_Set), SOC_SINGLE_EXT("Audio VOWCFG4 Data", SND_SOC_NOPM, 0, 0x80000, 0, Audio_Vow_Cfg4_Get, Audio_Vow_Cfg4_Set), SOC_SINGLE_EXT("Audio VOWCFG5 Data", SND_SOC_NOPM, 0, 0x80000, 0, Audio_Vow_Cfg5_Get, Audio_Vow_Cfg5_Set), SOC_SINGLE_EXT("Audio_VOW_State", SND_SOC_NOPM, 0, 0x80000, 0, Audio_Vow_State_Get, Audio_Vow_State_Set), SOC_SINGLE_EXT("Audio_VOW_Periodic", SND_SOC_NOPM, 0, 0x80000, 0, Audio_Vow_Periodic_Get, Audio_Vow_Periodic_Set), }; static int read_efuse_hp_impedance_current_calibration(void) { int ret = 0; int value, sign; pr_debug("+%s()\n", __func__); /* 1. enable efuse ctrl engine clock */ Ana_Set_Reg(TOP_CKHWEN_CON0_CLR, 0x1 << 2, 0x1 << 2); Ana_Set_Reg(TOP_CKPDN_CON0_CLR, 0x1 << 4, 0x1 << 4); /* 2. set RG_OTP_RD_SW */ Ana_Set_Reg(OTP_CON11, 0x0001, 0x0001); /* 3. set EFUSE addr */ /* HPDET_COMP[6:0] @ efuse bit 1840 ~ 1846 */ /* HPDET_COMP_SIGN @ efuse bit 1847 */ /* 1840 / 8 = 230 --> 0xe6 */ Ana_Set_Reg(OTP_CON0, 0xe6, 0xff); /* 4. Toggle RG_OTP_RD_TRIG */ ret = Ana_Get_Reg(OTP_CON8); if (ret == 0) Ana_Set_Reg(OTP_CON8, 0x0001, 0x0001); else Ana_Set_Reg(OTP_CON8, 0x0000, 0x0001); /* 5. Polling RG_OTP_RD_BUSY */ do { ret = Ana_Get_Reg(OTP_CON13) & 0x0001; usleep_range(100, 200); pr_debug("%s(), polling OTP_CON13 = 0x%x\n", __func__, ret); } while (ret == 1); /* Need to delay at least 1ms for 0xC1A and than can read */ usleep_range(500, 1000); /* 6. Read RG_OTP_DOUT_SW */ ret = Ana_Get_Reg(OTP_CON12); pr_debug("%s(), efuse = 0x%x\n", __func__, ret); sign = (ret >> 7) & 0x1; value = ret & 0x7f; value = sign ? -value : value; /* 7. Disables efuse_ctrl egine clock */ Ana_Set_Reg(OTP_CON11, 0x0000, 0x0001); Ana_Set_Reg(TOP_CKPDN_CON0_SET, 0x1 << 4, 0x1 << 4); Ana_Set_Reg(TOP_CKHWEN_CON0_SET, 0x1 << 2, 0x1 << 2); pr_debug("-%s(), efuse: %d\n", __func__, value); return value; } static void mt6358_codec_init_reg(struct snd_soc_component *codec) { pr_debug("%s\n", __func__); audckbufEnable(true); /* disable CLKSQ */ Ana_Set_Reg(AUDENC_ANA_CON6, 0x0000, 0x0003); /* disable AUDGLB */ Ana_Set_Reg(AUDDEC_ANA_CON13, 0x1 << 4, 0x1 << 4); /* Turn off AUDNCP_CLKDIV engine clock,Turn off AUD 26M */ Ana_Set_Reg(AUD_TOP_CKPDN_CON0, 0x66, 0x66); /* set pdn for golden setting */ Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x00ff, 0x00ff); /* Disable HeadphoneL/HeadphoneR short circuit protection */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0x3 << 12, 0x3 << 12); /* Disable voice short circuit protection */ Ana_Set_Reg(AUDDEC_ANA_CON6, 0x1 << 4, 0x1 << 4); /* disable LO buffer left short circuit protection */ Ana_Set_Reg(AUDDEC_ANA_CON7, 0x1 << 4, 0x1 << 4); /* gpio miso driving set to default 4mA */ Ana_Set_Reg(DRV_CON3, 0x8888, 0xffff); /* Enable mtkaif gpio SMT mode */ Ana_Set_Reg(SMT_CON1, 0x0ff0, 0x0ff0); /* Set HP_EINT trigger level to 2.0v */ Ana_Set_Reg(AUDENC_ANA_CON11, 0x1 << 10, 0x1 << 10); /* set gpio */ set_playback_gpio(false); set_capture_gpio(false); audckbufEnable(false); } void InitCodecDefault(void) { pr_debug("%s\n", __func__); mCodec_data->ana_gain[ANA_GAIN_MICAMP1] = 3; mCodec_data->ana_gain[ANA_GAIN_MICAMP2] = 3; mCodec_data->ana_gain[ANA_GAIN_MICAMP3] = 3; mCodec_data->ana_gain[ANA_GAIN_MICAMP4] = 3; mCodec_data->ana_gain[ANA_GAIN_HPOUTL] = 8; mCodec_data->ana_gain[ANA_GAIN_HPOUTR] = 8; mCodec_data->ana_gain[ANA_GAIN_HSOUTL] = 8; mCodec_data->ana_gain[ANA_GAIN_HSOUTR] = 8; mCodec_data->ana_mux[AUDIO_ANALOG_MUX_IN_MIC1] = AUDIO_ANALOG_AUDIOANALOG_INPUT_PREAMP; mCodec_data->ana_mux[AUDIO_ANALOG_MUX_IN_MIC2] = AUDIO_ANALOG_AUDIOANALOG_INPUT_PREAMP; mCodec_data->ana_mux[AUDIO_ANALOG_MUX_IN_MIC3] = AUDIO_ANALOG_AUDIOANALOG_INPUT_PREAMP; mCodec_data->ana_mux[AUDIO_ANALOG_MUX_IN_MIC4] = AUDIO_ANALOG_AUDIOANALOG_INPUT_PREAMP; } static void InitGlobalVarDefault(void) { mCodec_data = NULL; mAudio_Vow_Analog_Func_Enable = false; mAudio_Vow_Digital_Func_Enable = false; mIsVOWOn = false; mAdc_Power_Mode = 0; mInitCodec = false; mAnaSuspend = false; audck_buf_Count = 0; ClsqCount = 0; TopCkCount = 0; NvRegCount = 0; mIsNeedPullDown = true; } static struct task_struct *dc_trim_task; static int dc_trim_thread(void *arg) { pr_debug("%s()\n", __func__); get_hp_lr_trim_offset(); #ifdef CONFIG_MTK_ACCDET /* By default, set mic mode as AUDIO_MIC_MODE_ACC */ accdet_late_init(AUDIO_MIC_MODE_ACC); #endif do_exit(0); return 0; } static int mt6358_component_probe(struct snd_soc_component *component) { int ret = 0; pr_debug("%s()\n", __func__); if (mInitCodec == true) return 0; /* add codec controls */ snd_soc_add_component_controls(component, mt6358_snd_controls, ARRAY_SIZE(mt6358_snd_controls)); snd_soc_add_component_controls(component, mt6358_UL_Codec_controls, ARRAY_SIZE(mt6358_UL_Codec_controls)); snd_soc_add_component_controls(component, mt6358_pmic_Test_controls, ARRAY_SIZE(mt6358_pmic_Test_controls)); snd_soc_add_component_controls(component, Audio_snd_auxadc_controls, ARRAY_SIZE(Audio_snd_auxadc_controls)); /* here to set private data */ mCodec_data = kzalloc(sizeof(struct mt6358_codec_priv), GFP_KERNEL); if (!mCodec_data) { /*pr_warn("Failed to allocate private data\n");*/ return -ENOMEM; } snd_soc_component_set_drvdata(component, mCodec_data); memset((void *)mCodec_data, 0, sizeof(struct mt6358_codec_priv)); mt6358_codec_init_reg(component); InitCodecDefault(); efuse_current_calibrate = read_efuse_hp_impedance_current_calibration(); mInitCodec = true; apply_n12db_gain = 0; dc_trim_task = kthread_create(dc_trim_thread, NULL, "dc_trim_thread"); if (IS_ERR(dc_trim_task)) { ret = PTR_ERR(dc_trim_task); dc_trim_task = NULL; pr_debug("%s(), create dc_trim_thread failed, ret %d\n", __func__, ret); } else { wake_up_process(dc_trim_task); } return 0; } static int mt6358_component_remove(struct snd_soc_component *component) { return 0; } static unsigned int mt6358_component_read(struct snd_soc_component *component, unsigned int reg) { Ana_Get_Reg(reg); return 0; } static int mt6358_component_write(struct snd_soc_component *component, unsigned int reg, unsigned int value) { Ana_Set_Reg(reg, value, 0xffffffff); return 0; } static const struct snd_soc_component_driver mt6358_component_driver = { .name = CODEC_MT6358_NAME, .probe = mt6358_component_probe, .remove = mt6358_component_remove, .read = mt6358_component_read, .write = mt6358_component_write, }; static int mtk_mt6358_codec_dev_probe(struct platform_device *pdev) { if (pdev->dev.of_node) { dev_set_name(&pdev->dev, "%s", MT_SOC_CODEC_NAME); pdev->name = pdev->dev.kobj.name; /* check if use hp depop flow */ of_property_read_u32(pdev->dev.of_node, "use_hp_depop_flow", &mUseHpDepopFlow); pr_debug("%s(), use_hp_depop_flow = %d\n", __func__, mUseHpDepopFlow); } else { pr_info("%s(), pdev->dev.of_node = NULL!!!\n", __func__); } pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev)); return snd_soc_register_component(&pdev->dev, &mt6358_component_driver, mtk_6358_dai_codecs, ARRAY_SIZE(mtk_6358_dai_codecs)); } static int mtk_mt6358_codec_dev_remove(struct platform_device *pdev) { snd_soc_unregister_component(&pdev->dev); return 0; } #ifdef CONFIG_OF static const struct of_device_id mt_soc_codec_63xx_of_ids[] = { {.compatible = "mediatek,mt_soc_codec_63xx",}, {} }; #endif static struct platform_driver mtk_codec_6358_driver = { .driver = { .name = MT_SOC_CODEC_NAME, .owner = THIS_MODULE, #ifdef CONFIG_OF .of_match_table = mt_soc_codec_63xx_of_ids, #endif }, .probe = mtk_mt6358_codec_dev_probe, .remove = mtk_mt6358_codec_dev_remove, }; #ifndef CONFIG_OF static struct platform_device *soc_mtk_codec6358_dev; #endif static int __init mtk_mt6358_codec_init(void) { pr_info("%s:\n", __func__); #ifndef CONFIG_OF int ret = 0; soc_mtk_codec6358_dev = platform_device_alloc(MT_SOC_CODEC_NAME, -1); if (!soc_mtk_codec6358_dev) return -ENOMEM; ret = platform_device_add(soc_mtk_codec6358_dev); if (ret != 0) { platform_device_put(soc_mtk_codec6358_dev); return ret; } #endif InitGlobalVarDefault(); return platform_driver_register(&mtk_codec_6358_driver); } module_init(mtk_mt6358_codec_init); static void __exit mtk_mt6358_codec_exit(void) { platform_driver_unregister(&mtk_codec_6358_driver); } module_exit(mtk_mt6358_codec_exit); /* Module information */ MODULE_DESCRIPTION("MTK codec driver"); MODULE_LICENSE("GPL v2");