kernel_samsung_a34x-permissive/sound/soc/mediatek/codec/mt6357/mtk-soc-codec-6357.c

6177 lines
200 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
* Author: Michael Hsiao <michael.hsiao@mediatek.com>
*/
/******************************************************************************
*
* 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 <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <linux/math64.h>
#ifdef CONFIG_MTK_AUXADC_INTF
#include <mt-plat/mtk_auxadc_intf.h>
#include <mach/mtk_pmic.h>
#endif
#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"
#include <linux/iio/consumer.h>
#include <linux/mfd/mt6357/registers.h>
#include <linux/mfd/mt6397/core.h>
#include <linux/mfd/mt6357/core.h>
#if IS_ENABLED(CONFIG_MTK_PMIC_WRAP)
#include <linux/soc/mediatek/pmic_wrap.h>
#endif
#ifdef CONFIG_SND_SOC_MT6357_ACCDET
#include "../../../codecs/mt6357-accdet.h"
#endif
#include <linux/nvmem-consumer.h>
#include "mtk-soc-speaker-amp.h"
/* Use analog setting to do dc compensation */
#define ANALOG_HPTRIM
//#define ANALOG_HPTRIM_FOR_CUST
//#define BYPASS_HPIMP
/* 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 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 struct mt6357_codec_priv *mCodec_data;
static struct mt6357_priv *mCodec_priv;
static unsigned int mBlockSampleRate[AUDIO_ANALOG_DEVICE_INOUT_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 = AUDIO_ANALOGUL_MODE_ACC;
static int mAudio_Analog_Mic2_mode = AUDIO_ANALOGUL_MODE_ACC;
static int mAudio_Analog_Mic3_mode = AUDIO_ANALOGUL_MODE_ACC;
static int mAudio_Analog_Mic4_mode = AUDIO_ANALOGUL_MODE_ACC;
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_12DB = 20,
DL_GAIN_N_40DB = 0x1f,
};
#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 bool apply_n12db_gain;
static unsigned int dAuxAdcChannel = 16;
static const int mDcOffsetTrimChannel = 9;
static bool mInitCodec;
static unsigned int always_pull_down_enable;
static unsigned int always_pull_low_off;
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;
/* 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)
static void Audio_Amp_Change(int channels, bool enable);
static void SavePowerState(void)
{
int i = 0;
for (i = 0; i < AUDIO_ANALOG_DEVICE_MAX; i++) {
mCodec_data->mAudio_BackUpAna_DevicePower[i] =
mCodec_data->mAudio_Ana_DevicePower[i];
}
}
static void RestorePowerState(void)
{
int i = 0;
for (i = 0; i < AUDIO_ANALOG_DEVICE_MAX; i++) {
mCodec_data->mAudio_Ana_DevicePower[i] =
mCodec_data->mAudio_BackUpAna_DevicePower[i];
}
}
static bool GetDLStatus(void)
{
int i = 0;
for (i = 0; i < AUDIO_ANALOG_DEVICE_2IN1_SPK; i++) {
if (mCodec_data->mAudio_Ana_DevicePower[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->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_HEADSETL] == true) {
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_HEADSETL] = false;
Audio_Amp_Change(AUDIO_ANALOG_CHANNELS_LEFT1, false);
}
if (mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_HEADSETR] == true) {
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_HEADSETR] = false;
Audio_Amp_Change(AUDIO_ANALOG_CHANNELS_RIGHT1, false);
}
if (mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_EARPIECEL] == true) {
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_EARPIECEL] = false;
Voice_Amp_Change(false);
}
if (mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_SPEAKERL] == true) {
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_SPEAKERL] = false;
Speaker_Amp_Change(false);
}
/*Ana_Log_Print();*/
mAnaSuspend = true;
} else if ((bEnable == false) && (mAnaSuspend == true)) {
/*Ana_Log_Print();*/
if (mCodec_data->mAudio_BackUpAna_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_HEADSETL] == true) {
Audio_Amp_Change(AUDIO_ANALOG_CHANNELS_LEFT1, true);
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_HEADSETL] = true;
}
if (mCodec_data->mAudio_BackUpAna_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_HEADSETR] == true) {
Audio_Amp_Change(AUDIO_ANALOG_CHANNELS_RIGHT1, true);
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_HEADSETR] = false;
}
if (mCodec_data->mAudio_BackUpAna_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_EARPIECEL] == true) {
Voice_Amp_Change(true);
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_EARPIECEL] = false;
}
if (mCodec_data->mAudio_BackUpAna_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_SPEAKERL] == true) {
Speaker_Amp_Change(true);
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_SPEAKERL] = false;
}
RestorePowerState();
/*Ana_Log_Print();*/
mAnaSuspend = false;
}
}
static int audck_buf_Count;
void audckbufEnable(bool enable)
{
/* pr_debug("%s audck_buf_Count = %d, enable = %d\n",
* __func__, audck_buf_Count, 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_debug("audck_buf_Count count < 0\n");
audck_buf_Count = 0;
}
}
mutex_unlock(&Ana_buf_Ctrl_Mutex);
}
static int ClsqCount;
static void ClsqEnable(bool enable)
{
/* pr_debug("%s ClsqCount = %d enable = %d\n",
* __func__, ClsqCount, enable);
*/
mutex_lock(&AudAna_lock);
if (enable) {
if (ClsqCount == 0) {
Ana_Set_Reg(AUDENC_ANA_CON6, 0x0001, 0x0001);
/* Enable CLKSQ 26MHz */
}
ClsqCount++;
} else {
ClsqCount--;
if (ClsqCount < 0) {
pr_debug("%s(), count <0\n", __func__);
ClsqCount = 0;
}
if (ClsqCount == 0) {
Ana_Set_Reg(AUDENC_ANA_CON6, 0x0000, 0x0001);
/* Disable CLKSQ 26MHz */
}
}
mutex_unlock(&AudAna_lock);
}
static int TopCkCount;
static void Topck_Enable(bool enable)
{
/* pr_debug("%s enable = %d TopCkCount = %d\n",
* __func__, enable, TopCkCount);
*/
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 */
/* Turn off AUD 26M */
}
if (TopCkCount < 0) {
pr_debug("TopCkCount <0 =%d\n ", TopCkCount);
TopCkCount = 0;
}
}
mutex_unlock(&Ana_Clk_Mutex);
}
static int NvRegCount;
static void NvregEnable(bool enable)
{
/* pr_debug("%s NvRegCount == %d enable = %d\n",
* __func__, NvRegCount, enable);
*/
mutex_lock(&Ana_Clk_Mutex);
if (enable == true) {
if (NvRegCount == 0) {
Ana_Set_Reg(AUDDEC_ANA_CON11, 0x0, 0x1 << 4);
/* Enable AUDGLB */
}
NvRegCount++;
} else {
NvRegCount--;
if (NvRegCount == 0) {
Ana_Set_Reg(AUDDEC_ANA_CON11, 0x1 << 4, 0x1 << 4);
/* Disable AUDGLB */
}
if (NvRegCount < 0) {
pr_debug("%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);
Ana_Set_Reg(SMT_CON1, 0x0ff0, 0x0ff0);
} 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);
Ana_Set_Reg(SMT_CON1, 0x0000, 0x0ff0);
}
}
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);
Ana_Set_Reg(SMT_CON1, 0x0ff0, 0x0ff0);
} 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);
Ana_Set_Reg(SMT_CON1, 0x0000, 0x0ff0);
}
}
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)
{
int value = 0, ret = 0;
if (!IS_ERR(mCodec_priv->codec_auxadc)) {
ret = iio_read_channel_raw(mCodec_priv->codec_auxadc,
&value);
if (ret < 0) {
pr_notice("Error: %s read fail (%d)\n", __func__, ret);
return ret;
}
}
pr_debug("%s() value :%d\n", __func__, value);
return value;
}
static int get_accdet_auxadc(void)
{
int value = 0, ret = 0;
if (!IS_ERR(mCodec_priv->accdet_auxadc)) {
ret = iio_read_channel_processed(mCodec_priv->accdet_auxadc,
&value);
if (ret < 0) {
pr_notice("Error: %s read fail (%d)\n", __func__, ret);
return ret;
}
}
pr_debug("%s() value :%d\n", __func__, value);
return value;
}
/*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];
pr_debug("+%s()", __func__);
/* 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);
pr_debug(
"%s() polling 0xC1A=0x%x\n", __func__,
reg_val);
}
udelay(1000);
/* Need to 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 RG_AUDHPRTRIM_VAUDP15 = %x RG_AUDHPLFINETRIM_VAUDP15 = %x RG_AUDHPRFINETRIM_VAUDP15 = %x\n",
RG_AUDHPLTRIM_VAUDP15,
RG_AUDHPRTRIM_VAUDP15,
RG_AUDHPLFINETRIM_VAUDP15,
RG_AUDHPRFINETRIM_VAUDP15);
pr_debug("RG_AUDHPLTRIM_VAUDP15_SPKHP = %x RG_AUDHPLTRIM_VAUDP15_SPKHP = %x RG_AUDHPLFINETRIM_VAUDP15_SPKHP = %x RG_AUDHPRFINETRIM_VAUDP15_SPKHP = %x\n",
RG_AUDHPLTRIM_VAUDP15_SPKHP,
RG_AUDHPRTRIM_VAUDP15_SPKHP,
RG_AUDHPLFINETRIM_VAUDP15_SPKHP,
RG_AUDHPRFINETRIM_VAUDP15_SPKHP);
#endif
#endif
pr_debug("-%s()\n", __func__);
}
EXPORT_SYMBOL(Auddrv_Read_Efuse_HPOffset);
#ifndef BYPASS_HPIMP
static void setHpGainZero(void)
{
Ana_Set_Reg(ZCD_CON2, DL_GAIN_0DB << 7, 0x0f80);
Ana_Set_Reg(ZCD_CON2, DL_GAIN_0DB, 0x001f);
}
#endif
static void Zcd_Enable(bool _enable, int device)
{
if (_enable) {
switch (device) {
case AUDIO_ANALOG_DEVICE_OUT_EARPIECEL:
case AUDIO_ANALOG_DEVICE_OUT_EARPIECER:
Ana_Set_Reg(AUDDEC_ANA_CON8, 0x2, 0x7);
break;
case AUDIO_ANALOG_DEVICE_OUT_SPEAKERL:
case AUDIO_ANALOG_DEVICE_OUT_SPEAKERR:
Ana_Set_Reg(AUDDEC_ANA_CON8, 0x0, 0x7);
break;
case AUDIO_ANALOG_DEVICE_OUT_SPEAKER_HEADSET_L:
case AUDIO_ANALOG_DEVICE_OUT_SPEAKER_HEADSET_R:
Ana_Set_Reg(AUDDEC_ANA_CON8, 0x1, 0x7);
break;
case AUDIO_ANALOG_DEVICE_OUT_HEADSETL:
case AUDIO_ANALOG_DEVICE_OUT_HEADSETR:
default:
Ana_Set_Reg(AUDDEC_ANA_CON8, 0x1, 0x7);
break;
}
/* 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, 0x0 << 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(AUDDEC_ANA_CON8, 0x4, 0x7);
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 << 12, 0x7 << 12);
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_CON6, stage << 12, 0xf << 12);
udelay(600);
}
}
static void hp_pull_down(bool enable)
{
if (enable)
Ana_Set_Reg(AUDDEC_ANA_CON2, 0x400, 0x400);
else
Ana_Set_Reg(AUDDEC_ANA_CON2, 0x000, 0x400);
}
static bool is_valid_hp_pga_idx(int reg_idx)
{
return (reg_idx >= DL_GAIN_8DB && reg_idx <= DL_GAIN_N_12DB) ||
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_debug("%s(), volume index is not valid, from %d, to %d\n",
__func__, from, to);
/* pr_debug("%s, 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)
{
/* pr_debug("%s Mux = %d\n", __func__, Mux); */
/* Audio offset trimming buffer mux selection */
Ana_Set_Reg(AUDDEC_ANA_CON5, Mux, 0xf);
}
static void setOffsetTrimBufferGain(unsigned int gain)
{
/* Audio offset trimming buffer gain selection */
Ana_Set_Reg(AUDDEC_ANA_CON5, gain << 4, 0x3 << 4);
}
static void EnableTrimbuffer(bool benable)
{
if (benable == true) {
Ana_Set_Reg(AUDDEC_ANA_CON5, 0x1 << 6, 0x1 << 6);
/* Audio offset trimming buffer enable */
} else {
Ana_Set_Reg(AUDDEC_ANA_CON5, 0x0, 0x1 << 6);
/* Audio offset trimming buffer disable */
}
}
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);
}
static void set_input_mux(unsigned int Mux)
{
/* Audio left headphone input multiplexor selection,
* positive/negative pins:
* (00) open / open
* (01) LOLP / LOLN
* (10) IDACRP / IDACRN
* (11) HSP / HSN (test mode)
*/
Ana_Set_Reg(AUDDEC_ANA_CON0, Mux << 8, 0x3 << 8);
}
static void enable_lo_buffer(bool enable)
{
if (enable) {
Ana_Set_Reg(AUDDEC_ANA_CON4, 0x0110, 0xffff);
Ana_Set_Reg(AUDDEC_ANA_CON4, 0x0112, 0xffff);
Ana_Set_Reg(AUDDEC_ANA_CON4, 0x0113, 0xffff);
} else
/* Disable LO main output stage */
Ana_Set_Reg(AUDDEC_ANA_CON4, 0x0010, 0xffff);
}
#if !defined(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_CON7, 0xa0, 0xff);
TurnOnDacPower(AUDIO_ANALOG_DEVICE_OUT_HEADSETL);
/* sdm output mute enable */
/* Disable handset short-circuit protection */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x3000, 0xffff);
/* Disable linout short-circuit protection */
/* Reduce ESD resistance of AU_REFN */
Ana_Set_Reg(AUDDEC_ANA_CON2, 0x200, 0x200);
/* Set HPR/HPL gain as minimum (~ -40dB) */
Ana_Set_Reg(ZCD_CON2, DL_GAIN_N_40DB_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_CON12, 0x1055, 0x1055);
/* Enable NV regulator (-1.2V) */
Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0001, 0xffff);
udelay(100);
/* Disable AUD_ZCD */
Zcd_Enable(false, AUDIO_ANALOG_DEVICE_OUT_HEADSETL);
/* Enable IBIST */
Ana_Set_Reg(AUDDEC_ANA_CON10, 0x0055, 0xffff);
/* Set HP DR bias current optimization, 010: 6uA */
Ana_Set_Reg(AUDDEC_ANA_CON9, 0x92, 0xffff);
/* Set HP & ZCD bias current optimization */
/* 01: ZCD: 4uA, HP/HS/LO: 5uA */
Ana_Set_Reg(AUDDEC_ANA_CON10, 0x0055, 0xffff);
/* Set HPP/N STB enhance circuits */
Ana_Set_Reg(AUDDEC_ANA_CON2, 0x033, 0x00ff);
if (buffer_on) {
/* Enable HP aux output stage */
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x000c, 0xffff);
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x003c, 0xffff);
/* Enable HP main CMFB loop */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0c80, 0x0fff);
/* Enable HP driver bias circuits */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x30c0, 0xffff);
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x30f0, 0xffff);
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x00fc, 0x00ff);
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0e80, 0x0fff);
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0280, 0x0fff);
/* 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);
/* Enable HP aux feedback loop */
hp_aux_feedback_loop_gain_ramp(true);
/* Disable HP aux feedback loop */
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x77cf, 0xffff);
/* apply volume setting */
headset_volume_ramp(DL_GAIN_N_40DB,
mCodec_data->mAudio_Ana_Volume
[AUDIO_ANALOG_VOLUME_HPOUTL]);
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x00cf, 0x00ff);
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x00c3, 0x00ff);
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0003, 0x00ff);
/* Disable HP aux output stage */
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x77c3, 0xffff);
/* Unshort HP main output to HP aux output stage */
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x7703, 0xffff);
udelay(1000);
/* disable Pull-down HPL/R to AVSS28_AUD */
hp_pull_down(false);
} else {
/* Enable HP driver bias circuits */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x30c0, 0xf0ff);
/* Enable HS driver bias circuits */
/* Disable HS main output stage */
Ana_Set_Reg(AUDDEC_ANA_CON3, 0x0010, 0xffff);
/* Enable LO driver bias circuits */
/* Disable LO main output stage */
Ana_Set_Reg(AUDDEC_ANA_CON4, 0x0010, 0xffff);
}
/* Enable AUD_CLK */
Ana_Set_Reg(AUDDEC_ANA_CON11, 0x1, 0x1);
/* Enable low-noise mode of DAC */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0283, 0x0fff);
udelay(100);
} else {
/* Pull-down HPL/R to AVSS28_AUD */
hp_pull_down(true);
headset_volume_ramp(mCodec_data->mAudio_Ana_Volume
[AUDIO_ANALOG_VOLUME_HPOUTL], DL_GAIN_N_40DB);
/* HPR/HPL mux to open */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0000, 0x0f00);
/* Disable low-noise mode of DAC */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0000, 0x0001);
/* Disable Audio DAC */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0000, 0x000f);
/* Disable AUD_CLK */
Ana_Set_Reg(AUDDEC_ANA_CON11, 0x0, 0x1);
/* decrease HPL/R gain to normal gain step by step */
/* Short HP main output to HP aux output stage */
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x77c3, 0x00ff);
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x77cf, 0x00ff);
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x77ff, 0x00ff);
/* Disable HP aux feedback loop */
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);
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);
/* Enable HP main CMFB Switch */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x2 << 8, 0xff << 8);
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0, 0x3 << 4);
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0, 0x3 << 2);
/* Pull-down HPL/R, HS, LO to AVSS28_AUD */
Ana_Set_Reg(AUDDEC_ANA_CON7, 0xa8, 0xff);
/* Disable IBIST */
Ana_Set_Reg(AUDDEC_ANA_CON10, 0x1 << 8, 0x1 << 8);
/* Disable NV regulator (-1.2V) */
Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0, 0x1);
/* Disable cap-less LDOs (1.5V) */
Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0, 0x1055);
if (always_pull_low_off) {
/* Reset HPP/N STB enhance circuits */
Ana_Set_Reg(AUDDEC_ANA_CON2, 0x0, 0xff);
}
/* Disable NCP */
Ana_Set_Reg(AUDNCP_CLKDIV_CON3, 0x1, 0x1);
TurnOffDacPower();
}
}
static void open_trim_bufferhardware_withspk(bool enable, bool buffer_on)
{
pr_debug("%s(), enable %d, buffer_on %d\n",
__func__, enable, buffer_on);
if (enable) {
TurnOnDacPower(AUDIO_ANALOG_DEVICE_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 selection (01) LOLP / LOLN */
set_input_mux(1);
/* Disable handset short-circuit protection */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x3000, 0xf0ff);
/* Disable linout short-circuit protection */
/* Reduce ESD resistance of AU_REFN */
Ana_Set_Reg(AUDDEC_ANA_CON2, 0x200, 0x200);
/* Set HPR/HPL gain as minimum (~ -40dB) */
Ana_Set_Reg(ZCD_CON2, DL_GAIN_N_40DB_REG, 0xffff);
/* Set SPK gain as minimum (~ -40dB) */
Ana_Set_Reg(ZCD_CON1, DL_GAIN_N_40DB_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_CON12, 0x1055, 0x1055);
/* Enable NV regulator (-1.2V) */
Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0001, 0xffff);
udelay(100);
/* Disable AUD_ZCD */
Zcd_Enable(false, AUDIO_ANALOG_DEVICE_OUT_HEADSETL);
/* Enable IBIST */
Ana_Set_Reg(AUDDEC_ANA_CON10, 0x0055, 0xffff);
/* Set HP DR bias current optimization, 010: 6uA */
Ana_Set_Reg(AUDDEC_ANA_CON9, 0x92, 0xffff);
/* Set HP & ZCD bias current optimization */
/* 01: ZCD: 4uA, HP/HS/LO: 5uA */
Ana_Set_Reg(AUDDEC_ANA_CON10, 0x0055, 0xffff);
/* Set HPP/N STB enhance circuits */
Ana_Set_Reg(AUDDEC_ANA_CON2, 0x0033, 0x00ff);
if (buffer_on) {
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x000c, 0x00ff);
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x003c, 0x00ff);
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0c80, 0x0fff);
/* Enable HP driver bias circuits */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x35c0, 0xf0ff);
/* Enable HP driver core circuits */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x35f0, 0xf0ff);
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x00fc, 0x00ff);
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0e80, 0x0fff);
/* Enable HP main CMFB loop */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0280, 0x0fff);
/* Enable HS driver bias circuits */
/* Disable HS main output stage */
Ana_Set_Reg(AUDDEC_ANA_CON3, 0x0010, 0xffff);
/* Enable LO driver bias circuits */
/* Disable LO main output stage */
Ana_Set_Reg(AUDDEC_ANA_CON4, 0x0010, 0xffff);
enable_lo_buffer(true);
apply_speaker_gain(DL_GAIN_0DB);
/* Enable HP main output stage */
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x00ff, 0x00ff);
hp_main_output_ramp(true);
hp_aux_feedback_loop_gain_ramp(true);
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x77cf, 0x00ff);
/* apply volume setting */
headset_volume_ramp(DL_GAIN_N_40DB, DL_GAIN_N_12DB);
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x77c3, 0x00ff);
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x7703, 0x00ff);
/* disable Pull-down HPL/R to AVSS28_AUD */
hp_pull_down(false);
} else {
/* Enable HP driver bias circuits */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x30c0, 0xffff);
/* Enable HS driver bias circuits */
/* Disable HS main output stage */
Ana_Set_Reg(AUDDEC_ANA_CON3, 0x0010, 0xffff);
/* Enable LO driver bias circuits */
/* Disable LO main output stage */
enable_lo_buffer(false);
}
/* Enable AUD_CLK */
Ana_Set_Reg(AUDDEC_ANA_CON11, 0x1, 0x1);
/* Enable low-noise mode of DAC */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0283, 0x0fff);
udelay(100);
} else {
/* Pull-down HPL/R to AVSS28_AUD */
hp_pull_down(true);
/* HPR/HPL mux to open */
/* decrease HPL/R gain to normal gain step by step */
headset_volume_ramp(DL_GAIN_N_12DB, DL_GAIN_N_40DB);
Ana_Set_Reg(ZCD_CON1, DL_GAIN_N_40DB_REG, 0xffff);
/* Audio left headphone input selection (00) open / open */
set_input_mux(0);
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0000, 0x0f00);
/* Disable low-noise mode of DAC */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0000, 0x0001);
/* Disable Audio DAC */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0000, 0x000f);
/* Disable AUD_CLK */
Ana_Set_Reg(AUDDEC_ANA_CON11, 0x0, 0x1);
/* Short HP main output to HP aux output stage */
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x77c3, 0x00ff);
/* Enable HP aux output stage */
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x77cf, 0x00ff);
/* Disable HS main output stage */
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x77ff, 0x00ff);
/* 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);
/* HPR/HPL mux to open */
/* Disable HP main output stage */
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0, 0x3);
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);
/* Enable HP main CMFB Switch */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x2 << 8, 0xff << 8);
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0, 0x3 << 4);
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x0, 0x3 << 2);
/* Pull-down HPL/R, HS, LO to AVSS28_AUD */
Ana_Set_Reg(AUDDEC_ANA_CON7, 0xa8, 0xff);
/* Disable IBIST */
Ana_Set_Reg(AUDDEC_ANA_CON10, 0x1 << 8, 0x1 << 8);
/* Disable NV regulator (-1.2V) */
Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0, 0x1);
/* Disable cap-less LDOs (1.5V) */
Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0, 0x1055);
if (always_pull_low_off) {
/* Reset HPP/N STB enhance circuits */
Ana_Set_Reg(AUDDEC_ANA_CON2, 0x0, 0xff);
}
/* Disable NCP */
Ana_Set_Reg(AUDNCP_CLKDIV_CON3, 0x1, 0x1);
TurnOffDacPower();
}
}
#endif
static int efuse_current_calibrate;
#ifndef BYPASS_HPIMP
static bool OpenHeadPhoneImpedanceSetting(bool bEnable)
{
/* pr_debug("%s benable = %d\n", __func__, bEnable); */
if (GetDLStatus() == true)
return false;
if (bEnable == true) {
TurnOnDacPower(AUDIO_ANALOG_DEVICE_OUT_HEADSETL);
/* Disable headphone short-circuit protection */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x3000, 0xffff);
/* Disable handset short-circuit protection */
Ana_Set_Reg(AUDDEC_ANA_CON3, 0x0010, 0xffff);
/* Disable linout short-circuit protection */
enable_lo_buffer(false);
/* Reduce ESD resistance of AU_REFN */
Ana_Set_Reg(AUDDEC_ANA_CON2, 0x200, 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_CON12, 0x1055, 0x1055);
/* Enable NV regulator (-1.2V) */
Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0001, 0xffff);
udelay(100);
/* Disable AUD_ZCD */
Zcd_Enable(false, AUDIO_ANALOG_DEVICE_OUT_HEADSETL);
/* Enable IBIST */
Ana_Set_Reg(AUDDEC_ANA_CON10, 0x0055, 0xffff);
/* Disable HPR/L STB enhance circuits */
Ana_Set_Reg(AUDDEC_ANA_CON2, 0x200, 0xffff);
/* Enable HP main CMFB Switch */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0280, 0x0fff);
/* Enable AUD_CLK */
Ana_Set_Reg(AUDDEC_ANA_CON11, 0x1, 0x1);
/* Enable Audio L channel DAC */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x3009, 0xffff);
/* Enable HPDET circuit,
* select DACLP as HPDET input and HPR as HPDET output
*/
Ana_Set_Reg(AUDDEC_ANA_CON5, 0x1900, 0xffff);
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0283, 0x0fff);
/* disable Pull-down HPL/R to AVSS28_AUD */
hp_pull_down(false);
} else {
/* enable Pull-down HPL/R to AVSS28_AUD */
hp_pull_down(true);
/* disable HPDET circuit */
Ana_Set_Reg(AUDDEC_ANA_CON5, 0x0000, 0xff00);
/* Disable Audio DAC */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0000, 0x000f);
/* Disable AUD_CLK */
Ana_Set_Reg(AUDDEC_ANA_CON11, 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_CON6, 0x0, 0xff << 8);
/* Enable HP main CMFB Switch */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x2 << 8, 0xff << 8);
/* Pull-down HPL/R, HS, LO to AVSS28_AUD */
Ana_Set_Reg(AUDDEC_ANA_CON7, 0xa8, 0xff);
/* Disable IBIST */
Ana_Set_Reg(AUDDEC_ANA_CON10, 0x1 << 8, 0x1 << 8);
/* Disable NV regulator (-1.2V) */
Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0, 0x1);
/* Disable cap-less LDOs (1.5V) */
Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0, 0x1055);
if (always_pull_low_off) {
/* Reset HPP/N STB enhance circuits */
Ana_Set_Reg(AUDDEC_ANA_CON2, 0x0, 0xff);
} else {
Ana_Set_Reg(AUDDEC_ANA_CON2, 0x33, 0xff);
}
/* Disable NCP */
Ana_Set_Reg(AUDNCP_CLKDIV_CON3, 0x1, 0x1);
TurnOffDacPower();
}
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 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_debug("%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;
}
#define PARALLEL_OHM 470
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;
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_debug("%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);
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_info("%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_info("%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 detect auxadc value over 32630 ,
* the hpImpedance is over 5k ohm
*/
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);
}
if (PARALLEL_OHM != 0) {
if (impedance < PARALLEL_OHM) {
impedance = DIV_ROUND_CLOSEST(impedance *
PARALLEL_OHM,
PARALLEL_OHM -
impedance);
} else {
pr_debug("%s(), PARALLEL_OHM %d <= impedance %d\n",
__func__, PARALLEL_OHM, impedance);
}
}
pr_debug("%s(), phase %d [dc,detect]Sum %d times [%d,%d], hp_impedance %d, pick_impedance %d, AUXADC_CON10 0x%x\n",
__func__, phase_flag, kDetectTimes, dcSum, detectSum,
impedance, pick_impedance,
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);
return impedance;
}
#endif
/* 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 ana_trim_offset {
int hpl_trimecode;
int hpr_trimecode;
int hpl_finetrim;
int hpr_finetrim;
};
static struct ana_trim_offset hp_3pole_anaoffset,
hp_4pole_anaoffset,
spk_3pole_anaoffset,
spk_4pole_anaoffset;
#endif
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,
32613, 36592, 41058, 46067,
51688, 57995, 65071, 73011,
81920, 91916, 103131, 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_debug("%s(), invalid mic_bias %d\n", __func__, mic_bias);
return 2600;
};
}
static int calOffsetToDcComp(int offset, int vol_type)
{
int gain = mCodec_data->mAudio_Ana_Volume[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 long long get_gain_offset(int offset, int spkoffset,
int gain, int spkgain)
{
/* Follow hw path design to
* calculate offset by speaker and headphone gain
*/
long long ret;
ret = ((dBFactor_Nom[gain] + dBFactor_Den) /
(dBFactor_Den) * offset + spkoffset / 2) *
dBFactor_Nom[spkgain]/dBFactor_Den;
pr_debug("%s(), %lld gain %d spkgain %d\n",
__func__, ret, gain, spkgain);
return ret;
}
static long long calOffsetToDcCompSPKL(int offset, int vol_type)
{
int gain = apply_n12db_gain ?
mCodec_data->mAudio_Ana_Volume[vol_type] + 12 :
mCodec_data->mAudio_Ana_Volume[vol_type];
int mic_bias_mv;
int real_mic_vinp_mv;
long long offset_scale =
(long long) get_gain_offset(hpl_dc_offset, offset, gain,
mCodec_data->mAudio_Ana_Volume
[AUDIO_ANALOG_VOLUME_LINEOUTL]);
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);
}
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 */
pr_debug("%s(), %lld ret (1) %lld (2) %lld (size %d)\n",
__func__, offset_scale,
(long long)(offset_scale * 2804225),
(long long)(offset_scale * 2804225) / 32768,
sizeof(offset_scale));
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*/
/* 80uV / 0.0808uV(0dB) = 990.099 */
int step_0db = 990;
/* 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->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_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_debug("%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,
AUDIO_ANALOG_VOLUME_HPOUTL);
rch_value = calOffsetToDcComp(hpr_dc_offset,
AUDIO_ANALOG_VOLUME_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);
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(600);
}
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(sign_lch *
tmp_ramp << 8);
if (tmp_ramp < abs_rch)
set_rch_dc_compensation(sign_rch *
tmp_ramp << 8);
udelay(600);
}
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;
}
static int SetDcCompenSation_spk2hp(bool enable)
{
long long lch_value = 0, rch_value = 0, tmp_rampL = 0, tmp_rampR = 0;
int times = 0, i = 0;
long long sign_lch = 0, sign_rch = 0;
long long abs_lch = 0, abs_rch = 0;
int index_lgain =
apply_n12db_gain ?
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_HPOUTL] +
12 :
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_HPOUTL];
int index_rgain =
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_HPOUTL];
long long diff_lch = 0, diff_rch = 0, ramp_l = 0, ramp_r = 0;
long long ramp_stepL = get_dc_ramp_step(index_lgain);
long long ramp_stepR = get_dc_ramp_step(index_rgain);
long long ramp_times_lch = 0, ramp_times_rch = 0;
if (enable_dc_compensation == NULL ||
set_lch_dc_compensation == NULL ||
set_rch_dc_compensation == NULL) {
pr_debug("%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 = calOffsetToDcCompSPKL(spkl_dc_offset,
AUDIO_ANALOG_VOLUME_HPOUTL);
rch_value = calOffsetToDcComp(hpr_dc_offset,
AUDIO_ANALOG_VOLUME_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;
ramp_times_lch = abs_lch;
ramp_times_rch = abs_rch;
do_div(ramp_times_lch, ramp_stepL);
do_div(ramp_times_rch, ramp_stepR);
times = ramp_times_lch > ramp_times_rch ?
ramp_times_lch : ramp_times_rch;
if (enable) {
enable_dc_compensation(true);
for (i = 1; i <= times; i++) {
tmp_rampL = i * ramp_stepL;
tmp_rampR = i * ramp_stepR;
if (tmp_rampL < abs_lch) {
ramp_l = last_spk2hp_lch_comp_value +
sign_lch * tmp_rampL;
set_lch_dc_compensation(ramp_l << 8);
}
if (tmp_rampR < abs_rch) {
ramp_r = last_spk2hp_rch_comp_value +
sign_rch * tmp_rampR;
set_rch_dc_compensation(ramp_r << 8);
}
udelay(600);
}
set_lch_dc_compensation(lch_value << 8);
set_rch_dc_compensation(rch_value << 8);
last_spk2hp_lch_comp_value = lch_value;
last_spk2hp_rch_comp_value = rch_value;
} else {
for (i = times; i >= 0; i--) {
tmp_rampL = i * ramp_stepL;
tmp_rampR = i * ramp_stepR;
if (tmp_rampL < abs_lch)
set_lch_dc_compensation(sign_lch *
tmp_rampL << 8);
if (tmp_rampR < abs_rch)
set_rch_dc_compensation(sign_rch *
tmp_rampR << 8);
udelay(600);
}
set_lch_dc_compensation(0);
set_rch_dc_compensation(0);
enable_dc_compensation(false);
last_spk2hp_lch_comp_value = 0;
last_spk2hp_rch_comp_value = 0;
}
return 0;
}
#endif
#ifndef CONFIG_FPGA_EARLY_PORTING
static int calculate_trimmed_mean_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);
}
#endif
static void get_hp_trim_offset(void)
{
#ifndef CONFIG_FPGA_EARLY_PORTING
#ifdef ANALOG_HPTRIM
#define TRIM_TIMES 7
#define TRIM_DISCARD_NUM 1
#else
#define TRIM_TIMES 26
#define TRIM_DISCARD_NUM 3
#endif
#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);
/* get buffer on auxadc value */
OpenTrimBufferHardware(true, true);
setOffsetTrimMux(AUDIO_OFFSET_TRIM_MUX_HPL);
setOffsetTrimBufferGain(3); /* 18db */
EnableTrimbuffer(true);
usleep_range(1*1000, 10*1000);
for (i = 0; i < TRIM_TIMES; i++)
on_valueL[i] = audio_get_auxadc_value();
setOffsetTrimMux(AUDIO_OFFSET_TRIM_MUX_HPR);
usleep_range(1*1000, 10*1000);
for (i = 0; i < TRIM_TIMES; i++)
on_valueR[i] = audio_get_auxadc_value();
EnableTrimbuffer(false);
setOffsetTrimMux(AUDIO_OFFSET_TRIM_MUX_GROUND);
OpenTrimBufferHardware(false, true);
/* get buffer off auxadc value */
OpenTrimBufferHardware(true, false);
setOffsetTrimMux(AUDIO_OFFSET_TRIM_MUX_HPL);
setOffsetTrimBufferGain(3); /* 18db */
EnableTrimbuffer(true);
usleep_range(1*1000, 10*1000);
for (i = 0; i < TRIM_TIMES; i++)
off_valueL[i] = audio_get_auxadc_value();
setOffsetTrimMux(AUDIO_OFFSET_TRIM_MUX_HPR);
usleep_range(1*1000, 10*1000);
for (i = 0; i < TRIM_TIMES; i++)
off_valueR[i] = audio_get_auxadc_value();
EnableTrimbuffer(false);
setOffsetTrimMux(AUDIO_OFFSET_TRIM_MUX_GROUND);
OpenTrimBufferHardware(false, false);
hpl_dc_offset =
calculate_trimmed_mean_result(on_valueL, off_valueL,
TRIM_TIMES, TRIM_DISCARD_NUM,
TRIM_USEFUL_NUM);
hpr_dc_offset =
calculate_trimmed_mean_result(on_valueR, off_valueR,
TRIM_TIMES, TRIM_DISCARD_NUM,
TRIM_USEFUL_NUM);
pr_debug("%s(), channeL = %d, channeR = %d\n",
__func__, hpl_dc_offset, hpr_dc_offset);
#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;
#ifndef ANALOG_HPTRIM
Ana_Set_Reg(AUXADC_CON10, AUXADC_AVG_256, 0x7);
/* get buffer on auxadc value */
open_trim_bufferhardware_withspk(true, true);
setOffsetTrimMux(AUDIO_OFFSET_TRIM_MUX_LOLP);
setOffsetTrimBufferGain(3); /* 18db */
EnableTrimbuffer(true);
usleep_range(1*1000, 10*1000);
for (i = 0; i < TRIM_TIMES; i++)
on_value[i] = audio_get_auxadc_value();
setOffsetTrimMux(AUDIO_OFFSET_TRIM_MUX_LOLN);
setOffsetTrimBufferGain(3); /* 18db */
EnableTrimbuffer(true);
usleep_range(1*1000, 10*1000);
for (i = 0; i < TRIM_TIMES; i++)
off_value[i] = audio_get_auxadc_value();
EnableTrimbuffer(false);
setOffsetTrimMux(AUDIO_OFFSET_TRIM_MUX_GROUND);
open_trim_bufferhardware_withspk(false, false);
offset = calculate_trimmed_mean_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;
#else
Ana_Set_Reg(AUXADC_CON10, AUXADC_AVG_256, 0x7);
/* get buffer on auxadc value */
open_trim_bufferhardware_withspk(true, true);
setOffsetTrimMux(channel);
setOffsetTrimBufferGain(3); /* 18db */
EnableTrimbuffer(true);
usleep_range(1*1000, 10*1000);
for (i = 0; i < TRIM_TIMES; i++)
on_value[i] = audio_get_auxadc_value();
EnableTrimbuffer(false);
setOffsetTrimMux(AUDIO_OFFSET_TRIM_MUX_GROUND);
open_trim_bufferhardware_withspk(false, true);
/* get buffer off auxadc value */
open_trim_bufferhardware_withspk(true, false);
setOffsetTrimMux(channel);
setOffsetTrimBufferGain(3); /* 18db */
EnableTrimbuffer(true);
usleep_range(1*1000, 10*1000);
for (i = 0; i < TRIM_TIMES; i++)
off_value[i] = audio_get_auxadc_value();
EnableTrimbuffer(false);
setOffsetTrimMux(AUDIO_OFFSET_TRIM_MUX_GROUND);
open_trim_bufferhardware_withspk(false, false);
offset = calculate_trimmed_mean_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
#endif
return 0;
}
#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)
void set_anaoffset_value(struct ana_trim_offset *offset, int trimcodel,
int trimcoder, int finetriml, int finetrimr)
{
offset->hpl_trimecode = trimcodel;
offset->hpl_finetrim = finetriml;
offset->hpr_trimecode = trimcoder;
offset->hpr_finetrim = finetrimr;
}
unsigned int get_anaoffset_value(struct ana_trim_offset *offset)
{
unsigned int ret = (offset->hpr_finetrim << HPFINETRIM_R_SHIFT) |
(offset->hpl_finetrim << HPFINETRIM_L_SHIFT) |
(offset->hpr_trimecode << HPTRIM_R_SHIFT) |
(offset->hpl_trimecode << HPTRIM_L_SHIFT);
return ret;
}
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_3 = 0, hpr_finetrim_3 = 0;
int trimcode[2] = { 0, 0 };
int finetrim[2] = { 0, 0 };
int trimcodel_ceiling = 0, trimcoder_ceiling = 0;
int trimcodel_floor = 0, trimcoder_floor = 0;
int tmp = 0;
bool code_change = false;
pr_debug("%s(), Start DCtrim Calibrating\n", __func__);
/* clear AUDDEC_ELR_0 setting */
Ana_Set_Reg(AUDDEC_ELR_0, 0x0, 0xffff);
/* enable AUDDEC_ELR_0 */
Ana_Set_Reg(AUDDEC_ELR_0, 0x1 << HPTRIM_EN_SHIFT, HPTRIM_EN_MASK);
get_hp_trim_offset();
hpl_base = hpl_dc_offset;
hpr_base = hpr_dc_offset;
/* Step1: get trim code */
if (hpl_base == 0 && hpr_base == 0)
goto EXIT;
if (hpl_base > 0) {
Ana_Set_Reg(AUDDEC_ELR_0,
0x2 << HPTRIM_L_SHIFT, HPTRIM_L_MASK);
code_change = true;
} else 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,
0x2 << HPTRIM_R_SHIFT, HPTRIM_R_MASK);
code_change = true;
} else if (hpr_base < 0) {
Ana_Set_Reg(AUDDEC_ELR_0,
0xa << HPTRIM_R_SHIFT, HPTRIM_R_MASK);
code_change = true;
}
if (code_change) {
usleep_range(10*1000, 15*1000);
get_hp_trim_offset();
code_change = false;
hpl_min = hpl_dc_offset;
hpr_min = hpr_dc_offset;
/* 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;
} else 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));
trimcoder_ceiling = trimcoder_floor + 1;
} else 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 = hpl_dc_offset;
hpr_floor = hpr_dc_offset;
/* 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 = hpl_dc_offset;
hpr_ceiling = hpr_dc_offset;
/* Choose the best & update DC offset */
if (abs(hpl_ceiling) < abs(hpl_floor)) {
hpl_base = hpl_ceiling;
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] = trimcodel_ceiling;
} else {
hpl_base = hpl_floor;
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] = trimcodel_floor;
}
if (abs(hpr_ceiling) < abs(hpr_floor)) {
hpr_base = hpr_ceiling;
trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] = trimcoder_ceiling;
} else {
hpr_base = hpr_floor;
trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] = trimcoder_floor;
}
/* Step2: Trim code refine +1/0/-1 */
usleep_range(10*1000, 15*1000);
if (hpl_base == 0 && hpr_base == 0)
goto EXIT;
if ((hpl_base > 0) &&
(trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] != 0x7) &&
(trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] != 0x8)) {
tmp = trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] +
((trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] > 7) ? -1 : 1);
Ana_Set_Reg(AUDDEC_ELR_0,
tmp << HPTRIM_L_SHIFT, HPTRIM_L_MASK);
code_change = true;
} else if ((hpl_base < 0) &&
(trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] != 0) &&
(trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] != 0xf)) {
tmp = trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] -
((trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] > 7) ? -1 : 1);
Ana_Set_Reg(AUDDEC_ELR_0,
tmp << HPTRIM_L_SHIFT, HPTRIM_L_MASK);
code_change = true;
}
if ((hpr_base > 0) &&
(trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] != 0x7) &&
(trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] != 0x8)) {
tmp = trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] +
((trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] > 7) ? -1 : 1);
Ana_Set_Reg(AUDDEC_ELR_0,
tmp << HPTRIM_R_SHIFT, HPTRIM_R_MASK);
code_change = true;
} else if ((hpr_base < 0) &&
(trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] != 0) &&
(trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] != 0xf)) {
tmp = trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] -
((trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] > 7) ? -1 : 1);
Ana_Set_Reg(AUDDEC_ELR_0,
tmp << HPTRIM_R_SHIFT, HPTRIM_R_MASK);
code_change = true;
}
if (code_change) {
usleep_range(10*1000, 15*1000);
get_hp_trim_offset();
code_change = false;
hpl_min = hpl_dc_offset;
hpr_min = hpr_dc_offset;
if (hpl_base > 0 &&
(hpl_min >= 0 || abs(hpl_min) < abs(hpl_base))) {
if ((trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] != 0x7) &&
(trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] != 0x8)) {
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] =
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] +
((trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] > 7) ?
-1 : 1);
} else
pr_debug("%s(), [Step2][L>0, bit-overflow!!], don't refine, trimcodel = %d\n",
__func__,
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1]);
} else if (hpl_base < 0 &&
(hpl_min <= 0 || abs(hpl_min) < abs(hpl_base))) {
if ((trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] != 0) &&
(trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] != 0xf)) {
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] =
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] -
((trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] > 7) ?
-1 : 1);
} else {
pr_debug("%s(), [Step2][L<0, bit-overflow!!], don't refine, trimcodel = %d\n",
__func__,
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1]);
}
}
if (hpr_base > 0 &&
(hpr_min >= 0 || abs(hpr_min) < abs(hpr_base))) {
if ((trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] != 0x7) &&
(trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] != 0x8)) {
trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] =
trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] +
((trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] > 7) ?
-1 : 1);
} else {
pr_debug("%s(), [Step2][R>0, bit-overflow!!], don't refine, trimcoder = %d\n",
__func__,
trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1]);
}
} else if (hpr_base < 0 &&
(hpr_min <= 0 || abs(hpr_min) < abs(hpr_base))) {
if ((trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] != 0) &&
(trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] != 0xf)) {
trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] =
trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] -
((trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] > 7) ?
-1 : 1);
} else {
pr_debug("%s(), [Step2][R<0, bit-overflow!!], don't refine, trimcoder = %d\n",
__func__,
trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1]);
}
}
}
/* channel L */
Ana_Set_Reg(AUDDEC_ELR_0,
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] << HPTRIM_L_SHIFT,
HPTRIM_L_MASK);
/* channel R */
Ana_Set_Reg(AUDDEC_ELR_0,
trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] << HPTRIM_R_SHIFT,
HPTRIM_R_MASK);
/* Step3: Trim code fine tune */
usleep_range(10*1000, 15*1000);
get_hp_trim_offset();
hpl_base = hpl_dc_offset;
hpr_base = hpr_dc_offset;
if (hpl_base == 0 && hpr_base == 0)
goto EXIT;
if (hpl_base > 0) {
/* channel L */
Ana_Set_Reg(AUDDEC_ELR_0, 0x1 << HPFINETRIM_L_SHIFT,
HPFINETRIM_L_MASK);
code_change = true;
} else if (hpl_base < 0) {
/* channel L */
Ana_Set_Reg(AUDDEC_ELR_0, 0x2 << HPFINETRIM_L_SHIFT,
HPFINETRIM_L_MASK);
code_change = true;
}
if (hpr_base > 0) {
/* channel R */
Ana_Set_Reg(AUDDEC_ELR_0, 0x1 << HPFINETRIM_R_SHIFT,
HPFINETRIM_R_MASK);
code_change = true;
} else if (hpr_base < 0) {
/* channel R */
Ana_Set_Reg(AUDDEC_ELR_0, 0x2 << HPFINETRIM_R_SHIFT,
HPFINETRIM_R_MASK);
code_change = true;
}
if (code_change) {
usleep_range(10*1000, 15*1000);
get_hp_trim_offset();
code_change = false;
hpl_min = hpl_dc_offset;
hpr_min = hpr_dc_offset;
if (hpl_base > 0 || hpr_base > 0) {
Ana_Set_Reg(AUDDEC_ELR_0, 0x3 << HPFINETRIM_L_SHIFT,
HPFINETRIM_L_MASK);
Ana_Set_Reg(AUDDEC_ELR_0, 0x3 << HPFINETRIM_R_SHIFT,
HPFINETRIM_R_MASK);
usleep_range(10*1000, 15*1000);
get_hp_trim_offset();
code_change = false;
hpl_finetrim_3 = hpl_dc_offset;
hpr_finetrim_3 = hpr_dc_offset;
}
/* channel L */
Ana_Set_Reg(AUDDEC_ELR_0, 0x0 << HPFINETRIM_L_SHIFT,
HPFINETRIM_L_MASK);
/* channel R*/
Ana_Set_Reg(AUDDEC_ELR_0, 0x0 << HPFINETRIM_R_SHIFT,
HPFINETRIM_R_MASK);
if (hpl_base > 0) {
/* Choose base, finetrim=1, and finetrim=3 */
finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] =
pick_hp_finetrim(hpl_base,
hpl_min,
hpl_finetrim_3);
pr_debug("%s(), [Step3] refine finetriml = %d\n",
__func__,
finetrim[AUDIO_ANALOG_CHANNELS_LEFT1]);
}
if (hpr_base > 0) {
/* Choose base, finetrim=1, and finetrim=3 */
finetrim[AUDIO_ANALOG_CHANNELS_RIGHT1] =
pick_hp_finetrim(hpr_base,
hpr_min,
hpr_finetrim_3);
pr_debug("%s(), [Step3] refine finetrimr = %d\n",
__func__,
finetrim[AUDIO_ANALOG_CHANNELS_RIGHT1]);
}
if (hpl_base < 0 && hpl_min >= 0 &&
(abs(hpl_min) < abs(hpl_base)))
finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] = 0x2;
if (hpr_base < 0 && hpr_min >= 0 &&
(abs(hpr_min) < abs(hpr_base)))
finetrim[AUDIO_ANALOG_CHANNELS_RIGHT1] = 0x2;
}
/* channel L */
Ana_Set_Reg(AUDDEC_ELR_0,
finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] <<
HPFINETRIM_L_SHIFT, HPFINETRIM_L_MASK);
Ana_Set_Reg(AUDDEC_ELR_0,
finetrim[AUDIO_ANALOG_CHANNELS_RIGHT1] <<
HPFINETRIM_R_SHIFT, HPFINETRIM_R_MASK);
/* 4 pole fine trim */
usleep_range(10*1000, 15*1000);
get_hp_trim_offset();
hpl_base = hpl_dc_offset;
hpr_base = hpr_dc_offset;
EXIT:
/* check trimcode is valid */
if ((trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] < 0 ||
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] > 0xf) ||
(finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] < 0 ||
finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] > 0x3) ||
(trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] < 0 ||
trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] > 0xf) ||
(finetrim[AUDIO_ANALOG_CHANNELS_RIGHT1] < 0 ||
finetrim[AUDIO_ANALOG_CHANNELS_RIGHT1] > 0x3))
pr_info("%s(), [Warning], invalid trimcode/finetrime (3pole)\n",
__func__);
set_anaoffset_value(&hp_3pole_anaoffset,
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1],
trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1],
finetrim[AUDIO_ANALOG_CHANNELS_LEFT1],
finetrim[AUDIO_ANALOG_CHANNELS_RIGHT1]);
if ((hpl_base < 0) &&
(finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] == 0x0)) {
finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] = 0x2;
} else if ((hpl_base < 0) &&
(finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] == 0x2)) {
finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] = 0x0;
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] =
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] -
((trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] > 7) ? -1 : 1);
}
if ((hpr_base < 0) &&
(finetrim[AUDIO_ANALOG_CHANNELS_RIGHT1] == 0x0)) {
finetrim[AUDIO_ANALOG_CHANNELS_RIGHT1] = 0x2;
} else if ((hpr_base < 0) &&
(finetrim[AUDIO_ANALOG_CHANNELS_RIGHT1] == 0x2)) {
finetrim[AUDIO_ANALOG_CHANNELS_RIGHT1] = 0x0;
trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] =
trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] -
((trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] > 7) ?
-1 : 1);
}
/* check trimcode is valid */
if ((trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] < 0 ||
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] > 0xf) ||
(finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] < 0 ||
finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] > 0x3) ||
(trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] < 0 ||
trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1] > 0xf) ||
(finetrim[AUDIO_ANALOG_CHANNELS_RIGHT1] < 0 ||
finetrim[AUDIO_ANALOG_CHANNELS_RIGHT1] > 0x3))
pr_info("%s(), [Warning], invalid trimcode/finetrime (4pole)\n",
__func__);
set_anaoffset_value(&hp_4pole_anaoffset,
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1],
trimcode[AUDIO_ANALOG_CHANNELS_RIGHT1],
finetrim[AUDIO_ANALOG_CHANNELS_LEFT1],
finetrim[AUDIO_ANALOG_CHANNELS_RIGHT1]);
pr_debug("%s(), Result AUDDEC_ELR_0 = 0x%x hp_3pole_anaoffset= 0x%x hp_4pole_anaoffset= 0x%x get_offset %d /t %d\n",
__func__, Ana_Get_Reg(AUDDEC_ELR_0),
get_anaoffset_value(&hp_3pole_anaoffset),
get_anaoffset_value(&hp_4pole_anaoffset),
hpl_dc_offset, hpr_dc_offset);
/* clear AUDDEC_ELR_0 setting */
Ana_Set_Reg(AUDDEC_ELR_0, 0x0, 0xffff);
}
static void set_l_trim_code_spk(void)
{
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[2] = { 0, 0 };
int finetrim[2] = { 0, 0 };
int trimcode_ceiling = 0;
int trimcode_floor = 0;
int trimcode_tmp = 0;
pr_debug("%s(), Start SPK DCtrim Calibrating\n", __func__);
Ana_Set_Reg(AUDDEC_ELR_0, 0x0, 0xffff);
Ana_Set_Reg(AUDDEC_ELR_0, 0x0 << HPFINETRIM_L_SHIFT,
HPFINETRIM_L_MASK);
Ana_Set_Reg(AUDDEC_ELR_0,
hp_3pole_anaoffset.hpr_trimecode << HPTRIM_R_SHIFT,
HPTRIM_R_MASK);
Ana_Set_Reg(AUDDEC_ELR_0,
hp_3pole_anaoffset.hpr_finetrim << HPFINETRIM_R_SHIFT,
HPFINETRIM_R_MASK);
Ana_Set_Reg(AUDDEC_ELR_0, 0x1 << HPTRIM_EN_SHIFT, HPTRIM_EN_MASK);
/* Step1: get trim code */
usleep_range(10*1000, 15*1000);
hpl_base = get_spk_trim_offset(AUDIO_OFFSET_TRIM_MUX_HPL);
if (hpl_base == 0)
goto EXIT;
if (hpl_base > 0) {
Ana_Set_Reg(AUDDEC_ELR_0,
0x2 << HPTRIM_L_SHIFT, HPTRIM_L_MASK);
usleep_range(10*1000, 15*1000);
hpl_min = get_spk_trim_offset(AUDIO_OFFSET_TRIM_MUX_HPL);
/* 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 << HPTRIM_L_SHIFT, HPTRIM_L_MASK);
usleep_range(10*1000, 15*1000);
hpl_min = get_spk_trim_offset(AUDIO_OFFSET_TRIM_MUX_HPL);
/* 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 << HPTRIM_L_SHIFT, HPTRIM_L_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(AUDIO_OFFSET_TRIM_MUX_HPL);
usleep_range(10*1000, 15*1000);
/* Get ceiling trim code */
Ana_Set_Reg(AUDDEC_ELR_0,
trimcode_ceiling << HPTRIM_L_SHIFT, HPTRIM_L_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(AUDIO_OFFSET_TRIM_MUX_HPL);
usleep_range(10*1000, 15*1000);
/* Choose the best */
if (abs(hpl_ceiling) < abs(hpl_floor)) {
hpl_base = hpl_ceiling;
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] = trimcode_ceiling;
} else {
hpl_base = hpl_floor;
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] = trimcode_floor;
}
Ana_Set_Reg(AUDDEC_ELR_0,
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] << HPTRIM_L_SHIFT,
HPTRIM_L_MASK);
/* Step2: Trim code refine +1/0/-1 */
usleep_range(10*1000, 15*1000);
hpl_base = get_spk_trim_offset(AUDIO_OFFSET_TRIM_MUX_HPL);
if (hpl_base == 0)
goto EXIT;
if (hpl_base > 0) {
if ((trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] != 0x7) &&
(trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] != 0x8)) {
trimcode_tmp =
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] +
((trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] > 7) ? -1 : 1);
Ana_Set_Reg(AUDDEC_ELR_0,
trimcode_tmp << HPTRIM_L_SHIFT,
HPTRIM_L_MASK);
usleep_range(10*1000, 15*1000);
hpl_min =
get_spk_trim_offset(AUDIO_OFFSET_TRIM_MUX_HPL);
if (hpl_min >= 0 || abs(hpl_min) < abs(hpl_base)) {
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] =
trimcode_tmp;
hpl_base = hpl_min;
}
}
} else {
if ((trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] != 0) &&
(trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] != 0xf)) {
trimcode_tmp =
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] -
((trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] > 7) ?
-1 : 1);
Ana_Set_Reg(AUDDEC_ELR_0,
trimcode_tmp << HPTRIM_L_SHIFT,
HPTRIM_L_MASK);
usleep_range(10*1000, 15*1000);
hpl_min =
get_spk_trim_offset(AUDIO_OFFSET_TRIM_MUX_HPL);
if (hpl_min <= 0 || abs(hpl_min) < abs(hpl_base)) {
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] =
trimcode_tmp;
hpl_base = hpl_min;
}
}
}
Ana_Set_Reg(AUDDEC_ELR_0,
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] << HPTRIM_L_SHIFT,
HPTRIM_L_MASK);
/* Step3: Trim code fine tune */
if (hpl_base == 0)
goto EXIT;
if (hpl_base > 0) {
Ana_Set_Reg(AUDDEC_ELR_0,
0x1 << HPFINETRIM_L_SHIFT, HPFINETRIM_L_MASK);
usleep_range(10*1000, 15*1000);
hpl_min = get_spk_trim_offset(AUDIO_OFFSET_TRIM_MUX_HPL);
if (hpl_min >= 0 || abs(hpl_min) < abs(hpl_base)) {
finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] = 0x1;
hpl_base = hpl_min;
} else {
Ana_Set_Reg(AUDDEC_ELR_0,
0x3 << HPFINETRIM_L_SHIFT,
HPFINETRIM_L_MASK);
usleep_range(10*1000, 15*1000);
hpl_min =
get_spk_trim_offset(AUDIO_OFFSET_TRIM_MUX_HPL);
if (hpl_min >= 0 && abs(hpl_min) < abs(hpl_base)) {
finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] = 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 << HPFINETRIM_L_SHIFT, HPFINETRIM_L_MASK);
usleep_range(10*1000, 15*1000);
hpl_finetrim_2 = get_spk_trim_offset(AUDIO_OFFSET_TRIM_MUX_HPL);
if (hpl_finetrim_2 <= 0 ||
abs(hpl_finetrim_2) < abs(hpl_base)) {
finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] = 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 << HPFINETRIM_L_SHIFT,
HPFINETRIM_L_MASK);
usleep_range(10*1000, 15*1000);
hpl_finetrim_3 =
get_spk_trim_offset(AUDIO_OFFSET_TRIM_MUX_HPL);
finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] =
pick_spk_finetrim(hpl_base,
hpl_finetrim_2,
hpl_finetrim_3);
if (finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] == 0x2)
hpl_base = hpl_finetrim_2;
else if (finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] == 0x3)
hpl_base = hpl_finetrim_3;
}
}
Ana_Set_Reg(AUDDEC_ELR_0,
finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] << HPFINETRIM_L_SHIFT,
HPFINETRIM_L_MASK);
/* 4 pole fine trim */
usleep_range(10*1000, 15*1000);
hpl_base = get_spk_trim_offset(AUDIO_OFFSET_TRIM_MUX_HPL);
spkl_dc_offset = hpl_base;
EXIT:
/* check trimcode is valid */
if ((trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] < 0 ||
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] > 0xf) ||
(finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] < 0 ||
finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] > 0x3))
pr_info("%s(), [Warning], invalid trimcode/finetrime (3pole)\n",
__func__);
set_anaoffset_value(&hp_3pole_anaoffset,
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1],
hp_3pole_anaoffset.hpr_trimecode,
finetrim[AUDIO_ANALOG_CHANNELS_LEFT1],
hp_3pole_anaoffset.hpr_finetrim);
if ((hpl_base < 0) &&
(finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] == 0x0)) {
finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] = 0x2;
} else if ((hpl_base < 0) &&
(finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] == 0x2)) {
finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] = 0x0;
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] =
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] -
((trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] > 7) ? -1 : 1);
}
/* check trimcode is valid */
if ((trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] < 0 ||
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1] > 0xf) ||
(finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] < 0 ||
finetrim[AUDIO_ANALOG_CHANNELS_LEFT1] > 0x3))
pr_info("%s(), [Warning], invalid trimcode/finetrime (4pole)\n",
__func__);
set_anaoffset_value(&spk_4pole_anaoffset,
trimcode[AUDIO_ANALOG_CHANNELS_LEFT1],
hp_4pole_anaoffset.hpr_trimecode,
finetrim[AUDIO_ANALOG_CHANNELS_LEFT1],
hp_4pole_anaoffset.hpr_finetrim);
pr_debug("%s(), Result AUDDEC_ELR_0 = 0x%x spk_3pole_anaoffset= 0x%x spk_4pole_anaoffset= 0x%x get_offset %d /t %d\n",
__func__, Ana_Get_Reg(AUDDEC_ELR_0),
get_anaoffset_value(&spk_3pole_anaoffset),
get_anaoffset_value(&spk_4pole_anaoffset),
spkl_dc_offset, hpr_dc_offset);
/* clear AUDDEC_ELR_0 setting */
Ana_Set_Reg(AUDDEC_ELR_0, 0x0, 0xffff);
}
#endif
static void get_hp_lr_trim_offset(void)
{
#ifdef ANALOG_HPTRIM
set_lr_trim_code();
if (mtk_spk_get_type() == 0)
set_l_trim_code_spk();
#else
get_hp_trim_offset();
if (mtk_spk_get_type() == 0)
spkl_dc_offset = get_spk_trim_offset(AUDIO_OFFSET_TRIM_MUX_HPL);
else
spkl_dc_offset = 0;
#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) {
/* pr_debug("%s set up SNDRV_PCM_STREAM_CAPTURE rate = %d\n",
* __func__, substream->runtime->rate);
*/
mBlockSampleRate[AUDIO_ANALOG_DEVICE_IN_ADC] =
substream->runtime->rate;
} else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
/* pr_debug("%s set up SNDRV_PCM_STREAM_PLAYBACK rate = %d\n",
* __func__, substream->runtime->rate);
*/
mBlockSampleRate[AUDIO_ANALOG_DEVICE_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_6357_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__);
audckbufEnable(true);
/* gpio mosi mode */
set_playback_gpio(true);
/* Enable HP main CMFB Switch */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0280, 0x0fff);
/* Pull-down HPL/R, HS, LO to AVSS28_AUD */
Ana_Set_Reg(AUDDEC_ANA_CON7, 0x00a8, 0xffff);
switch (device) {
case AUDIO_ANALOG_DEVICE_OUT_EARPIECEL:
case AUDIO_ANALOG_DEVICE_OUT_EARPIECER:
/* Release HS CMFB pull down */
Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0088, 0xffff);
break;
case AUDIO_ANALOG_DEVICE_OUT_SPEAKERL:
case AUDIO_ANALOG_DEVICE_OUT_SPEAKERR:
/* Release LO CMFB pull down */
Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0028, 0xffff);
break;
case AUDIO_ANALOG_DEVICE_OUT_SPEAKER_HEADSET_L:
case AUDIO_ANALOG_DEVICE_OUT_SPEAKER_HEADSET_R:
/* Dsiable HP main CMFB Switch */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0000, 0x0fff);
/* Release HP CMFB pull down */
Ana_Set_Reg(AUDDEC_ANA_CON7, 0x00A0, 0x0fff);
/* Release LO CMFB pull down */
Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0020, 0x0fff);
break;
case AUDIO_ANALOG_DEVICE_OUT_HEADSETL:
case AUDIO_ANALOG_DEVICE_OUT_HEADSETR:
default:
/* Dsiable HP main CMFB Switch */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0000, 0x0fff);
/* Release HP CMFB pull down */
Ana_Set_Reg(AUDDEC_ANA_CON7, 0x00a0, 0x0fff);
break;
};
NvregEnable(true); /* Enable AUDGLB */
/* Pull-down HPL/R to AVSS28_AUD */
if (!always_pull_down_enable)
hp_pull_down(true);
ClsqEnable(true); /* Turn on 26MHz source clock */
Topck_Enable(true); /* Turn on AUDNCP_CLKDIV engine clock */
/* Turn on AUD 26M */
udelay(250);
Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x0000, 0x00c4);
udelay(250);
/* Audio system digital clock power down release */
Ana_Set_Reg(AFUNC_AUD_CON2, 0x0006, 0xffff);
/* sdm audio fifo clock power on */
Ana_Set_Reg(AFUNC_AUD_CON0, 0xCBA1, 0xffff);
/* scrambler clock on enable */
Ana_Set_Reg(AFUNC_AUD_CON2, 0x0003, 0xffff);
/* sdm power on */
Ana_Set_Reg(AFUNC_AUD_CON2, 0x000B, 0xffff);
/* sdm fifo enable */
/* afe enable */
Ana_Set_Reg(AFE_UL_DL_CON0, 0x0001, 0x0001);
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) {
/* turn off afe */
Ana_Set_Reg(AFE_UL_DL_CON0, 0x0000, 0x0001);
/* all power down */
Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x00df, 0x00df);
} else {
/* down-link power down */
Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x0040, 0x0040);
}
/* disable aud_pad RX fifos */
Ana_Set_Reg(AFE_AUD_PAD_TOP, 0x0000, 0x00ff);
udelay(250);
set_playback_gpio(false);
Topck_Enable(false);
ClsqEnable(false);
/* disable Pull-down HPL/R to AVSS28_AUD */
if (!always_pull_down_enable)
hp_pull_down(false);
NvregEnable(false);
audckbufEnable(false);
}
static void setDlMtkifSrc(bool enable)
{
pr_debug("%s(), enable = %d, freq = %d\n",
__func__,
enable,
mBlockSampleRate[AUDIO_ANALOG_DEVICE_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->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_HEADSETL],
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_HEADSETR]);
if (enable) {
mic_vinp_mv = get_accdet_auxadc();
#ifdef ANALOG_HPTRIM
if (mic_vinp_mv > MIC_VINP_4POLE_THRES_MV &&
((codec_debug_enable & DBG_DCTRIM_BYPASS_4POLE) == 0)) {
Ana_Set_Reg(AUDDEC_ELR_0, 0x1 << 12
| get_anaoffset_value(&hp_4pole_anaoffset),
0xffff);
} else {
Ana_Set_Reg(AUDDEC_ELR_0, 0x1 << 12
| get_anaoffset_value(&hp_3pole_anaoffset),
0xffff);
}
/* pr_debug("%s(), mic_vinp_mv %d ana_offset 0x%x\n",
* __func__, mic_vinp_mv, Ana_Get_Reg(AUDDEC_ELR_0));
*/
#endif
if (GetDLStatus() == false)
TurnOnDacPower(AUDIO_ANALOG_DEVICE_OUT_HEADSETL);
/* here pmic analog control */
if (mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_HEADSETL] == false &&
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_HEADSETR] == false) {
/* switch to ground to de pop-noise */
/*HP_Switch_to_Ground();*/
/* Disable headphone short-circuit protection */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x3000, 0xffff);
/* Disable handset short-circuit protection */
Ana_Set_Reg(AUDDEC_ANA_CON3, 0x0010, 0xffff);
/* Disable linout short-circuit protection */
Ana_Set_Reg(AUDDEC_ANA_CON4, 0x0010, 0xffff);
/* Reduce ESD resistance of AU_REFN */
Ana_Set_Reg(AUDDEC_ANA_CON2, 0x200, 0x200);
/* Set HPR/HPL gain as minimum (~ -40dB) */
Ana_Set_Reg(ZCD_CON2, DL_GAIN_N_40DB_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) */
Ana_Set_Reg(AUDDEC_ANA_CON12, 0x1055, 0x1055);
/* Enable NV regulator (-1.2V) */
Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0001, 0xffff);
udelay(100);
/* Enable AUD_ZCD */
Zcd_Enable(true, AUDIO_ANALOG_DEVICE_OUT_HEADSETL);
/* Enable IBIST */
Ana_Set_Reg(AUDDEC_ANA_CON10, 0x0055, 0xffff);
/* Set HP DR bias current optimization, 010: 6uA */
Ana_Set_Reg(AUDDEC_ANA_CON9, 0x92, 0xffff);
/* Set HP & ZCD bias current optimization */
/* 01: ZCD: 4uA, HP/HS/LO: 5uA */
Ana_Set_Reg(AUDDEC_ANA_CON10, 0x0055, 0xffff);
/* Set HPP/N STB enhance circuits */
Ana_Set_Reg(AUDDEC_ANA_CON2, 0x0033, 0x00ff);
/* 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_CON6, 0x0c80, 0x0fff);
/* 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_CON6, 0x0e80, 0x0fff);
/* Disable HP aux CMFB loop */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0280, 0x0fff);
/* Enable HP main output stage */
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x00ff, 0xffff);
/* Enable HPR/L main output stage step by step */
hp_main_output_ramp(true);
udelay(1000);
/* Reduce HP aux feedback loop gain */
hp_aux_feedback_loop_gain_ramp(true);
/* Disable HP aux feedback loop */
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x77cf, 0xffff);
/* apply volume setting */
headset_volume_ramp(DL_GAIN_N_40DB,
mCodec_data->mAudio_Ana_Volume
[AUDIO_ANALOG_VOLUME_HPOUTL]);
/* Disable HP aux output stage */
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x77c3, 0xffff);
/* Unshort HP main output to HP aux output stage */
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x7703, 0xffff);
udelay(100);
/* Enable AUD_CLK */
Ana_Set_Reg(AUDDEC_ANA_CON11, 0x1, 0x1);
/* Enable Audio DAC */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x30ff, 0xffff);
/* Enable low-noise mode of DAC */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0xf281, 0x0fff);
udelay(100);
/* Switch HPL MUX to audio DAC */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x32ff, 0xffff);
/* Switch HPR MUX to audio DAC */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x3aff, 0xffff);
#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->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_HEADSETL] == false &&
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_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_CON6, 0x0000, 0x0001);
/* Disable Audio DAC */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0000, 0x000f);
/* Disable AUD_CLK */
Ana_Set_Reg(AUDDEC_ANA_CON11, 0x0, 0x1);
/* Short HP main output to HP aux output stage */
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x77c3, 0xffff);
/* Enable HP aux output stage */
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x77cf, 0xffff);
/* decrease HPL/R gain to normal gain step by step */
headset_volume_ramp(mCodec_data->mAudio_Ana_Volume
[AUDIO_ANALOG_VOLUME_HPOUTL],
DL_GAIN_N_40DB);
/* Enable HP aux feedback loop */
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x77ff, 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_CON6, 0x0e00, 0x0fff);
/* Disable HP main CMFB loop */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0c00, 0x0fff);
/* 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,
* Enable HP main CMFB for HP off state
*/
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0200, 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, 0x3 << 2);
/* Pull-down HPL/R, HS, LO to AVSS28_AUD */
Ana_Set_Reg(AUDDEC_ANA_CON7, 0xa8, 0xff);
/* Disable IBIST */
Ana_Set_Reg(AUDDEC_ANA_CON10, 0x1 << 8, 0x1 << 8);
/* Disable AUD_ZCD */
Zcd_Enable(false, AUDIO_ANALOG_DEVICE_OUT_HEADSETL);
/* Disable NV regulator (-1.2V) */
Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0, 0x1);
/* Disable cap-less LDOs (1.5V) */
Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0, 0x1055);
if (always_pull_low_off) {
/* Reset HPP/N STB enhance circuits */
Ana_Set_Reg(AUDDEC_ANA_CON2, 0x0, 0xff);
}
/* Disable NCP */
Ana_Set_Reg(AUDNCP_CLKDIV_CON3, 0x1, 0x1);
if (GetDLStatus() == false)
TurnOffDacPower();
}
}
}
static int Audio_AmpL_Get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* pr_debug("Audio_AmpL_Get = %d\n",
* mCodec_data->mAudio_Ana_DevicePower
* [AUDIO_ANALOG_DEVICE_OUT_HEADSETL]);
*/
ucontrol->value.integer.value[0] =
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_HEADSETL];
return 0;
}
static int Audio_AmpL_Set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
mutex_lock(&Ana_Power_Mutex);
/* pr_debug("%s(): enable = %ld,
* mAudio_Ana_DevicePower[AUDIO_ANALOG_DEVICE_OUT_HEADSETL] = %d\n",
* __func__, ucontrol->value.integer.value[0],
* mCodec_data->mAudio_Ana_DevicePower
* [AUDIO_ANALOG_DEVICE_OUT_HEADSETL]);
*/
if ((ucontrol->value.integer.value[0] == true)
&& (mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_HEADSETL] == false)) {
Audio_Amp_Change(AUDIO_ANALOG_CHANNELS_LEFT1, true);
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_HEADSETL] =
ucontrol->value.integer.value[0];
} else if ((ucontrol->value.integer.value[0] == false)
&& (mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_HEADSETL] == true)) {
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_HEADSETL] =
ucontrol->value.integer.value[0];
Audio_Amp_Change(AUDIO_ANALOG_CHANNELS_LEFT1, false);
}
mutex_unlock(&Ana_Power_Mutex);
return 0;
}
static int Audio_AmpR_Get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* pr_debug("Audio_AmpR_Get = %d\n",
* mCodec_data->mAudio_Ana_DevicePower
* [AUDIO_ANALOG_DEVICE_OUT_HEADSETR]);
*/
ucontrol->value.integer.value[0] =
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_HEADSETR];
return 0;
}
static int Audio_AmpR_Set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
mutex_lock(&Ana_Power_Mutex);
/* pr_debug("%s(): enable = %ld,
* mAudio_Ana_DevicePower[HEADSETR] = %d\n", __func__,
* ucontrol->value.integer.value[0],
* mCodec_data->mAudio_Ana_DevicePower
* [AUDIO_ANALOG_DEVICE_OUT_HEADSETR]);
*/
if ((ucontrol->value.integer.value[0] == true) &&
(mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_HEADSETR] == false)) {
Audio_Amp_Change(AUDIO_ANALOG_CHANNELS_RIGHT1, true);
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_HEADSETR] =
ucontrol->value.integer.value[0];
} else if ((ucontrol->value.integer.value[0] == false) &&
(mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_HEADSETR] == true)) {
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_HEADSETR] =
ucontrol->value.integer.value[0];
Audio_Amp_Change(AUDIO_ANALOG_CHANNELS_RIGHT1, false);
}
mutex_unlock(&Ana_Power_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 */
/* dcxo */
Ana_Set_Reg(DCXO_CW14, 0x1 << 13, 0x1 << 13);
/* gpio mosi mode */
set_playback_gpio(true);
/* Enable HP main CMFB Switch */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0200, 0x0fff);
/* Pull-down HPL/R, HS, LO to AVSS28_AUD */
Ana_Set_Reg(AUDDEC_ANA_CON7, 0x00a8, 0xffff);
/* Release HS CMFB pull down */
Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0088, 0xffff);
/* Enable AUDGLB */
Ana_Set_Reg(AUDDEC_ANA_CON11, 0x0000, 0xffff);
/* Pull-down HPL/R to AVSS28_AUD */
if (!always_pull_down_enable)
hp_pull_down(true);
Ana_Set_Reg(AUDENC_ANA_CON6, 0x0000, 0x0001);
/* Turn on AUDNCP_CLKDIV engine clock */
Ana_Set_Reg(AUD_TOP_CKPDN_CON0, 0x0, 0x66);
udelay(250);
/* power on clock */
Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x8000, 0xBfff);
udelay(250);
/* enable aud_pad RX fifos */
Ana_Set_Reg(AFE_AUD_PAD_TOP, 0x0031, 0x00ff);
/* Audio system digital clock power down release */
Ana_Set_Reg(AFUNC_AUD_CON2, 0x0006, 0xffff);
/* sdm audio fifo clock power on */
Ana_Set_Reg(AFUNC_AUD_CON0, 0xCBA1, 0xffff);
/* scrambler clock on enable */
Ana_Set_Reg(AFUNC_AUD_CON2, 0x0003, 0xffff);
/* sdm power on */
Ana_Set_Reg(AFUNC_AUD_CON2, 0x000B, 0xffff);
/* sdm fifo enable */
/* afe enable */
Ana_Set_Reg(AFE_UL_DL_CON0, 0x0001, 0x0001);
setDlMtkifSrc(true);
/* Disable headphone short-circuit protection */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x3000, 0xffff);
/* Disable handset short-circuit protection */
Ana_Set_Reg(AUDDEC_ANA_CON3, 0x0010, 0xffff);
/* Disable linout short-circuit protection */
Ana_Set_Reg(AUDDEC_ANA_CON4, 0x0010, 0xffff);
/* Reduce ESD resistance of AU_REFN */
Ana_Set_Reg(AUDDEC_ANA_CON2, 0x600, 0xffff);
/* Set HS gain as minimum (~ -40dB) */
Ana_Set_Reg(ZCD_CON3, DL_GAIN_N_40DB, 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_CON12, 0x1055, 0x1055);
/* Enable NV regulator (-1.2V) */
Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0001, 0xffff);
udelay(100);
/* Disable AUD_ZCD */
Zcd_Enable(false, AUDIO_ANALOG_DEVICE_OUT_HEADSETL);
/* Enable IBIST */
Ana_Set_Reg(AUDDEC_ANA_CON10, 0x0055, 0xffff);
/* Set HP DR bias current optimization, 010: 6uA */
Ana_Set_Reg(AUDDEC_ANA_CON9, 0x92, 0xffff);
/* Set HP & ZCD bias current optimization */
/* 01: ZCD: 4uA, HP/HS/LO: 5uA */
Ana_Set_Reg(AUDDEC_ANA_CON10, 0x0055, 0xffff);
/* Set HS STB enhance circuits */
Ana_Set_Reg(AUDDEC_ANA_CON3, 0x0090, 0xffff);
/* Enable HS driver bias circuits */
Ana_Set_Reg(AUDDEC_ANA_CON3, 0x0092, 0xffff);
/* Enable HS driver core circuits */
Ana_Set_Reg(AUDDEC_ANA_CON3, 0x0093, 0xffff);
/* Set HS gain to 0dB */
Ana_Set_Reg(ZCD_CON3, DL_GAIN_0DB, 0xffff);
/* Enable AUD_CLK */
Ana_Set_Reg(AUDDEC_ANA_CON11, 0x1, 0x1);
/* Enable Audio DAC */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x3009, 0xffff);
/* Enable low-noise mode of DAC */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0201, 0x0fff);
/* Switch HS MUX to audio DAC */
Ana_Set_Reg(AUDDEC_ANA_CON3, 0x009b, 0xffff);
/* phone mic dcc */
/* set gpio miso mode */
set_capture_gpio(true);
/* gpio miso driving set to default 4mA, 0x8888 */
Ana_Set_Reg(DRV_CON3, 0x8888, 0xffff);
/* Enable audio ADC CLKGEN */
Ana_Set_Reg(AUDDEC_ANA_CON11, 0x1 << 5, 0x1 << 5);
/* ADC CLK from CLKGEN (13MHz) */
Ana_Set_Reg(AUDENC_ANA_CON3, 0x0000, 0xffff);
Ana_Set_Reg(AUDENC_ANA_CON6, 0x0001, 0x0001);
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 bias */
/* Enable MICBIAS0, MISBIAS0 = 1P9V */
Ana_Set_Reg(AUDENC_ANA_CON8, 0x0021, 0xffff);
/* Audio L preamplifier DCC precharge */
Ana_Set_Reg(AUDENC_ANA_CON0, 0x0004, 0xffff);
/* "ADC1", main_mic */
/* Audio L preamplifier input sel : AIN0. Enable audio L PGA */
Ana_Set_Reg(AUDENC_ANA_CON0, 0x0041, 0xf0ff);
/* Enable audio L PGA gain : 24dB */
Ana_Set_Reg(AUDENC_ANA_CON0, 0x4 << 8, 0x0700);
/* 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, 0x5041, 0xf000);
/* Audio R preamplifier DCC precharge */
Ana_Set_Reg(AUDENC_ANA_CON1, 0x0004, 0xffff);
/* ref mic */
/* Audio R preamplifier input sel : AIN2. Enable audio R PGA */
Ana_Set_Reg(AUDENC_ANA_CON1, 0x00c1, 0xf0ff);
/* Enable audio R PGA gain : 24dB */
Ana_Set_Reg(AUDENC_ANA_CON1, 0x4 << 8, 0x0700);
/* 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, 0x50c1, 0xf000);
/* Audio R preamplifier DCC precharge off */
Ana_Set_Reg(AUDENC_ANA_CON1, 0x0, 0x1 << 2);
/* Audio L preamplifier DCC precharge off */
Ana_Set_Reg(AUDENC_ANA_CON0, 0x0, 0x1 << 2);
/* here to set digital part */
/* power on clock */
Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x8000, 0xffff);
/* 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;
}
static void Voice_Amp_Change(bool enable)
{
if (enable) {
if (GetDLStatus() == false) {
TurnOnDacPower(AUDIO_ANALOG_DEVICE_OUT_EARPIECEL);
pr_debug("%s(), amp on\n", __func__);
/* Disable headphone short-circuit protection */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x3000, 0xffff);
/* Disable handset short-circuit protection */
Ana_Set_Reg(AUDDEC_ANA_CON3, 0x0010, 0xffff);
/* Disable linout short-circuit protection */
Ana_Set_Reg(AUDDEC_ANA_CON4, 0x0010, 0xffff);
/* Reduce ESD resistance of AU_REFN */
Ana_Set_Reg(AUDDEC_ANA_CON2, 0x200, 0x200);
/* Set HS gain as minimum (~ -40dB) */
Ana_Set_Reg(ZCD_CON3, DL_GAIN_N_40DB, 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_CON12, 0x1055, 0x1055);
/* Enable NV regulator (-1.2V) */
Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0001, 0xffff);
udelay(100);
/* Enable AUD_ZCD */
Zcd_Enable(true, AUDIO_ANALOG_DEVICE_OUT_EARPIECEL);
/* Enable IBIST */
Ana_Set_Reg(AUDDEC_ANA_CON10, 0x0055, 0xffff);
/* Set HP DR bias current optimization, 010: 6uA */
Ana_Set_Reg(AUDDEC_ANA_CON9, 0x92, 0xffff);
/* Set HP & ZCD bias current optimization */
/* 01: ZCD: 4uA, HP/HS/LO: 5uA */
Ana_Set_Reg(AUDDEC_ANA_CON10, 0x0055, 0xffff);
/* Set HS STB enhance circuits */
Ana_Set_Reg(AUDDEC_ANA_CON3, 0x0090, 0xffff);
/* Enable HS driver bias circuits */
Ana_Set_Reg(AUDDEC_ANA_CON3, 0x0092, 0xffff);
/* Enable HS driver core circuits */
Ana_Set_Reg(AUDDEC_ANA_CON3, 0x0093, 0xffff);
/* Set HS gain to normal gain step by step */
Ana_Set_Reg(ZCD_CON3,
mCodec_data->mAudio_Ana_Volume
[AUDIO_ANALOG_VOLUME_HSOUTL],
0xffff);
/* Enable AUD_CLK */
Ana_Set_Reg(AUDDEC_ANA_CON11, 0x1, 0x1);
/* Enable Audio DAC */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x3009, 0xffff);
/* Enable low-noise mode of DAC */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0281, 0xffff);
/* Switch HS MUX to audio DAC */
Ana_Set_Reg(AUDDEC_ANA_CON3, 0x009b, 0xffff);
/* disable Pull-down HPL/R to AVSS28_AUD */
hp_pull_down(false);
}
} else {
pr_debug("%s(), amp off\n", __func__);
/* HS mux to open */
Ana_Set_Reg(AUDDEC_ANA_CON3, 0x0000, 0x3 << 2);
if (GetDLStatus() == false) {
/* Pull-down HPL/R to AVSS28_AUD */
hp_pull_down(true);
/* Disable Audio DAC */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0000, 0x000f);
/* Disable AUD_CLK */
Ana_Set_Reg(AUDDEC_ANA_CON11, 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_CON3, 0x0, 0x1);
/* Disable HS driver bias circuits */
Ana_Set_Reg(AUDDEC_ANA_CON3, 0x0000, 0x1 << 1);
/* Disable HP aux CMFB loop */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0, 0xff << 8);
/* Enable HP main CMFB Switch */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x2 << 8, 0xff << 8);
/* Pull-down HPL/R, HS, LO to AVSS28_AUD */
Ana_Set_Reg(AUDDEC_ANA_CON7, 0xa8, 0xff);
/* Disable IBIST */
Ana_Set_Reg(AUDDEC_ANA_CON10, 0x1 << 8, 0x1 << 8);
/* Disable AUD_ZCD */
Zcd_Enable(false, AUDIO_ANALOG_DEVICE_OUT_EARPIECEL);
/* Disable NV regulator (-1.2V) */
Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0, 0x1);
/* Disable cap-less LDOs (1.5V) */
Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0, 0x1055);
/* Disable NCP */
Ana_Set_Reg(AUDNCP_CLKDIV_CON3, 0x1, 0x1);
TurnOffDacPower();
}
Ana_Set_Reg(AUDDEC_ANA_CON3, 0x0000, 0x1 << 2);
}
}
static int Voice_Amp_Get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* pr_debug("Voice_Amp_Get = %d\n",
* mCodec_data->mAudio_Ana_DevicePower
* [AUDIO_ANALOG_DEVICE_OUT_EARPIECEL]);
*/
ucontrol->value.integer.value[0] =
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_EARPIECEL];
return 0;
}
static int Voice_Amp_Set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
mutex_lock(&Ana_Power_Mutex);
pr_debug("%s()\n", __func__);
if ((ucontrol->value.integer.value[0] == true) &&
(mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_EARPIECEL] == false)) {
Voice_Amp_Change(true);
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_EARPIECEL] =
ucontrol->value.integer.value[0];
} else if ((ucontrol->value.integer.value[0] == false) &&
(mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_EARPIECEL] == true)) {
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_EARPIECEL] =
ucontrol->value.integer.value[0];
Voice_Amp_Change(false);
}
mutex_unlock(&Ana_Power_Mutex);
return 0;
}
static void Speaker_Amp_Change(bool enable)
{
if (enable) {
if (GetDLStatus() == false)
TurnOnDacPower(AUDIO_ANALOG_DEVICE_OUT_SPEAKERL);
pr_debug("%s(), enable %d\n", __func__, enable);
/* Disable headphone short-circuit protection */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x3000, 0xffff);
/* Disable handset short-circuit protection */
Ana_Set_Reg(AUDDEC_ANA_CON3, 0x0010, 0xffff);
/* Disable linout short-circuit protection */
Ana_Set_Reg(AUDDEC_ANA_CON4, 0x0010, 0xffff);
/* Reduce ESD resistance of AU_REFN */
Ana_Set_Reg(AUDDEC_ANA_CON2, 0x200, 0x200);
/* Set HS gain as minimum (~ -40dB) */
Ana_Set_Reg(ZCD_CON1, DL_GAIN_N_40DB_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) */
Ana_Set_Reg(AUDDEC_ANA_CON12, 0x1055, 0x1055);
/* Enable NV regulator (-1.2V) */
Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0001, 0xffff);
udelay(100);
/* Enable AUD_ZCD */
Zcd_Enable(true, AUDIO_ANALOG_DEVICE_OUT_SPEAKERL);
/* Enable IBIST */
Ana_Set_Reg(AUDDEC_ANA_CON10, 0x0055, 0xffff);
/* Set HP DR bias current optimization, 010: 6uA */
Ana_Set_Reg(AUDDEC_ANA_CON9, 0x92, 0xffff);
/* Set HP & ZCD bias current optimization */
/* 01: ZCD: 4uA, HP/HS/LO: 5uA */
Ana_Set_Reg(AUDDEC_ANA_CON10, 0x0055, 0xffff);
/* Set LO STB enhance circuits */
Ana_Set_Reg(AUDDEC_ANA_CON4, 0x0110, 0xffff);
/* Enable LO driver bias circuits */
Ana_Set_Reg(AUDDEC_ANA_CON4, 0x0112, 0xffff);
/* Enable LO driver core circuits */
Ana_Set_Reg(AUDDEC_ANA_CON4, 0x0113, 0xffff);
/* Set LOL gain to normal gain step by step */
apply_speaker_gain(mCodec_data->mAudio_Ana_Volume
[AUDIO_ANALOG_VOLUME_LINEOUTR]);
/* Enable AUD_CLK */
Ana_Set_Reg(AUDDEC_ANA_CON11, 0x1, 0x1);
/* Enable Audio DAC */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x3009, 0xffff);
/* Enable low-noise mode of DAC */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0201, 0xffff);
/* Switch LOL MUX to audio DAC */
Ana_Set_Reg(AUDDEC_ANA_CON4, 0x011b, 0xffff);
/* disable Pull-down HPL/R to AVSS28_AUD */
hp_pull_down(false);
} else {
pr_debug("%s(), enable %d\n", __func__, enable);
/* LOL mux to open */
Ana_Set_Reg(AUDDEC_ANA_CON4, 0x0000, 0x3 << 2);
if (GetDLStatus() == false) {
/* Pull-down HPL/R to AVSS28_AUD */
hp_pull_down(true);
/* Disable Audio DAC */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0000, 0x000f);
/* Disable AUD_CLK */
Ana_Set_Reg(AUDDEC_ANA_CON11, 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_CON4, 0x0, 0x1);
/* Disable LO driver bias circuits */
Ana_Set_Reg(AUDDEC_ANA_CON4, 0x0000, 0x1 << 1);
/* Disable HP aux CMFB loop */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0, 0xff << 8);
/* Enable HP main CMFB Switch */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x2 << 8, 0xff << 8);
/* Pull-down HPL/R, HS, LO to AVSS28_AUD */
Ana_Set_Reg(AUDDEC_ANA_CON7, 0xa8, 0xff);
/* Disable IBIST */
Ana_Set_Reg(AUDDEC_ANA_CON10, 0x1 << 8, 0x1 << 8);
/* Disable AUD_ZCD */
Zcd_Enable(false, AUDIO_ANALOG_DEVICE_OUT_SPEAKERL);
/* Disable NV regulator (-1.2V) */
Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0, 0x1);
/* Disable cap-less LDOs (1.5V) */
Ana_Set_Reg(AUDDEC_ANA_CON12, 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)
{
/* pr_debug("%s()\n", __func__); */
ucontrol->value.integer.value[0] =
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_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->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_SPEAKERL] == false)) {
Speaker_Amp_Change(true);
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_SPEAKERL] =
ucontrol->value.integer.value[0];
} else if ((ucontrol->value.integer.value[0] == false) &&
(mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_SPEAKERL] == true)) {
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_SPEAKERL] =
ucontrol->value.integer.value[0];
Speaker_Amp_Change(false);
}
return 0;
}
static void Ext_Speaker_Amp_Change(bool enable)
{
pr_debug("%s(), enable %d\n", __func__, enable);
#define SPK_WARM_UP_TIME (25) /* unit is ms */
if (enable) {
AudDrv_GPIO_EXTAMP_Select(false, 3);
/*udelay(1000); */
usleep_range(1 * 1000, 2 * 1000);
AudDrv_GPIO_EXTAMP_Select(true, 3);
usleep_range(5 * 1000, 10 * 1000);
} else {
AudDrv_GPIO_EXTAMP_Select(false, 3);
udelay(500);
}
}
static int Ext_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->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_EXTSPKAMP];
return 0;
}
static int Ext_Speaker_Amp_Set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
pr_debug("%s() gain = %ld\n ", __func__,
ucontrol->value.integer.value[0]);
if (ucontrol->value.integer.value[0]) {
/*AKITA-5 M8 audio bring up begin */
#ifdef SND_SOC_AW87519
aw87519_amp_lch_on();
aw87519_amp_rch_on();
#endif
/*AKITA-5 - end */
Ext_Speaker_Amp_Change(true);
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_EXTSPKAMP] =
ucontrol->value.integer.value[0];
} else {
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_EXTSPKAMP] =
ucontrol->value.integer.value[0];
/*AKITA-5 M8 audio bring up begin */
#ifdef SND_SOC_AW87519
aw87519_amp_lch_off();
aw87519_amp_rch_off();
#endif
/*AKITA-5 - end */
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->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_RECEIVER_SPEAKER_SWITCH]);
ucontrol->value.integer.value[0] =
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_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->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_RECEIVER_SPEAKER_SWITCH] == false)) {
Receiver_Speaker_Switch_Change(true);
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_RECEIVER_SPEAKER_SWITCH] =
ucontrol->value.integer.value[0];
} else if ((ucontrol->value.integer.value[0] == false) &&
(mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_RECEIVER_SPEAKER_SWITCH] ==
true)) {
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_RECEIVER_SPEAKER_SWITCH] =
ucontrol->value.integer.value[0];
Receiver_Speaker_Switch_Change(false);
}
return 0;
}
static void Headset_Speaker_Amp_Change(bool enable)
{
if (enable) {
#ifdef ANALOG_HPTRIM
if (apply_n12db_gain) {
mic_vinp_mv = get_accdet_auxadc();
if (mic_vinp_mv > MIC_VINP_4POLE_THRES_MV &&
((codec_debug_enable & DBG_DCTRIM_BYPASS_4POLE)
== 0)) {
Ana_Set_Reg(AUDDEC_ELR_0, 0x1 << 12
| get_anaoffset_value(
&spk_4pole_anaoffset), 0xffff);
} else {
Ana_Set_Reg(AUDDEC_ELR_0, 0x1 << 12
| get_anaoffset_value(
&spk_3pole_anaoffset), 0xffff);
}
/* pr_debug("%s(), mic_vinp_mv %d ana_offset 0x%x\n",
* __func__, mic_vinp_mv, Ana_Get_Reg(AUDDEC_ELR_0));
*/
}
#endif
if (GetDLStatus() == false)
TurnOnDacPower(
AUDIO_ANALOG_DEVICE_OUT_SPEAKER_HEADSET_L);
pr_debug("%s(), enable %d\n", __func__, enable);
/* Audio left headphone input selection (01) LOLP / LOLN */
set_input_mux(1);
/* Disable headphone short-circuit protection */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x3000, 0xf0ff);
/* HP IVBUF (Vin path) de-gain enable: -12dB */
if (apply_n12db_gain)
Ana_Set_Reg(AUDDEC_ANA_CON7, 0x0004, 0xff);
/* Disable handset short-circuit protection */
Ana_Set_Reg(AUDDEC_ANA_CON3, 0x0010, 0xffff);
/* Disable linout short-circuit protection */
enable_lo_buffer(false);
/* Reduce ESD resistance of AU_REFN */
Ana_Set_Reg(AUDDEC_ANA_CON2, 0x200, 0x200);
/* Set HPR/HPL gain as minimum (~ -40dB) */
Ana_Set_Reg(ZCD_CON2, DL_GAIN_N_40DB_REG, 0xffff);
/* Set HPR/HPL gain as minimum (~ -40dB) */
Ana_Set_Reg(ZCD_CON1, DL_GAIN_N_40DB_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) */
Ana_Set_Reg(AUDDEC_ANA_CON12, 0x1055, 0x1055);
/* Enable NV regulator (-1.2V) */
Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0001, 0xffff);
udelay(100);
/* Enable AUD_ZCD */
Zcd_Enable(true, AUDIO_ANALOG_DEVICE_OUT_SPEAKER_HEADSET_L);
/* Enable IBIST */
Ana_Set_Reg(AUDDEC_ANA_CON10, 0x0055, 0xffff);
/* Set HP DR bias current optimization, 010: 6uA */
Ana_Set_Reg(AUDDEC_ANA_CON9, 0x92, 0xffff);
/* Set HP & ZCD bias current optimization */
/* 01: ZCD: 4uA, HP/HS/LO: 5uA */
Ana_Set_Reg(AUDDEC_ANA_CON10, 0x0055, 0xffff);
/* Set HPP/N STB enhance circuits */
Ana_Set_Reg(AUDDEC_ANA_CON2, 0x33, 0x00ff);
/* No Pull-down HPL/R to AVSS28_AUD */
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x000c, 0x00ff);
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x003c, 0x00ff);
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0c80, 0x0fff);
/* Enable HP driver bias circuits */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x30c0, 0xf0ff);
/* Enable HP driver core circuits */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x30f0, 0xf0ff);
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x00fc, 0x00ff);
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0e80, 0x0fff);
/* Enable HP main CMFB loop */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0280, 0x0fff);
/* Enable HP main output stage */
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x00ff, 0x00ff);
enable_lo_buffer(true);
apply_speaker_gain(mCodec_data->mAudio_Ana_Volume
[AUDIO_ANALOG_VOLUME_LINEOUTR]);
/* Enable HPR/L main output stage step by step */
hp_main_output_ramp(true);
hp_aux_feedback_loop_gain_ramp(true);
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x77cf, 0x00ff);
/* apply volume setting */
headset_volume_ramp(DL_GAIN_N_40DB,
mCodec_data->mAudio_Ana_Volume
[AUDIO_ANALOG_VOLUME_HPOUTL]);
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x77c3, 0x00ff);
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x7703, 0x00ff);
udelay(100);
/* Enable AUD_CLK */
Ana_Set_Reg(AUDDEC_ANA_CON11, 0x1, 0x1);
/* Enable Audio DAC */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x30F9, 0xf0ff);
/* Enable low-noise mode of DAC */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0281, 0x0fff);
/* Switch LOL MUX to audio DAC */
Ana_Set_Reg(AUDDEC_ANA_CON4, 0x011b, 0xffff);
/* Switch HPL MUX to Line-out */
/* Switch HPR MUX to DAC */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x39ff, 0xffff);
#ifndef ANALOG_HPTRIM
SetDcCompenSation_spk2hp(true);
#endif
/* disable Pull-down HPL/R to AVSS28_AUD */
hp_pull_down(false);
} else {
/* Pull-down HPL/R to AVSS28_AUD */
hp_pull_down(true);
#ifndef ANALOG_HPTRIM
SetDcCompenSation_spk2hp(false);
#endif
/* Audio left headphone input selection (00) open / open */
set_input_mux(0);
if (GetDLStatus() == false) {
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0000, 0x0001);
/* Disable Audio DAC */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0000, 0x000f);
/* Disable AUD_CLK */
Ana_Set_Reg(AUDDEC_ANA_CON11, 0x0, 0x1);
/* Short HP main output to HP aux output stage */
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x77c3, 0x00ff);
/* Enable HP aux output stage */
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x77cf, 0x00ff);
/* decrease HPL/R gain to normal gain step by step */
headset_volume_ramp(mCodec_data->mAudio_Ana_Volume
[AUDIO_ANALOG_VOLUME_HPOUTL],
DL_GAIN_N_40DB);
/* Enable HP aux feedback loop */
Ana_Set_Reg(AUDDEC_ANA_CON1, 0x77ff, 0x00ff);
/* 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);
/* decrease LOL gain to minimum gain step by step */
Ana_Set_Reg(ZCD_CON1, DL_GAIN_N_40DB_REG, 0xffff);
/* LOL mux to open */
Ana_Set_Reg(AUDDEC_ANA_CON4, 0x0000, 0x3 << 2);
/* 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 LO driver core circuits */
Ana_Set_Reg(AUDDEC_ANA_CON4, 0x0, 0x1);
/* Disable HP driver bias circuits */
Ana_Set_Reg(AUDDEC_ANA_CON0, 0x0, 0x3 << 6);
/* Disable LO driver bias circuits */
Ana_Set_Reg(AUDDEC_ANA_CON4, 0x0000, 0x1 << 1);
/* Disable HP aux CMFB loop */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x0, 0xff << 8);
/* Enable HP main CMFB Switch */
Ana_Set_Reg(AUDDEC_ANA_CON6, 0x2 << 8, 0xff << 8);
/* Pull-down HPL/R, HS, LO to AVSS28_AUD */
Ana_Set_Reg(AUDDEC_ANA_CON7, 0xa8, 0xff);
/* Disable IBIST */
Ana_Set_Reg(AUDDEC_ANA_CON10, 0x1 << 8, 0x1 << 8);
/* Disable AUD_ZCD */
Zcd_Enable(false, AUDIO_ANALOG_DEVICE_OUT_SPEAKER_HEADSET_L);
/* Disable NV regulator (-1.2V) */
Ana_Set_Reg(AUDDEC_ANA_CON13, 0x0, 0x1);
/* Disable cap-less LDOs (1.5V) */
Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0, 0x1055);
if (always_pull_low_off) {
/* Reset HPP/N STB enhance circuits */
Ana_Set_Reg(AUDDEC_ANA_CON2, 0x0, 0xff);
}
/* Disable NCP */
Ana_Set_Reg(AUDNCP_CLKDIV_CON3, 0x1, 0x1);
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->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_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->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_SPEAKER_HEADSET_R] == false)) {
Headset_Speaker_Amp_Change(true);
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_SPEAKER_HEADSET_R] =
ucontrol->value.integer.value[0];
} else if ((ucontrol->value.integer.value[0] == false) &&
(mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_OUT_SPEAKER_HEADSET_R] ==
true)) {
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_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 *DAC_SampleRate_function[] = {
* "8000", "11025", "16000", "24000", "32000", "44100", "48000"};
*/
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",
"-11Db", "-12Db", "-13Db", "-14Db", "-15Db", "-16Db", "-17Db",
"-18Db", "-19Db", "-20Db", "-21Db", "-22Db", "-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)
{
pr_debug("Speaker_PGA_Get = %d\n",
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_LINEOUTL]);
ucontrol->value.integer.value[0] =
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_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];
pr_debug("%s(), index = %d\n", __func__, index);
if (index >= ARRAY_SIZE(DAC_DL_PGA_Speaker_GAIN)) {
pr_debug("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->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_LINEOUTL] = index;
return 0;
}
static int Lineout_PGAR_Get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* pr_debug("%s = %d\n", __func__,
* mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_LINEOUTR]);
*/
ucontrol->value.integer.value[0] =
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_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];
pr_debug("%s(), index = %d\n", __func__, index);
if (index >= ARRAY_SIZE(DAC_DL_PGA_Speaker_GAIN)) {
pr_debug("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->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_LINEOUTR] = index;
return 0;
}
static int Handset_PGA_Get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* pr_debug("Handset_PGA_Get = %d\n",
* mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_HSOUTL]);
*/
ucontrol->value.integer.value[0] =
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_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];
pr_debug("%s(), index = %d\n", __func__, index);
if (index >= ARRAY_SIZE(DAC_DL_PGA_Handset_GAIN)) {
pr_debug("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->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_HSOUTL] = index;
return 0;
}
static int Headset_PGAL_Get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* pr_debug("Headset_PGAL_Get = %d\n",
* mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_HPOUTL]);
*/
ucontrol->value.integer.value[0] =
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_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->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_HPOUTL];
if (index >= ARRAY_SIZE(DAC_DL_PGA_Headset_GAIN)) {
pr_debug("return -EINVAL\n");
return -EINVAL;
}
if (index == (ARRAY_SIZE(DAC_DL_PGA_Headset_GAIN) - 1))
index = DL_GAIN_N_40DB;
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_HPOUTL] = index;
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_HPOUTR] = index;
if (mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_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)
{
/* pr_debug("Headset_PGAR_Get = %d\n",
* mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_HPOUTR]);
*/
ucontrol->value.integer.value[0] =
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_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->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_HPOUTR];
pr_debug("%s(), index = %d\n", __func__, index);
if (index >= ARRAY_SIZE(DAC_DL_PGA_Headset_GAIN)) {
pr_debug("return -EINVAL\n");
return -EINVAL;
}
if (index == (ARRAY_SIZE(DAC_DL_PGA_Headset_GAIN) - 1))
index = DL_GAIN_N_40DB;
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_HPOUTL] = index;
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_HPOUTR] = index;
if (mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_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[AUDIO_ANALOG_DEVICE_IN_ADC] = %d\n",
__func__, mBlockSampleRate[AUDIO_ANALOG_DEVICE_IN_ADC]);
ucontrol->value.integer.value[0] =
mBlockSampleRate[AUDIO_ANALOG_DEVICE_IN_ADC];
return 0;
}
static int codec_adc_sample_rate_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
mBlockSampleRate[AUDIO_ANALOG_DEVICE_IN_ADC] =
ucontrol->value.integer.value[0];
pr_debug("%s mBlockSampleRate[AUDIO_ANALOG_DEVICE_IN_ADC] = %d\n",
__func__,
mBlockSampleRate[AUDIO_ANALOG_DEVICE_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[AUDIO_ANALOG_DEVICE_OUT_DAC] = %d\n",
__func__,
mBlockSampleRate[AUDIO_ANALOG_DEVICE_OUT_DAC]);
ucontrol->value.integer.value[0] =
mBlockSampleRate[AUDIO_ANALOG_DEVICE_OUT_DAC];
return 0;
}
static int codec_dac_sample_rate_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
mBlockSampleRate[AUDIO_ANALOG_DEVICE_OUT_DAC] =
ucontrol->value.integer.value[0];
pr_debug("%s mBlockSampleRate[AUDIO_ANALOG_DEVICE_OUT_DAC] = %d\n",
__func__,
mBlockSampleRate[AUDIO_ANALOG_DEVICE_OUT_DAC]);
return 0;
}
static int Aud_Clk_Buf_Get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* pr_debug("\%s n", __func__); */
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)
{
pr_debug("%s(), value = %d\n",
__func__, ucontrol->value.enumerated.item[0]);
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);
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;
}
static int pmic_dc_offset_spk2hp_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
pr_debug("%s(), SPKL %d\n", __func__, spkl_dc_offset);
ucontrol->value.integer.value[0] = spkl_dc_offset;
return 0;
}
static int pmic_dc_offset_spk2hp_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
pr_debug("%s(), %ld\n", __func__, ucontrol->value.integer.value[0]);
spkl_dc_offset = ucontrol->value.integer.value[0];
return 0;
}
static const char * const dctrim_control_state[] = {
"Not_Yet", "Calibrating", "Calibrated"};
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_debug("%s(), return -EINVAL\n", __func__);
return -EINVAL;
}
if (ucontrol->value.integer.value[0] == 1)
get_hp_lr_trim_offset();
else
dctrim_calibrated = ucontrol->value.integer.value[0];
return 0;
}
static int hp_impedance_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
#ifdef BYPASS_HPIMP
pr_debug("%s(), bypass hp_impedance\n", __func__);
ucontrol->value.integer.value[0] = 32;
return 0;
#else
if (!set_hp_impedance_ctl) {
pr_debug("%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_debug("%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;
#endif
}
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 const char *const apply_n12db_setting[] = { "Off", "On" };
static int apply_n12db_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.integer.value[0] = apply_n12db_gain;
pr_debug("%s(), hp_impedance = %ld\n",
__func__, ucontrol->value.integer.value[0]);
return 0;
}
static int apply_n12db_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
apply_n12db_gain = ucontrol->value.integer.value[0];
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_debug("%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),
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(apply_n12db_setting),
apply_n12db_setting),
};
static const struct snd_kcontrol_new mt6357_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_SINGLE_EXT("[HP+SPK] DcTrim_DC_Offset", SND_SOC_NOPM,
0, 0x10000, 0, pmic_dc_offset_spk2hp_get,
pmic_dc_offset_spk2hp_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_ENUM_EXT("Apply_N12DB_Gain", Audio_DL_Enum[14],
apply_n12db_get, apply_n12db_set),
};
void SetMicPGAGain(void)
{
int index = 0;
index = mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_MICAMP1];
pr_debug("%s AUDIO_ANALOG_VOLUME_MICAMP1 index =%d\n",
__func__, index);
Ana_Set_Reg(AUDENC_ANA_CON0, index << 8, 0x0700);
index = mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_MICAMP2];
Ana_Set_Reg(AUDENC_ANA_CON1, index << 8, 0x0700);
}
static bool GetAdcStatus(void)
{
int i = 0;
for (i = AUDIO_ANALOG_DEVICE_IN_ADC1;
i < AUDIO_ANALOG_DEVICE_MAX; i++) {
if ((mCodec_data->mAudio_Ana_DevicePower[i] == true)
&& (i != AUDIO_ANALOG_DEVICE_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);
/* set gpio miso mode */
set_capture_gpio(true);
/* Enable audio ADC CLKGEN */
Ana_Set_Reg(AUDDEC_ANA_CON11, 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_CON12, 0x0100, 0x2500);
/* LCLDO_ENC remote sense */
Ana_Set_Reg(AUDDEC_ANA_CON12, 0x2500, 0x2500);
/* mic bias */
if (mCodec_data->mAudio_Ana_Mux
[AUDIO_MICSOURCE_MUX_IN_1] == 0) {
/* phone mic */
/* Enable MICBIAS0, MISBIAS0 = 1P9V */
Ana_Set_Reg(AUDENC_ANA_CON8, 0x0021, 0xffff);
} else if (mCodec_data->mAudio_Ana_Mux
[AUDIO_MICSOURCE_MUX_IN_1] == 1) {
/* headset mic */
/* Enable MICBIAS1, MISBIAS1 = 2P6V */
Ana_Set_Reg(AUDENC_ANA_CON9, 0x0001, 0x0001);
}
SetMicPGAGain();
}
if (ADCType == AUDIO_ANALOG_DEVICE_IN_ADC1) {
/* main and headset mic */
if (mCodec_data->mAudio_Ana_Mux
[AUDIO_MICSOURCE_MUX_IN_1] == 0) {
/* "ADC1", main_mic */
/* Audio L preamplifier input sel :
* AIN0. Enable audio L PGA
*/
Ana_Set_Reg(AUDENC_ANA_CON0, 0x0041, 0xf0ff);
/* Audio L ADC input sel :
* L PGA. Enable audio L ADC
*/
Ana_Set_Reg(AUDENC_ANA_CON0, 0x5041, 0xf000);
} else if (mCodec_data->mAudio_Ana_Mux
[AUDIO_MICSOURCE_MUX_IN_1] == 1) {
/* "ADC2", headset mic */
/* Audio L preamplifier input sel :
* AIN1. Enable audio L PGA
*/
Ana_Set_Reg(AUDENC_ANA_CON0, 0x0081, 0xf0ff);
/* Audio L ADC input sel :
* L PGA. Enable audio L ADC
*/
Ana_Set_Reg(AUDENC_ANA_CON0, 0x5081, 0xf000);
}
} else if (ADCType == AUDIO_ANALOG_DEVICE_IN_ADC2) {
/* ref mic */
/* Audio R preamplifier input sel :
* AIN2. Enable audio R PGA
*/
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) {
/* here to set digital part */
/* AdcClockEnable(true); */
Topck_Enable(true);
/* power on clock */
Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x8000, 0xdfbf);
/* 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 & total audio clk disable */
Ana_Set_Reg(PMIC_AUDIO_TOP_CON0,
0x00bf, 0x00bf);
}
/* up-link power down */
Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x0020, 0x0020);
}
if (ADCType == AUDIO_ANALOG_DEVICE_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);
/* Audio L preamplifier input sel :
* off, Audio L PGA 0 dB gain
*/
/* Disable audio L PGA */
} else if (ADCType == AUDIO_ANALOG_DEVICE_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);
/* Audio R preamplifier input sel :
* off, Audio R PGA 0 dB gain
*/
/* Disable audio R PGA */
}
if (GetAdcStatus() == false) {
/* mic bias */
if (mCodec_data->mAudio_Ana_Mux
[AUDIO_MICSOURCE_MUX_IN_1] == 0) {
/* phone mic */
/* Disable MICBIAS0, MISBIAS0 = 1P7V */
Ana_Set_Reg(AUDENC_ANA_CON8, 0x0000, 0xffff);
} else if (mCodec_data->mAudio_Ana_Mux
[AUDIO_MICSOURCE_MUX_IN_1] == 1) {
/* headset mic */
/* Disable MICBIAS1 */
Ana_Set_Reg(AUDENC_ANA_CON9, 0x0000, 0x0001);
}
/* LCLDO_ENC remote sense off */
Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0100, 0x2500);
/* disable LCLDO_ENC 1P8V */
Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0000, 0x2500);
/* ADC CLK from CLKGEN (13MHz) */
Ana_Set_Reg(AUDENC_ANA_CON3, 0x0000, 0xffff);
/* disable audio ADC CLKGEN */
Ana_Set_Reg(AUDDEC_ANA_CON11, 0x0 << 5, 0x1 << 5);
set_capture_gpio(false);
/* 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_debug("%s(), set_ap_dmic == NULL\n",
__func__);
audckbufEnable(true);
/* Enable audio globe bias */
NvregEnable(true);
/* Enable CLKSQ 26MHz */
ClsqEnable(true);
/* set gpio miso mode */
set_capture_gpio(true);
/* mic bias */
/* Enable MICBIAS0, MISBIAS0 = 1P9V */
Ana_Set_Reg(AUDENC_ANA_CON8, 0x0021, 0xffff);
/* RG_BANDGAPGEN=1'b0 */
Ana_Set_Reg(AUDENC_ANA_CON9, 0x0, 0x1 << 12);
/* DMIC enable */
Ana_Set_Reg(AUDENC_ANA_CON7, 0x0005, 0xffff);
/* here to set digital part */
/* AdcClockEnable(true); */
Topck_Enable(true);
/* power on clock */
Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x8000, 0xdfbf);
/* 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 & total audio clk disable */
Ana_Set_Reg(PMIC_AUDIO_TOP_CON0,
0x00bf, 0x00bf);
}
/* up-link power down */
Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x0020, 0x0020);
/* DMIC disable */
Ana_Set_Reg(AUDENC_ANA_CON7, 0x0000, 0xffff);
/* mic bias */
/* MISBIAS0 = 1P7V */
Ana_Set_Reg(AUDENC_ANA_CON8, 0x0001, 0xffff);
/* RG_BANDGAPGEN=1'b0 */
Ana_Set_Reg(AUDENC_ANA_CON9, 0x0, 0x1 << 12);
/* MICBIA0 disable */
Ana_Set_Reg(AUDENC_ANA_CON8, 0x0000, 0xffff);
set_capture_gpio(false);
/* 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, AUDIO_MICSOURCE_MUX_IN_1 %d, ECMmode %d\n",
__func__,
enable,
ADCType,
mCodec_data->mAudio_Ana_Mux[AUDIO_MICSOURCE_MUX_IN_1],
ECMmode);
if (enable) {
if (GetAdcStatus() == false) {
audckbufEnable(true);
/* Enable audio globe bias */
NvregEnable(true);
/* Enable CLKSQ 26MHz */
ClsqEnable(true);
/* set gpio miso mode */
set_capture_gpio(true);
/* Enable audio ADC CLKGEN */
Ana_Set_Reg(AUDDEC_ANA_CON11, 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_CON12, 0x0100, 0x2500);
/* LCLDO_ENC remote sense */
Ana_Set_Reg(AUDDEC_ANA_CON12, 0x2500, 0x2500);
/* AdcClockEnable(true); */
Topck_Enable(true);
/* Use higer 3db corner to reduce mic spike settle time
* , Default: 0x2061
*/
Ana_Set_Reg(AFE_DCCLK_CFG0, 0x0402, 0xffff);
Ana_Set_Reg(AFE_DCCLK_CFG0, 0x0402, 0xffff);
Ana_Set_Reg(AFE_DCCLK_CFG0, 0x0400, 0xffff);
Ana_Set_Reg(AFE_DCCLK_CFG0, 0x0401, 0xffff);
Ana_Set_Reg(AFE_DCCLK_CFG1, 0x0100, 0xffff);
/* mic bias */
if (mCodec_data->mAudio_Ana_Mux
[AUDIO_MICSOURCE_MUX_IN_1] == 0) {
/* phone mic */
switch (ECMmode) {
case 1: /* AUDIO_MIC_MODE_DCCECMDIFF */
Ana_Set_Reg(AUDENC_ANA_CON8,
0x7700, 0xff00);
break;
case 2:/* AUDIO_MIC_MODE_DCCECMSINGLE */
Ana_Set_Reg(AUDENC_ANA_CON8,
0x1100, 0xff00);
break;
default:
Ana_Set_Reg(AUDENC_ANA_CON8,
0x0000, 0xff00);
break;
}
/* Enable MICBIAS0, MISBIAS0 = 1P9V */
Ana_Set_Reg(AUDENC_ANA_CON8, 0x0021, 0x00ff);
} else if (mCodec_data->mAudio_Ana_Mux
[AUDIO_MICSOURCE_MUX_IN_1] == 1) {
/* headset mic */
/* Enable MICBIAS1, MISBIAS1 = 2P6V */
Ana_Set_Reg(AUDENC_ANA_CON9,
0x0001, 0x0001);
}
SetMicPGAGain();
}
if (ADCType == AUDIO_ANALOG_DEVICE_IN_ADC1) {
/* main and headset mic */
/* Audio L preamplifier DCC precharge */
Ana_Set_Reg(AUDENC_ANA_CON0, 0x0004, 0xf8ff);
if (mCodec_data->mAudio_Ana_Mux
[AUDIO_MICSOURCE_MUX_IN_1] == 0) {
/* "ADC1", main_mic */
/* Audio L preamplifier input sel :
* AIN0. Enable audio L PGA
*/
Ana_Set_Reg(AUDENC_ANA_CON0, 0x0041, 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, 0x5041, 0xf000);
} else if (mCodec_data->mAudio_Ana_Mux
[AUDIO_MICSOURCE_MUX_IN_1] == 1) {
/* "ADC2", headset mic */
/* Audio L preamplifier input sel :
* AIN1. Enable audio L PGA
*/
Ana_Set_Reg(AUDENC_ANA_CON0, 0x0081, 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, 0x5081, 0xf000);
}
} else if (ADCType == AUDIO_ANALOG_DEVICE_IN_ADC2) {
/* 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, 0x00c1, 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, 0x50c1, 0xf000);
}
if (GetAdcStatus() == false) {
/* Audio R preamplifier DCC precharge off */
Ana_Set_Reg(AUDENC_ANA_CON1, 0x0, 0x1 << 2);
/* Audio L preamplifier DCC precharge off */
Ana_Set_Reg(AUDENC_ANA_CON0, 0x0, 0x1 << 2);
/* here to set digital part */
/* power on clock */
Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x8000, 0xdfbf);
/* 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 & total audio clk disable */
Ana_Set_Reg(PMIC_AUDIO_TOP_CON0,
0x00bf, 0x00bf);
}
/* up-link power down */
Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x0020, 0x0020);
}
if (ADCType == AUDIO_ANALOG_DEVICE_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);
/* Audio L preamplifier input sel :
* off, Audio L PGA 0 dB gain
*/
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 == AUDIO_ANALOG_DEVICE_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);
/* Audio R preamplifier input sel :
* off, Audio R PGA 0 dB gain
*/
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->mAudio_Ana_Mux
[AUDIO_MICSOURCE_MUX_IN_1] == 0) {
/* phone mic */
/* Disable MICBIAS0, MISBIAS0 = 1P7V */
Ana_Set_Reg(AUDENC_ANA_CON8, 0x0000, 0xffff);
} else if (mCodec_data->mAudio_Ana_Mux
[AUDIO_MICSOURCE_MUX_IN_1] == 1) {
/* headset mic */
/* Disable MICBIAS1 */
Ana_Set_Reg(AUDENC_ANA_CON9,
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);
Ana_Set_Reg(AUDDEC_ANA_CON12, 0x0000, 0x2500);
/* ADC CLK from CLKGEN (13MHz) */
Ana_Set_Reg(AUDENC_ANA_CON3, 0x0000, 0xffff);
/* disable audio ADC CLKGEN */
Ana_Set_Reg(AUDDEC_ANA_CON11, 0x0 << 5, 0x1 << 5);
set_capture_gpio(false);
/* AdcClockEnable(false); */
Topck_Enable(false);
/* ClsqAuxEnable(false); */
ClsqEnable(false);
NvregEnable(false);
audckbufEnable(false);
}
}
return true;
}
/* 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(ADC_function), ADC_function),
};
static bool amic_dcc_tuning_enable;
static int Audio_UL_AMIC_DCC_Get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
pr_debug("amic_dcc_tuning_enable = %d\n", amic_dcc_tuning_enable);
ucontrol->value.integer.value[0] = amic_dcc_tuning_enable;
return 0;
}
static int Audio_UL_AMIC_DCC_Set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
amic_dcc_tuning_enable = ucontrol->value.integer.value[0];
pr_debug("%s() Amic_dcc_tuning_enable = %d\n",
__func__, amic_dcc_tuning_enable);
Ana_Set_Reg(AFE_DCCLK_CFG0, 0x2061, 0xffff);
return 0;
}
static int Audio_ADC1_Get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* pr_debug("Audio_ADC1_Get = %d\n",
* mCodec_data->mAudio_Ana_DevicePower
* [AUDIO_ANALOG_DEVICE_IN_ADC1]);
*/
ucontrol->value.integer.value[0] =
mCodec_data->mAudio_Ana_DevicePower[AUDIO_ANALOG_DEVICE_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 == AUDIO_ANALOGUL_MODE_ACC)
TurnOnADcPowerACC(AUDIO_ANALOG_DEVICE_IN_ADC1, true);
else if (mAudio_Analog_Mic1_mode == AUDIO_ANALOGUL_MODE_DCC)
TurnOnADcPowerDCC(AUDIO_ANALOG_DEVICE_IN_ADC1, true,
0);
else if (mAudio_Analog_Mic1_mode == AUDIO_ANALOGUL_MODE_DMIC)
TurnOnADcPowerDmic(AUDIO_ANALOG_DEVICE_IN_ADC1, true);
else if (mAudio_Analog_Mic1_mode ==
AUDIO_ANALOGUL_MODE_DCCECMDIFF)
TurnOnADcPowerDCC(AUDIO_ANALOG_DEVICE_IN_ADC1, true,
1);
else if (mAudio_Analog_Mic1_mode ==
AUDIO_ANALOGUL_MODE_DCCECMSINGLE)
TurnOnADcPowerDCC(AUDIO_ANALOG_DEVICE_IN_ADC1, true,
2);
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_IN_ADC1] =
ucontrol->value.integer.value[0];
} else {
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_IN_ADC1] =
ucontrol->value.integer.value[0];
if (mAudio_Analog_Mic1_mode == AUDIO_ANALOGUL_MODE_ACC)
TurnOnADcPowerACC(AUDIO_ANALOG_DEVICE_IN_ADC1, false);
else if (mAudio_Analog_Mic1_mode == AUDIO_ANALOGUL_MODE_DCC)
TurnOnADcPowerDCC(AUDIO_ANALOG_DEVICE_IN_ADC1, false,
0);
else if (mAudio_Analog_Mic1_mode == AUDIO_ANALOGUL_MODE_DMIC)
TurnOnADcPowerDmic(AUDIO_ANALOG_DEVICE_IN_ADC1, false);
else if (mAudio_Analog_Mic1_mode ==
AUDIO_ANALOGUL_MODE_DCCECMDIFF)
TurnOnADcPowerDCC(AUDIO_ANALOG_DEVICE_IN_ADC1, false,
1);
else if (mAudio_Analog_Mic1_mode ==
AUDIO_ANALOGUL_MODE_DCCECMSINGLE)
TurnOnADcPowerDCC(AUDIO_ANALOG_DEVICE_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)
{
/* pr_debug("Audio_ADC2_Get = %d\n",
* mCodec_data->mAudio_Ana_DevicePower
* [AUDIO_ANALOG_DEVICE_IN_ADC2]);
*/
ucontrol->value.integer.value[0] =
mCodec_data->mAudio_Ana_DevicePower[AUDIO_ANALOG_DEVICE_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 == AUDIO_ANALOGUL_MODE_ACC)
TurnOnADcPowerACC(AUDIO_ANALOG_DEVICE_IN_ADC2, true);
else if (mAudio_Analog_Mic2_mode == AUDIO_ANALOGUL_MODE_DCC)
TurnOnADcPowerDCC(AUDIO_ANALOG_DEVICE_IN_ADC2, true,
0);
else if (mAudio_Analog_Mic2_mode == AUDIO_ANALOGUL_MODE_DMIC)
TurnOnADcPowerDmic(AUDIO_ANALOG_DEVICE_IN_ADC2, true);
else if (mAudio_Analog_Mic2_mode ==
AUDIO_ANALOGUL_MODE_DCCECMDIFF)
TurnOnADcPowerDCC(AUDIO_ANALOG_DEVICE_IN_ADC2, true,
1);
else if (mAudio_Analog_Mic2_mode ==
AUDIO_ANALOGUL_MODE_DCCECMSINGLE)
TurnOnADcPowerDCC(AUDIO_ANALOG_DEVICE_IN_ADC2, true,
2);
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_IN_ADC2] =
ucontrol->value.integer.value[0];
} else {
mCodec_data->mAudio_Ana_DevicePower
[AUDIO_ANALOG_DEVICE_IN_ADC2] =
ucontrol->value.integer.value[0];
if (mAudio_Analog_Mic2_mode == AUDIO_ANALOGUL_MODE_ACC)
TurnOnADcPowerACC(AUDIO_ANALOG_DEVICE_IN_ADC2, false);
else if (mAudio_Analog_Mic2_mode == AUDIO_ANALOGUL_MODE_DCC)
TurnOnADcPowerDCC(AUDIO_ANALOG_DEVICE_IN_ADC2, false,
0);
else if (mAudio_Analog_Mic2_mode == AUDIO_ANALOGUL_MODE_DMIC)
TurnOnADcPowerDmic(AUDIO_ANALOG_DEVICE_IN_ADC2, false);
else if (mAudio_Analog_Mic2_mode ==
AUDIO_ANALOGUL_MODE_DCCECMDIFF)
TurnOnADcPowerDCC(AUDIO_ANALOG_DEVICE_IN_ADC2, false,
1);
else if (mAudio_Analog_Mic2_mode ==
AUDIO_ANALOGUL_MODE_DCCECMSINGLE)
TurnOnADcPowerDCC(AUDIO_ANALOG_DEVICE_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->mAudio_Ana_Mux[AUDIO_ANALOG_MUX_IN_MIC1]);
ucontrol->value.integer.value[0] =
mCodec_data->mAudio_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_debug("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_debug("%s() [AudioWarn]\n ", __func__);
pr_debug("%s() done\n", __func__);
mCodec_data->mAudio_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->mAudio_Ana_Mux[AUDIO_ANALOG_MUX_IN_MIC2]);
ucontrol->value.integer.value[0] =
mCodec_data->mAudio_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_debug("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_debug("%s() [AudioWarn]\n ", __func__);
pr_debug("%s() done\n", __func__);
mCodec_data->mAudio_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)
{
/* pr_debug("%s Mul_Sel = %d ", __func__, 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_debug("%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->mAudio_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_debug("return -EINVAL\n");
return -EINVAL;
}
mCodec_data->mAudio_Ana_Mux[AUDIO_ANALOG_MUX_IN_PREAMP_1] =
ucontrol->value.integer.value[0];
AudioPreAmp1_Sel(
mCodec_data->mAudio_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_debug("%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->mAudio_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_debug("return -EINVAL\n");
return -EINVAL;
}
mCodec_data->mAudio_Ana_Mux[AUDIO_ANALOG_MUX_IN_PREAMP_2] =
ucontrol->value.integer.value[0];
AudioPreAmp2_Sel(
mCodec_data->mAudio_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)
{
/* pr_debug("Audio_AmpR_Get = %d\n",
* mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_MICAMP1]);
*/
ucontrol->value.integer.value[0] =
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_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_debug("return -EINVAL\n");
return -EINVAL;
}
index = ucontrol->value.integer.value[0];
Ana_Set_Reg(AUDENC_ANA_CON0, (index << 8), 0x0700);
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_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)
{
/* pr_debug("Audio_PGA2_Get = %d\n",
* mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_MICAMP2]);
*/
ucontrol->value.integer.value[0] =
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_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_debug("return -EINVAL\n");
return -EINVAL;
}
index = ucontrol->value.integer.value[0];
Ana_Set_Reg(AUDENC_ANA_CON1, index << 8, 0x0700);
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_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)
{
/* pr_debug("Audio_MicSource1_Get = %d\n",
* mCodec_data->mAudio_Ana_Mux[AUDIO_MICSOURCE_MUX_IN_1]);
*/
ucontrol->value.integer.value[0] =
mCodec_data->mAudio_Ana_Mux[AUDIO_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_debug("return -EINVAL\n");
return -EINVAL;
}
index = ucontrol->value.integer.value[0];
/* pr_debug("%s() index = %d done\n", __func__, index); */
mCodec_data->mAudio_Ana_Mux[AUDIO_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)
{
/* pr_debug("%s() mAudio_Analog_Mic1_mode = %d\n",
* __func__, mAudio_Analog_Mic1_mode);
*/
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_debug("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)
{
/* pr_debug("%s() = %d\n", __func__, mAudio_Analog_Mic2_mode); */
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_debug("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)
{
/* pr_debug("%s() = %d\n", __func__, mAudio_Analog_Mic3_mode); */
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_debug("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)
{
/* pr_debug("%s() = %d\n", __func__, mAudio_Analog_Mic4_mode); */
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_debug("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_debug("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 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)
{
pr_debug("%s()\n", __func__);
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_debug("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);
TurnOffDacPower();
} else if (ucontrol->value.integer.value[0] > 0) {
/* enable pmic lpbk */
pr_debug("set PMIC LPBK3, DLSR=%d, ULSR=%d\n",
mBlockSampleRate[AUDIO_ANALOG_DEVICE_OUT_DAC],
mBlockSampleRate[AUDIO_ANALOG_DEVICE_IN_ADC]);
/* set dl part */
TurnOnDacPower(AUDIO_ANALOG_DEVICE_OUT_HEADSETL);
Ana_Set_Reg(PMIC_AUDIO_TOP_CON0, 0x8000, 0xffff);
/* power on clock */
/* enable aud_pad TX fifos */
Ana_Set_Reg(AFE_AUD_PAD_TOP, 0x3131, 0xffff);
/*mt6357 test*/
/* 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)
{
pr_debug("%s()\n", __func__);
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? */
pr_debug("%s()\n", __func__);
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 mt6357_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 mt6357_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_AMIC_DCC_Setting", Audio_UL_Enum[24],
Audio_UL_AMIC_DCC_Get,
Audio_UL_AMIC_DCC_Set),
};
static int read_efuse_hp_impedance_current_calibration(void)
{
int ret = 0;
int value, sign;
unsigned short efuse_val = 0;
pr_info("+%s()\n", __func__);
#ifndef AUDIO_USING_WRAP
/* 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 1392 ~ 1398 */
/* HPDET_COMP_SIGN @ efuse bit 1399 */
/* 1392 / 8 = 174 --> 0xae */
Ana_Set_Reg(OTP_CON0, 0xae, 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_info("%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 */
efuse_val = Ana_Get_Reg(OTP_CON12);
pr_info("%s(), efuse = 0x%x\n", __func__, efuse_val);
#else
ret = nvmem_device_read(mCodec_priv->hp_efuse, 0xae, 2, &efuse_val);
if (ret < 0) {
dev_err(mCodec_priv->dev, "%s(), efuse read fail: %d\n",
__func__, ret);
efuse_val = 0;
}
#endif
sign = (efuse_val >> 7) & 0x1;
value = efuse_val & 0x7f;
value = sign ? -value : value;
#ifndef AUDIO_USING_WRAP
/* 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);
#endif
pr_info("-%s(), efuse: %d\n", __func__, value);
return value;
}
static void mt6357_codec_init_reg(struct snd_soc_component *component)
{
pr_info("%s\n", __func__);
audckbufEnable(true);
Ana_Set_Reg(AUDENC_ANA_CON6, 0x0000, 0x0001);
/* disable AUDGLB */
Ana_Set_Reg(AUDDEC_ANA_CON11, 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, 0x20ff, 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_CON3, 0x1 << 4, 0x1 << 4);
/* disable LO buffer left short circuit protection */
Ana_Set_Reg(AUDDEC_ANA_CON4, 0x1 << 4, 0x1 << 4);
/* AUDENC_ANA_CON10 bit12 EINTHIRENB 0:2M 1:500k */
Ana_Set_Reg(AUDENC_ANA_CON10, 0x1c07, 0xffff);
/* set gpio */
set_playback_gpio(false);
set_capture_gpio(false);
audckbufEnable(false);
#ifdef CONFIG_SND_SOC_MT6357_ACCDET
mtk_accdet_init(component);
#endif
}
void InitCodecDefault(void)
{
pr_info("%s\n", __func__);
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_MICAMP1] = 3;
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_MICAMP2] = 3;
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_MICAMP3] = 3;
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_MICAMP4] = 3;
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_HPOUTR] = 8;
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_HPOUTR] = 8;
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_HSOUTL] = 8;
mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_HSOUTR] = 8;
mCodec_data->mAudio_Ana_Mux[AUDIO_ANALOG_MUX_IN_MIC1] =
AUDIO_ANALOG_AUDIOANALOG_INPUT_PREAMP;
mCodec_data->mAudio_Ana_Mux[AUDIO_ANALOG_MUX_IN_MIC2] =
AUDIO_ANALOG_AUDIOANALOG_INPUT_PREAMP;
mCodec_data->mAudio_Ana_Mux[AUDIO_ANALOG_MUX_IN_MIC3] =
AUDIO_ANALOG_AUDIOANALOG_INPUT_PREAMP;
mCodec_data->mAudio_Ana_Mux[AUDIO_ANALOG_MUX_IN_MIC4] =
AUDIO_ANALOG_AUDIOANALOG_INPUT_PREAMP;
}
static void InitGlobalVarDefault(void)
{
mCodec_data = NULL;
mAdc_Power_Mode = 0;
mInitCodec = false;
mAnaSuspend = false;
audck_buf_Count = 0;
ClsqCount = 0;
TopCkCount = 0;
NvRegCount = 0;
}
static struct task_struct *dc_trim_task;
static int dc_trim_thread(void *arg)
{
/* Default Pull-down HPL/R to AVSS28_AUD */
if (always_pull_down_enable)
hp_pull_down(true);
get_hp_lr_trim_offset();
#ifdef CONFIG_MTK_ACCDET
accdet_late_init(0);
#endif
do_exit(0);
return 0;
}
static int mt6357_component_probe(struct snd_soc_component *component)
{
int ret;
pr_debug("%s()\n", __func__);
if (mInitCodec == true)
return 0;
/* add codec controls */
snd_soc_add_component_controls(component, mt6357_snd_controls,
ARRAY_SIZE(mt6357_snd_controls));
snd_soc_add_component_controls(component, mt6357_UL_Codec_controls,
ARRAY_SIZE(mt6357_UL_Codec_controls));
snd_soc_add_component_controls(component, mt6357_pmic_Test_controls,
ARRAY_SIZE(mt6357_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 mt6357_codec_priv), GFP_KERNEL);
if (!mCodec_data) {
/*pr_debug("Failed to allocate private data\n");*/
return -ENOMEM;
}
snd_soc_component_set_drvdata(component, mCodec_data);
memset((void *)mCodec_data, 0, sizeof(struct mt6357_codec_priv));
mt6357_codec_init_reg(component);
InitCodecDefault();
efuse_current_calibrate =
read_efuse_hp_impedance_current_calibration();
mInitCodec = true;
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 mt6357_component_remove(struct snd_soc_component *component)
{
pr_debug("%s()\n", __func__);
return 0;
}
static unsigned int mt6357_component_read(struct snd_soc_component *component,
unsigned int reg)
{
pr_debug("%s() reg = 0x%x", __func__, reg);
Ana_Get_Reg(reg);
return 0;
}
static int mt6357_component_write(struct snd_soc_component *component,
unsigned int reg,
unsigned int value)
{
pr_debug("%s() reg = 0x%x value= 0x%x\n", __func__, reg, value);
Ana_Set_Reg(reg, value, 0xffffffff);
return 0;
}
static const struct snd_soc_component_driver mt6357_component_driver = {
.name = CODEC_MT6357_NAME,
.probe = mt6357_component_probe,
.remove = mt6357_component_remove,
.read = mt6357_component_read,
.write = mt6357_component_write,
};
static int mtk_codec_dev_probe(struct platform_device *pdev)
{
#if IS_ENABLED(CONFIG_MTK_PMIC_WRAP)
struct device_node *pwrap_node;
#else
struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent);
#endif
int ret = 0;
pr_info("%s: ++\n", __func__);
InitGlobalVarDefault();
mCodec_priv = devm_kzalloc(&pdev->dev,
sizeof(struct mt6357_priv),
GFP_KERNEL);
if (!mCodec_priv)
return -ENOMEM;
#if IS_ENABLED(CONFIG_MTK_PMIC_WRAP)
pwrap_node = of_parse_phandle(pdev->dev.of_node,
"mediatek,pwrap-regmap", 0);
if (!pwrap_node)
return -ENODEV;
mCodec_priv->regmap = pwrap_node_to_regmap(pwrap_node);
#else
mCodec_priv->regmap = mt6397->regmap;
#endif
if (IS_ERR(mCodec_priv->regmap))
return PTR_ERR(mCodec_priv->regmap);
#ifdef AUDIO_USING_WRAP
/* get pmic efuse handler */
mCodec_priv->hp_efuse = devm_nvmem_device_get(&pdev->dev,
"pmic-hp-efuse");
ret = PTR_ERR_OR_ZERO(mCodec_priv->hp_efuse);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "Error: Get efuse failed (%d)\n",
ret);
return ret;
}
#endif
dev_set_drvdata(&pdev->dev, mCodec_priv);
mCodec_priv->dev = &pdev->dev;
/* get pmic codec auxadc iio channel handler */
mCodec_priv->codec_auxadc = devm_iio_channel_get(&pdev->dev,
"pmic_codec");
ret = PTR_ERR_OR_ZERO(mCodec_priv->codec_auxadc);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_dbg(&pdev->dev, "Error: Get iio ch failed (%d)\n",
ret);
return ret;
}
/* get pmic accdet auxadc iio channel handler */
mCodec_priv->accdet_auxadc = devm_iio_channel_get(&pdev->dev,
"pmic_accdet");
ret = PTR_ERR_OR_ZERO(mCodec_priv->accdet_auxadc);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_dbg(&pdev->dev, "Error: Get iio ch failed (%d)\n",
ret);
return ret;
}
mt63xx_set_local_priv(mCodec_priv);
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
if (pdev->dev.dma_mask == NULL)
pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
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);
/* check if enable always PullDown */
ret = of_property_read_u32(pdev->dev.of_node,
"always_pull_down_enable",
&always_pull_down_enable);
if (ret) {
always_pull_down_enable = 0;
dev_info(&pdev->dev,
"%s(), get always_pull_down_enable fail, default 0\n",
__func__);
}
/* check if enable always PullDown */
ret = of_property_read_u32(pdev->dev.of_node,
"always_pull_low_off",
&always_pull_low_off);
if (ret) {
always_pull_low_off = 0;
dev_info(&pdev->dev,
"%s(), get always_pull_low_off fail, default 0\n",
__func__);
}
pr_debug("%s(), always_pull_down_enable = %d always_pull_low_off = %d\n",
__func__, always_pull_down_enable,
always_pull_low_off);
} else {
pr_debug("%s(), pdev->dev.of_node = NULL!!!\n", __func__);
}
pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
return devm_snd_soc_register_component(&pdev->dev,
&mt6357_component_driver,
mtk_6357_dai_codecs,
ARRAY_SIZE(mtk_6357_dai_codecs));
}
static const struct of_device_id mt6357_of_match[] = {
{.compatible = "mediatek,mt6357-sound",},
{}
};
MODULE_DEVICE_TABLE(of, mt6357_of_match);
static struct platform_driver mt6357_platform_driver = {
.driver = {
.name = "mt6357-sound",
.of_match_table = mt6357_of_match,
},
.probe = mtk_codec_dev_probe,
};
module_platform_driver(mt6357_platform_driver)
/* Module information */
MODULE_DESCRIPTION("MTK codec driver");
MODULE_LICENSE("GPL v2");