kernel_samsung_a34x-permissive/sound/soc/mediatek/codec/mt6358/mtk-soc-codec-6358.c
2024-04-28 15:51:13 +02:00

7890 lines
222 KiB
C

/* 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 <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#ifdef CONFIG_MTK_ACCDET
#include "accdet.h"
#endif
#include <mt-plat/mtk_auxadc_intf.h>
#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 <mach/vow_api.h>
#endif
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#ifdef CONFIG_MT8183_QUERY_PCB_ID_METHOD
#include<mtk_auxadc.h>
#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, &reg_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, &reg_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) {
/* <Periodic ON> */
/* 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");