ASoC: changes to fix codec nack issue

This change fixes codec HW issues, Slimbus master capability issue
and codec NACK issues caused due to SIDO buck going down abruptly.

Change-Id: I74e94630b2ba4c132d66315ceee5127e05f284c6
Signed-off-by: Yeleswarapu Nagaradhesh <nagaradh@codeaurora.org>
This commit is contained in:
Yeleswarapu Nagaradhesh 2015-09-28 18:16:32 +05:30 committed by Gerrit - the friendly Code Review server
parent da26ec31d0
commit 07c2b1c579
8 changed files with 951 additions and 364 deletions

View file

@ -1566,20 +1566,19 @@ static bool wcd9335_is_volatile_register(struct device *dev, unsigned int reg)
case WCD9335_ANA_MBHC_ZDET:
case WCD9335_ANA_MICB2:
case WCD9335_CPE_SS_SS_ERROR_INT_STATUS:
case WCD9335_CPE_SS_SS_ERROR_INT_MASK:
case WCD9335_CPE_SS_SS_ERROR_INT_CLEAR:
case WCD9335_CPE_SS_STATUS:
case WCD9335_CPE_SS_BACKUP_INT:
case WCD9335_FLYBACK_EN:
case WCD9335_ANA_RX_SUPPLIES:
case WCD9335_CPE_SS_CFG:
case WCD9335_SOC_MAD_MAIN_CTL_1:
case WCD9335_SOC_MAD_AUDIO_CTL_3:
case WCD9335_SOC_MAD_AUDIO_CTL_4:
case WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT10:
case WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT11:
case WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT12:
case WCD9335_VBADC_ADC_DOUTMSB:
case WCD9335_VBADC_ADC_DOUTLSB:
case WCD9335_CDC_VBAT_VBAT_GAIN_MON_VAL:
case WCD9335_FLYBACK_EN:
case WCD9335_ANA_RX_SUPPLIES:
case WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL:
case WCD9335_SIDO_SIDO_CCL_2:
case WCD9335_SIDO_SIDO_CCL_4:
case WCD9335_DATA_HUB_NATIVE_FIFO_STATUS:
case WCD9335_MBHC_FSM_STATUS:
case WCD9335_SPLINE_SRC0_STATUS:
@ -1589,6 +1588,9 @@ static bool wcd9335_is_volatile_register(struct device *dev, unsigned int reg)
case WCD9335_SIDO_SIDO_TEST_2:
case WCD9335_SIDO_SIDO_CCL_8:
case WCD9335_BIAS_VBG_FINE_ADJ:
case WCD9335_VBADC_ADC_DOUTMSB:
case WCD9335_VBADC_ADC_DOUTLSB:
case WCD9335_CDC_VBAT_VBAT_GAIN_MON_VAL:
return true;
default:
return false;

View file

@ -330,4 +330,9 @@
#define WCD9XXX_A_ANA_HPH (0x609)
#define WCD9XXX_A_CDC_CLSH_CRC (0xC01)
#define WCD9XXX_FLYBACK_EN (0x6A4)
#define WCD9XXX_RX_BIAS_FLYB_BUFF (0x6C7)
#define WCD9XXX_HPH_L_EN (0x6D3)
#define WCD9XXX_HPH_R_EN (0x6D6)
#define WCD9XXX_HPH_REFBUFF_UHQA_CTL (0x6DD)
#define WCD9XXX_CLASSH_CTRL_VCL_2 (0x69B)
#endif

View file

@ -1241,17 +1241,6 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc)
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MECH_DETECTION_TYPE,
!detection_type);
/*
* For faster pull-up, adjust the pull-up current to 3uA.
* Possible that some codecs may choose not to update the
* pull up current, in which case this callback function
* will not be defined.
*/
if (mbhc->mbhc_cb->hph_pull_up_control) {
mbhc->mbhc_cb->hph_pull_up_control(codec,
(detection_type ? REMOVE : INSERT));
}
pr_debug("%s: mbhc->current_plug: %d detection_type: %d\n", __func__,
mbhc->current_plug, detection_type);
wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
@ -1647,7 +1636,7 @@ static bool wcd_mbhc_fw_validate(const void *data, size_t size)
return true;
}
irqreturn_t wcd_mbhc_btn_press_handler(int irq, void *data)
static irqreturn_t wcd_mbhc_btn_press_handler(int irq, void *data)
{
struct wcd_mbhc *mbhc = data;
int mask;
@ -1808,6 +1797,18 @@ static irqreturn_t wcd_mbhc_hphr_ocp_irq(int irq, void *data)
return IRQ_HANDLED;
}
static void wcd_mbhc_moisture_config(struct wcd_mbhc *mbhc)
{
if (mbhc->mbhc_cfg->moist_cfg.m_vref_ctl == V_OFF)
return;
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MOISTURE_VREF,
mbhc->mbhc_cfg->moist_cfg.m_vref_ctl);
if (mbhc->mbhc_cb->hph_pull_up_control)
mbhc->mbhc_cb->hph_pull_up_control(mbhc->codec,
mbhc->mbhc_cfg->moist_cfg.m_iref_ctl);
}
static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc)
{
int ret = 0;
@ -1818,9 +1819,12 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc)
/* enable HS detection */
if (mbhc->mbhc_cb->hph_pull_up_control)
mbhc->mbhc_cb->hph_pull_up_control(codec, INSERT);
mbhc->mbhc_cb->hph_pull_up_control(codec, I_DEFAULT);
else
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HS_L_DET_PULL_UP_CTRL, 3);
wcd_mbhc_moisture_config(mbhc);
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_PLUG_TYPE, mbhc->hphl_swh);
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_GND_PLUG_TYPE, mbhc->gnd_swh);
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_SW_HPH_LP_100K_TO_GND, 1);
@ -1977,7 +1981,6 @@ int wcd_mbhc_set_keycode(struct wcd_mbhc *mbhc)
WARN_ONCE(1, "Wrong button number:%d\n", i);
result = -1;
return result;
break;
}
ret = snd_jack_set_key(mbhc->button_jack.jack,
type,

View file

@ -55,6 +55,7 @@ enum wcd_mbhc_register_function {
WCD_MBHC_HPHL_PA_EN,
WCD_MBHC_HPH_PA_EN,
WCD_MBHC_SWCH_LEVEL_REMOVE,
WCD_MBHC_MOISTURE_VREF,
WCD_MBHC_PULLDOWN_CTRL,
WCD_MBHC_REG_FUNC_MAX,
};
@ -85,11 +86,6 @@ enum {
MIC_BIAS_4
};
enum {
REMOVE = 0,
INSERT,
};
enum {
MICB_PULLUP_ENABLE,
MICB_PULLUP_DISABLE,
@ -211,6 +207,31 @@ enum wcd_mbhc_hph_type {
WCD_MBHC_HPH_STEREO,
};
/*
* These enum definitions are directly mapped to the register
* definitions
*/
enum mbhc_moisture_vref {
V_OFF,
V_45_MV,
V_100_MV,
V_225_MV,
};
enum mbhc_hs_pullup_iref {
I_DEFAULT = -1,
I_OFF = 0,
I_1P0_UA,
I_2P0_UA,
I_3P0_UA,
};
struct wcd_mbhc_moisture_cfg {
enum mbhc_moisture_vref m_vref_ctl;
enum mbhc_hs_pullup_iref m_iref_ctl;
};
struct wcd_mbhc_config {
bool read_fw_bin;
void *calibration;
@ -218,9 +239,10 @@ struct wcd_mbhc_config {
bool mono_stero_detection;
bool (*swap_gnd_mic) (struct snd_soc_codec *codec);
bool hs_ext_micbias;
bool gnd_det_en;
int key_code[WCD_MBHC_KEYCODE_NUM];
uint32_t linein_th;
bool gnd_det_en;
struct wcd_mbhc_moisture_cfg moist_cfg;
};
struct wcd_mbhc_intr {
@ -263,14 +285,20 @@ struct wcd_mbhc_register {
"%s: BCL should have acquired\n", __func__); \
}
#define WCD_MBHC_REG_UPDATE_BITS(function, val) \
do { \
if (mbhc->wcd_mbhc_regs[function].reg) { \
snd_soc_update_bits(mbhc->codec, \
mbhc->wcd_mbhc_regs[function].reg, \
mbhc->wcd_mbhc_regs[function].mask, \
val << (mbhc->wcd_mbhc_regs[function].offset)); \
} \
/*
* Macros to update and read mbhc register bits. Check for
* "0" before updating or reading the register, because it
* is possible that one codec wants to write to that bit and
* other codec does not.
*/
#define WCD_MBHC_REG_UPDATE_BITS(function, val) \
do { \
if (mbhc->wcd_mbhc_regs[function].reg) { \
snd_soc_update_bits(mbhc->codec, \
mbhc->wcd_mbhc_regs[function].reg, \
mbhc->wcd_mbhc_regs[function].mask, \
val << (mbhc->wcd_mbhc_regs[function].offset)); \
} \
} while (0)
#define WCD_MBHC_REG_READ(function, val) \
@ -313,7 +341,8 @@ struct wcd_mbhc_cb {
bool (*hph_pa_on_status)(struct snd_soc_codec *);
void (*set_btn_thr)(struct snd_soc_codec *, s16 *, s16 *,
int num_btn, bool);
void (*hph_pull_up_control)(struct snd_soc_codec *, bool);
void (*hph_pull_up_control)(struct snd_soc_codec *,
enum mbhc_hs_pullup_iref);
int (*mbhc_micbias_control)(struct snd_soc_codec *, int req);
void (*mbhc_micb_ramp_control)(struct snd_soc_codec *, bool);
void (*skip_imped_detect)(struct snd_soc_codec *);

File diff suppressed because it is too large Load diff

View file

@ -99,6 +99,15 @@ struct tasha_reg_mask_val {
u8 val;
};
/* Selects compander and smart boost settings
* for a given speaker mode
*/
enum {
SPKR_MODE_DEFAULT,
SPKR_MODE_1, /* COMP Gain = 12dB, Smartboost Max = 5.5V */
};
extern void *tasha_get_afe_config(struct snd_soc_codec *codec,
enum afe_config_type config_type);
extern int tasha_cdc_mclk_enable(struct snd_soc_codec *codec, int enable,
@ -120,5 +129,5 @@ extern int tasha_codec_info_create_codec_entry(struct snd_info_entry *,
extern int tasha_codec_enable_standalone_micbias(struct snd_soc_codec *codec,
int micb_num,
bool enable);
extern int tasha_set_spkr_mode(struct snd_soc_codec *codec, int mode);
#endif

View file

@ -22,6 +22,25 @@
#define WCD_USLEEP_RANGE 50
enum {
DAC_GAIN_0DB = 0,
DAC_GAIN_0P2DB,
DAC_GAIN_0P4DB,
DAC_GAIN_0P6DB,
DAC_GAIN_0P8DB,
DAC_GAIN_M0P2DB,
DAC_GAIN_M0P4DB,
DAC_GAIN_M0P6DB,
};
enum {
VREF_FILT_R_0OHM = 0,
VREF_FILT_R_25KOHM,
VREF_FILT_R_50KOHM,
VREF_FILT_R_100KOHM,
};
static void (*clsh_state_fp[NUM_CLSH_STATES_V2])(struct snd_soc_codec *,
struct wcd_clsh_cdc_data *,
u8 req_state, bool en, int mode);
@ -215,25 +234,80 @@ static void wcd_clsh_flyback_ctrl(struct snd_soc_codec *codec,
usleep_range(500, 500 + WCD_USLEEP_RANGE);
}
static void wcd_clsh_set_hph_mode(struct snd_soc_codec *codec,
int mode)
static void wcd_clsh_set_gain_path(struct snd_soc_codec *codec,
int mode)
{
u8 val;
struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
if (!TASHA_IS_2_0(wcd9xxx->version))
return;
switch (mode) {
case CLS_H_NORMAL:
case CLS_AB:
val = 0x00;
break;
case CLS_H_HIFI:
val = 0x02;
break;
case CLS_H_LP:
val = 0x01;
break;
};
snd_soc_update_bits(codec, WCD9XXX_HPH_L_EN, 0xC0, (val << 6));
snd_soc_update_bits(codec, WCD9XXX_HPH_R_EN, 0xC0, (val << 6));
}
static void wcd_clsh_set_hph_mode(struct snd_soc_codec *codec,
int mode)
{
u8 val;
u8 gain;
u8 res_val = VREF_FILT_R_0OHM;
struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
switch (mode) {
case CLS_H_NORMAL:
res_val = VREF_FILT_R_50KOHM;
val = 0x00;
gain = DAC_GAIN_0DB;
break;
case CLS_AB:
val = 0x00;
gain = DAC_GAIN_0DB;
break;
case CLS_H_HIFI:
val = 0x08;
gain = DAC_GAIN_M0P2DB;
break;
case CLS_H_LP:
val = 0x04;
gain = DAC_GAIN_0P2DB;
break;
};
snd_soc_update_bits(codec, WCD9XXX_A_ANA_HPH, 0x0C, val);
if (TASHA_IS_2_0(wcd9xxx->version)) {
snd_soc_update_bits(codec, WCD9XXX_CLASSH_CTRL_VCL_2,
0x30, (res_val << 4));
snd_soc_update_bits(codec, WCD9XXX_HPH_REFBUFF_UHQA_CTL,
0x07, gain);
}
}
static void wcd_clsh_set_flyback_current(struct snd_soc_codec *codec, int mode)
{
struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
if (!TASHA_IS_2_0(wcd9xxx->version))
return;
snd_soc_update_bits(codec, WCD9XXX_RX_BIAS_FLYB_BUFF, 0x0F, 0x0A);
snd_soc_update_bits(codec, WCD9XXX_RX_BIAS_FLYB_BUFF, 0xF0, 0xA0);
/* Sleep needed to avoid click and pop as per HW requirement */
usleep_range(100, 110);
}
static void wcd_clsh_set_buck_regulator_mode(struct snd_soc_codec *codec,
@ -265,6 +339,7 @@ static void wcd_clsh_state_lo(struct snd_soc_codec *codec,
wcd_clsh_set_buck_mode(codec, mode);
wcd_clsh_set_flyback_mode(codec, mode);
wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true);
wcd_clsh_set_flyback_current(codec, mode);
wcd_clsh_buck_ctrl(codec, clsh_d, mode, true);
} else {
wcd_clsh_buck_ctrl(codec, clsh_d, mode, false);
@ -312,6 +387,7 @@ static void wcd_clsh_state_hph_ear(struct snd_soc_codec *codec,
0x40, 0x40);
if ((req_state == WCD_CLSH_STATE_HPHL) ||
(req_state == WCD_CLSH_STATE_HPHR)) {
wcd_clsh_set_gain_path(codec, mode);
wcd_clsh_set_flyback_mode(codec, mode);
wcd_clsh_set_buck_mode(codec, mode);
}
@ -412,6 +488,9 @@ static void wcd_clsh_state_hph_lo(struct snd_soc_codec *codec,
else {
wcd_clsh_set_flyback_mode(codec, mode);
wcd_clsh_set_buck_mode(codec, mode);
if ((req_state == WCD_CLSH_STATE_HPHL) ||
(req_state == WCD_CLSH_STATE_HPHR))
wcd_clsh_set_gain_path(codec, mode);
}
} else {
if ((req_state == WCD_CLSH_STATE_HPHL) ||
@ -537,7 +616,9 @@ static void wcd_clsh_state_hph_r(struct snd_soc_codec *codec,
wcd_clsh_set_buck_mode(codec, mode);
wcd_clsh_set_flyback_mode(codec, mode);
wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true);
wcd_clsh_set_flyback_current(codec, mode);
wcd_clsh_buck_ctrl(codec, clsh_d, mode, true);
wcd_clsh_set_gain_path(codec, mode);
wcd_clsh_set_hph_mode(codec, mode);
} else {
wcd_clsh_set_hph_mode(codec, CLS_H_NORMAL);
@ -589,7 +670,9 @@ static void wcd_clsh_state_hph_l(struct snd_soc_codec *codec,
wcd_clsh_set_buck_mode(codec, mode);
wcd_clsh_set_flyback_mode(codec, mode);
wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true);
wcd_clsh_set_flyback_current(codec, mode);
wcd_clsh_buck_ctrl(codec, clsh_d, mode, true);
wcd_clsh_set_gain_path(codec, mode);
wcd_clsh_set_hph_mode(codec, mode);
} else {
wcd_clsh_set_hph_mode(codec, CLS_H_NORMAL);
@ -630,6 +713,7 @@ static void wcd_clsh_state_ear(struct snd_soc_codec *codec,
wcd_clsh_set_buck_mode(codec, mode);
wcd_clsh_set_flyback_mode(codec, mode);
wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true);
wcd_clsh_set_flyback_current(codec, mode);
wcd_clsh_buck_ctrl(codec, clsh_d, mode, true);
} else {
snd_soc_update_bits(codec,
@ -671,6 +755,12 @@ static bool wcd_clsh_is_state_valid(u8 state)
case WCD_CLSH_STATE_HPHR:
case WCD_CLSH_STATE_HPH_ST:
case WCD_CLSH_STATE_LO:
case WCD_CLSH_STATE_HPHL_EAR:
case WCD_CLSH_STATE_HPHR_EAR:
case WCD_CLSH_STATE_HPH_ST_EAR:
case WCD_CLSH_STATE_HPHL_LO:
case WCD_CLSH_STATE_HPHR_LO:
case WCD_CLSH_STATE_HPH_ST_LO:
return true;
default:
return false;

View file

@ -45,6 +45,19 @@ static int wcd_resmgr_codec_reg_update_bits(struct wcd9xxx_resmgr_v2 *resmgr,
return change;
}
static int wcd_resmgr_codec_reg_read(struct wcd9xxx_resmgr_v2 *resmgr,
unsigned int reg)
{
int val;
if (resmgr->codec)
val = snd_soc_read(resmgr->codec, reg);
else
val = wcd9xxx_reg_read(resmgr->core_res, reg);
return val;
}
/*
* wcd_resmgr_get_clk_type()
* Returns clk type that is currently enabled
@ -185,12 +198,12 @@ static int wcd_resmgr_enable_clk_mclk(struct wcd9xxx_resmgr_v2 *resmgr)
return -EINVAL;
}
resmgr->clk_mclk_users++;
if (++resmgr->clk_mclk_users == 1) {
if ((resmgr->clk_mclk_users == 1) &&
(resmgr->clk_type == WCD_CLK_OFF)) {
wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_CLK_TOP,
0x80, 0x80);
wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_CLK_TOP,
0x08, 0x00);
wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_CLK_TOP,
0x04, 0x04);
wcd_resmgr_codec_reg_update_bits(resmgr,
@ -204,14 +217,8 @@ static int wcd_resmgr_enable_clk_mclk(struct wcd9xxx_resmgr_v2 *resmgr)
* as per HW requirement
*/
usleep_range(10, 15);
} else if ((resmgr->clk_mclk_users == 1) &&
(resmgr->clk_type == WCD_CLK_RCO)) {
/* RCO to MCLK switch */
wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_CLK_TOP,
0x80, 0x80);
wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_CLK_TOP,
0x08, 0x00);
}
resmgr->clk_type = WCD_CLK_MCLK;
pr_debug("%s: mclk_users: %d, clk_type: %s\n", __func__,
@ -228,22 +235,24 @@ static int wcd_resmgr_disable_clk_mclk(struct wcd9xxx_resmgr_v2 *resmgr)
return -EINVAL;
}
resmgr->clk_mclk_users--;
if ((resmgr->clk_mclk_users == 0) && (resmgr->clk_rco_users > 0)) {
/* MCLK to RCO switch */
wcd_resmgr_codec_reg_update_bits(resmgr,
WCD9335_ANA_CLK_TOP,
0x08, 0x08);
resmgr->clk_type = WCD_CLK_RCO;
} else if ((resmgr->clk_mclk_users == 0) &&
(resmgr->clk_rco_users == 0)) {
/* Turn off MCLK */
wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_CLK_TOP,
0x04, 0x00);
if (--resmgr->clk_mclk_users == 0) {
if (resmgr->clk_rco_users > 0) {
/* MCLK to RCO switch */
wcd_resmgr_codec_reg_update_bits(resmgr,
WCD9335_ANA_CLK_TOP,
0x08, 0x08);
resmgr->clk_type = WCD_CLK_RCO;
} else {
wcd_resmgr_codec_reg_update_bits(resmgr,
WCD9335_ANA_CLK_TOP,
0x04, 0x00);
resmgr->clk_type = WCD_CLK_OFF;
}
wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_CLK_TOP,
0x80, 0x00);
resmgr->clk_type = WCD_CLK_OFF;
}
pr_debug("%s: mclk_users: %d, clk_type: %s\n", __func__,
resmgr->clk_mclk_users,
wcd_resmgr_clk_type_to_str(resmgr->clk_type));
@ -253,6 +262,8 @@ static int wcd_resmgr_disable_clk_mclk(struct wcd9xxx_resmgr_v2 *resmgr)
static int wcd_resmgr_enable_clk_rco(struct wcd9xxx_resmgr_v2 *resmgr)
{
bool rco_cal_done = true;
resmgr->clk_rco_users++;
if ((resmgr->clk_rco_users == 1) &&
((resmgr->clk_type == WCD_CLK_OFF) ||
@ -283,9 +294,16 @@ static int wcd_resmgr_enable_clk_rco(struct wcd9xxx_resmgr_v2 *resmgr)
/* RCO Calibration */
wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_RCO,
0x04, 0x04);
wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_RCO,
0x04, 0x00);
/* RCO calibration takes app. 5ms to complete */
usleep_range(WCD9XXX_RCO_CALIBRATION_DELAY_INC_US,
WCD9XXX_RCO_CALIBRATION_DELAY_INC_US + 100);
if (wcd_resmgr_codec_reg_read(resmgr, WCD9335_ANA_RCO) & 0x02)
rco_cal_done = false;
WARN((!rco_cal_done), "RCO Calibration failed\n");
/* Switch MUX to RCO */
if (resmgr->clk_mclk_users == 1) {