ASoC: wcd934x: Add support for HPH surge recovery
Add support for headphone surge recovery (up to -80v) on wcd934x audio codec. Change-Id: Ibcf4a0be857db7054e9a95ad8f78483f4cbc6dd4 Signed-off-by: Yeleswarapu Nagaradhesh <nagaradh@codeaurora.org> Signed-off-by: Phani Kumar Uppalapati <phaniu@codeaurora.org>
This commit is contained in:
parent
46451883c7
commit
406b8c31f1
5 changed files with 364 additions and 8 deletions
|
@ -38,7 +38,7 @@
|
|||
#define WCD_MBHC_JACK_BUTTON_MASK (SND_JACK_BTN_0 | SND_JACK_BTN_1 | \
|
||||
SND_JACK_BTN_2 | SND_JACK_BTN_3 | \
|
||||
SND_JACK_BTN_4 | SND_JACK_BTN_5 )
|
||||
#define OCP_ATTEMPT 1
|
||||
#define OCP_ATTEMPT 20
|
||||
#define HS_DETECT_PLUG_TIME_MS (3 * 1000)
|
||||
#define SPECIAL_HS_DETECT_TIME_MS (2 * 1000)
|
||||
#define MBHC_BUTTON_PRESS_THRESHOLD_MIN 250
|
||||
|
@ -226,6 +226,10 @@ static const char *wcd_mbhc_get_event_string(int event)
|
|||
return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_DAPM_MICBIAS_2_OFF);
|
||||
case WCD_EVENT_PRE_DAPM_MICBIAS_2_OFF:
|
||||
return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_DAPM_MICBIAS_2_OFF);
|
||||
case WCD_EVENT_OCP_OFF:
|
||||
return WCD_MBHC_STRINGIFY(WCD_EVENT_OCP_OFF);
|
||||
case WCD_EVENT_OCP_ON:
|
||||
return WCD_MBHC_STRINGIFY(WCD_EVENT_OCP_ON);
|
||||
case WCD_EVENT_INVALID:
|
||||
default:
|
||||
return WCD_MBHC_STRINGIFY(WCD_EVENT_INVALID);
|
||||
|
@ -394,6 +398,16 @@ out_micb_en:
|
|||
/* Disable micbias, enable pullup & cs */
|
||||
wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_PULLUP);
|
||||
break;
|
||||
case WCD_EVENT_OCP_OFF:
|
||||
mbhc->mbhc_cb->irq_control(mbhc->codec,
|
||||
mbhc->intr_ids->hph_left_ocp,
|
||||
false);
|
||||
break;
|
||||
case WCD_EVENT_OCP_ON:
|
||||
mbhc->mbhc_cb->irq_control(mbhc->codec,
|
||||
mbhc->intr_ids->hph_left_ocp,
|
||||
true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -461,6 +475,7 @@ static void wcd_mbhc_clr_and_turnon_hph_padac(struct wcd_mbhc *mbhc)
|
|||
&mbhc->hph_pa_dac_state)) {
|
||||
pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
|
||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHR_PA_EN, 1);
|
||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHR_OCP_DET_EN, 1);
|
||||
pa_turned_on = true;
|
||||
}
|
||||
mutex_unlock(&mbhc->hphr_pa_lock);
|
||||
|
@ -469,6 +484,7 @@ static void wcd_mbhc_clr_and_turnon_hph_padac(struct wcd_mbhc *mbhc)
|
|||
&mbhc->hph_pa_dac_state)) {
|
||||
pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
|
||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_PA_EN, 1);
|
||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_OCP_DET_EN, 1);
|
||||
pa_turned_on = true;
|
||||
}
|
||||
mutex_unlock(&mbhc->hphl_pa_lock);
|
||||
|
@ -502,6 +518,8 @@ static void wcd_mbhc_set_and_turnoff_hph_padac(struct wcd_mbhc *mbhc)
|
|||
pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
|
||||
set_bit(WCD_MBHC_HPHL_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
|
||||
set_bit(WCD_MBHC_HPHR_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
|
||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_OCP_DET_EN, 0);
|
||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHR_OCP_DET_EN, 0);
|
||||
} else {
|
||||
pr_debug("%s PA is off\n", __func__);
|
||||
}
|
||||
|
@ -2014,13 +2032,24 @@ exit:
|
|||
static irqreturn_t wcd_mbhc_hphl_ocp_irq(int irq, void *data)
|
||||
{
|
||||
struct wcd_mbhc *mbhc = data;
|
||||
int val;
|
||||
|
||||
pr_debug("%s: received HPHL OCP irq\n", __func__);
|
||||
if (mbhc) {
|
||||
if ((mbhc->hphlocp_cnt < OCP_ATTEMPT) &&
|
||||
(!mbhc->hphrocp_cnt)) {
|
||||
pr_debug("%s: retry\n", __func__);
|
||||
if (mbhc->mbhc_cb->hph_register_recovery) {
|
||||
if (mbhc->mbhc_cb->hph_register_recovery(mbhc)) {
|
||||
WCD_MBHC_REG_READ(WCD_MBHC_HPHR_OCP_STATUS,
|
||||
val);
|
||||
if ((val != -EINVAL) && val)
|
||||
mbhc->is_hph_ocp_pending = true;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (mbhc->hphlocp_cnt < OCP_ATTEMPT) {
|
||||
mbhc->hphlocp_cnt++;
|
||||
pr_debug("%s: retry, hphlocp_cnt: %d\n", __func__,
|
||||
mbhc->hphlocp_cnt);
|
||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_OCP_FSM_EN, 0);
|
||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_OCP_FSM_EN, 1);
|
||||
} else {
|
||||
|
@ -2035,6 +2064,7 @@ static irqreturn_t wcd_mbhc_hphl_ocp_irq(int irq, void *data)
|
|||
} else {
|
||||
pr_err("%s: Bad wcd9xxx_spmi private data\n", __func__);
|
||||
}
|
||||
done:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -2043,10 +2073,26 @@ static irqreturn_t wcd_mbhc_hphr_ocp_irq(int irq, void *data)
|
|||
struct wcd_mbhc *mbhc = data;
|
||||
|
||||
pr_debug("%s: received HPHR OCP irq\n", __func__);
|
||||
if ((mbhc->hphrocp_cnt < OCP_ATTEMPT) &&
|
||||
(!mbhc->hphlocp_cnt)) {
|
||||
pr_debug("%s: retry\n", __func__);
|
||||
|
||||
if (!mbhc) {
|
||||
pr_err("%s: Bad mbhc private data\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (mbhc->is_hph_ocp_pending) {
|
||||
mbhc->is_hph_ocp_pending = false;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (mbhc->mbhc_cb->hph_register_recovery) {
|
||||
if (mbhc->mbhc_cb->hph_register_recovery(mbhc))
|
||||
/* register corruption, hence reset registers */
|
||||
goto done;
|
||||
}
|
||||
if (mbhc->hphrocp_cnt < OCP_ATTEMPT) {
|
||||
mbhc->hphrocp_cnt++;
|
||||
pr_debug("%s: retry, hphrocp_cnt: %d\n", __func__,
|
||||
mbhc->hphrocp_cnt);
|
||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_OCP_FSM_EN, 0);
|
||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_OCP_FSM_EN, 1);
|
||||
} else {
|
||||
|
@ -2057,6 +2103,7 @@ static irqreturn_t wcd_mbhc_hphr_ocp_irq(int irq, void *data)
|
|||
wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
|
||||
mbhc->hph_status, WCD_MBHC_JACK_MASK);
|
||||
}
|
||||
done:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,6 +66,10 @@ enum wcd_mbhc_register_function {
|
|||
WCD_MBHC_ANC_DET_EN,
|
||||
WCD_MBHC_FSM_STATUS,
|
||||
WCD_MBHC_MUX_CTL,
|
||||
WCD_MBHC_HPHL_OCP_DET_EN,
|
||||
WCD_MBHC_HPHR_OCP_DET_EN,
|
||||
WCD_MBHC_HPHL_OCP_STATUS,
|
||||
WCD_MBHC_HPHR_OCP_STATUS,
|
||||
WCD_MBHC_REG_FUNC_MAX,
|
||||
};
|
||||
|
||||
|
@ -127,6 +131,8 @@ enum wcd_notify_event {
|
|||
WCD_EVENT_POST_HPHR_PA_OFF,
|
||||
WCD_EVENT_PRE_HPHL_PA_OFF,
|
||||
WCD_EVENT_PRE_HPHR_PA_OFF,
|
||||
WCD_EVENT_OCP_OFF,
|
||||
WCD_EVENT_OCP_ON,
|
||||
WCD_EVENT_LAST,
|
||||
};
|
||||
|
||||
|
@ -322,6 +328,8 @@ do { \
|
|||
mbhc->wcd_mbhc_regs[function].reg)) & \
|
||||
(mbhc->wcd_mbhc_regs[function].mask)) >> \
|
||||
(mbhc->wcd_mbhc_regs[function].offset)); \
|
||||
} else { \
|
||||
val = -EINVAL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
@ -365,6 +373,7 @@ struct wcd_mbhc_cb {
|
|||
void (*mbhc_gnd_det_ctrl)(struct snd_soc_codec *, bool);
|
||||
void (*hph_pull_down_ctrl)(struct snd_soc_codec *, bool);
|
||||
void (*mbhc_moisture_config)(struct wcd_mbhc *);
|
||||
bool (*hph_register_recovery)(struct wcd_mbhc *);
|
||||
};
|
||||
|
||||
struct wcd_mbhc {
|
||||
|
@ -430,6 +439,7 @@ struct wcd_mbhc {
|
|||
struct mutex hphr_pa_lock;
|
||||
|
||||
unsigned long intr_status;
|
||||
bool is_hph_ocp_pending;
|
||||
};
|
||||
#define WCD_MBHC_CAL_SIZE(buttons, rload) ( \
|
||||
sizeof(struct wcd_mbhc_general_cfg) + \
|
||||
|
|
|
@ -118,6 +118,14 @@ static struct wcd_mbhc_register
|
|||
WCD934X_MBHC_STATUS_SPARE_1, 0x01, 0, 0),
|
||||
WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL",
|
||||
WCD934X_MBHC_NEW_CTL_2, 0x70, 4, 0),
|
||||
WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_DET_EN",
|
||||
WCD934X_HPH_L_TEST, 0x01, 0, 0),
|
||||
WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_DET_EN",
|
||||
WCD934X_HPH_R_TEST, 0x01, 0, 0),
|
||||
WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_STATUS",
|
||||
WCD934X_INTR_PIN1_STATUS0, 0x04, 2, 0),
|
||||
WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_STATUS",
|
||||
WCD934X_INTR_PIN1_STATUS0, 0x08, 3, 0),
|
||||
};
|
||||
|
||||
static const struct wcd_mbhc_intr intr_ids = {
|
||||
|
@ -778,6 +786,26 @@ static void tavil_mbhc_moisture_config(struct wcd_mbhc *mbhc)
|
|||
0x0C, TAVIL_MBHC_MOISTURE_RREF << 2);
|
||||
}
|
||||
|
||||
static bool tavil_hph_register_recovery(struct wcd_mbhc *mbhc)
|
||||
{
|
||||
struct snd_soc_codec *codec = mbhc->codec;
|
||||
struct wcd934x_mbhc *wcd934x_mbhc = tavil_soc_get_mbhc(codec);
|
||||
|
||||
if (!wcd934x_mbhc)
|
||||
return false;
|
||||
|
||||
wcd934x_mbhc->is_hph_recover = false;
|
||||
snd_soc_dapm_force_enable_pin(snd_soc_codec_get_dapm(codec),
|
||||
"RESET_HPH_REGISTERS");
|
||||
snd_soc_dapm_sync(snd_soc_codec_get_dapm(codec));
|
||||
|
||||
snd_soc_dapm_disable_pin(snd_soc_codec_get_dapm(codec),
|
||||
"RESET_HPH_REGISTERS");
|
||||
snd_soc_dapm_sync(snd_soc_codec_get_dapm(codec));
|
||||
|
||||
return wcd934x_mbhc->is_hph_recover;
|
||||
}
|
||||
|
||||
static const struct wcd_mbhc_cb mbhc_cb = {
|
||||
.request_irq = tavil_mbhc_request_irq,
|
||||
.irq_control = tavil_mbhc_irq_control,
|
||||
|
@ -800,6 +828,7 @@ static const struct wcd_mbhc_cb mbhc_cb = {
|
|||
.mbhc_gnd_det_ctrl = tavil_mbhc_gnd_det_ctrl,
|
||||
.hph_pull_down_ctrl = tavil_mbhc_hph_pull_down_ctrl,
|
||||
.mbhc_moisture_config = tavil_mbhc_moisture_config,
|
||||
.hph_register_recovery = tavil_hph_register_recovery,
|
||||
};
|
||||
|
||||
static struct regulator *tavil_codec_find_ondemand_regulator(
|
||||
|
|
|
@ -32,6 +32,7 @@ struct wcd934x_mbhc {
|
|||
struct wcd9xxx *wcd9xxx;
|
||||
struct fw_info *fw_data;
|
||||
bool mbhc_started;
|
||||
bool is_hph_recover;
|
||||
};
|
||||
|
||||
extern int tavil_mbhc_init(struct wcd934x_mbhc **mbhc,
|
||||
|
|
|
@ -141,6 +141,14 @@ static const struct snd_kcontrol_new name##_mux = \
|
|||
|
||||
#define TAVIL_VERSION_ENTRY_SIZE 17
|
||||
|
||||
#define TAVIL_HPH_REG_RANGE_1 (WCD934X_HPH_R_DAC_CTL - WCD934X_HPH_CNP_EN + 1)
|
||||
#define TAVIL_HPH_REG_RANGE_2 (WCD934X_HPH_NEW_ANA_HPH3 -\
|
||||
WCD934X_HPH_NEW_ANA_HPH2 + 1)
|
||||
#define TAVIL_HPH_REG_RANGE_3 (WCD934X_HPH_NEW_INT_PA_RDAC_MISC3 -\
|
||||
WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL + 1)
|
||||
#define TAVIL_HPH_TOTAL_REG (TAVIL_HPH_REG_RANGE_1 + TAVIL_HPH_REG_RANGE_2 +\
|
||||
TAVIL_HPH_REG_RANGE_3)
|
||||
|
||||
enum {
|
||||
VI_SENSE_1,
|
||||
VI_SENSE_2,
|
||||
|
@ -1781,6 +1789,9 @@ static int tavil_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
|
|||
usleep_range(7000, 7100);
|
||||
clear_bit(HPH_PA_DELAY, &tavil->status_mask);
|
||||
}
|
||||
|
||||
snd_soc_update_bits(codec, WCD934X_HPH_R_TEST, 0x01, 0x01);
|
||||
|
||||
/* Remove mute */
|
||||
snd_soc_update_bits(codec, WCD934X_CDC_RX2_RX_PATH_CTL,
|
||||
0x10, 0x00);
|
||||
|
@ -1815,6 +1826,9 @@ static int tavil_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
|
|||
(snd_soc_read(codec, WCD934X_CDC_DSD1_PATH_CTL) & 0x01))
|
||||
snd_soc_update_bits(codec, WCD934X_CDC_DSD1_CFG2,
|
||||
0x04, 0x04);
|
||||
snd_soc_update_bits(codec, WCD934X_HPH_R_TEST, 0x01, 0x00);
|
||||
snd_soc_update_bits(codec, WCD934X_CDC_RX2_RX_PATH_CTL,
|
||||
0x10, 0x10);
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
/* 5ms sleep is required after PA disable */
|
||||
|
@ -1856,6 +1870,7 @@ static int tavil_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
|
|||
usleep_range(7000, 7100);
|
||||
clear_bit(HPH_PA_DELAY, &tavil->status_mask);
|
||||
}
|
||||
snd_soc_update_bits(codec, WCD934X_HPH_L_TEST, 0x01, 0x01);
|
||||
/* Remove Mute on primary path */
|
||||
snd_soc_update_bits(codec, WCD934X_CDC_RX1_RX_PATH_CTL,
|
||||
0x10, 0x00);
|
||||
|
@ -1890,6 +1905,10 @@ static int tavil_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
|
|||
(snd_soc_read(codec, WCD934X_CDC_DSD0_PATH_CTL) & 0x01))
|
||||
snd_soc_update_bits(codec, WCD934X_CDC_DSD0_CFG2,
|
||||
0x04, 0x04);
|
||||
|
||||
snd_soc_update_bits(codec, WCD934X_HPH_L_TEST, 0x01, 0x00);
|
||||
snd_soc_update_bits(codec, WCD934X_CDC_RX1_RX_PATH_CTL,
|
||||
0x10, 0x10);
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
/* 5ms sleep is required after PA disable */
|
||||
|
@ -4122,6 +4141,244 @@ static int tavil_codec_enable_micbias(struct snd_soc_dapm_widget *w,
|
|||
return __tavil_codec_enable_micbias(w, event);
|
||||
}
|
||||
|
||||
|
||||
static const struct reg_sequence tavil_hph_reset_tbl[] = {
|
||||
{ WCD934X_HPH_CNP_EN, 0x80 },
|
||||
{ WCD934X_HPH_CNP_WG_CTL, 0x9A },
|
||||
{ WCD934X_HPH_CNP_WG_TIME, 0x14 },
|
||||
{ WCD934X_HPH_OCP_CTL, 0x28 },
|
||||
{ WCD934X_HPH_AUTO_CHOP, 0x16 },
|
||||
{ WCD934X_HPH_CHOP_CTL, 0x83 },
|
||||
{ WCD934X_HPH_PA_CTL1, 0x46 },
|
||||
{ WCD934X_HPH_PA_CTL2, 0x50 },
|
||||
{ WCD934X_HPH_L_EN, 0x80 },
|
||||
{ WCD934X_HPH_L_TEST, 0xE0 },
|
||||
{ WCD934X_HPH_L_ATEST, 0x50 },
|
||||
{ WCD934X_HPH_R_EN, 0x80 },
|
||||
{ WCD934X_HPH_R_TEST, 0xE0 },
|
||||
{ WCD934X_HPH_R_ATEST, 0x54 },
|
||||
{ WCD934X_HPH_RDAC_CLK_CTL1, 0x99 },
|
||||
{ WCD934X_HPH_RDAC_CLK_CTL2, 0x9B },
|
||||
{ WCD934X_HPH_RDAC_LDO_CTL, 0x33 },
|
||||
{ WCD934X_HPH_RDAC_CHOP_CLK_LP_CTL, 0x00 },
|
||||
{ WCD934X_HPH_REFBUFF_UHQA_CTL, 0xA8 },
|
||||
{ WCD934X_HPH_REFBUFF_LP_CTL, 0x0A },
|
||||
{ WCD934X_HPH_L_DAC_CTL, 0x00 },
|
||||
{ WCD934X_HPH_R_DAC_CTL, 0x00 },
|
||||
{ WCD934X_HPH_NEW_ANA_HPH2, 0x00 },
|
||||
{ WCD934X_HPH_NEW_ANA_HPH3, 0x00 },
|
||||
{ WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, 0x00 },
|
||||
{ WCD934X_HPH_NEW_INT_RDAC_HD2_CTL, 0xA0 },
|
||||
{ WCD934X_HPH_NEW_INT_RDAC_VREF_CTL, 0x10 },
|
||||
{ WCD934X_HPH_NEW_INT_RDAC_OVERRIDE_CTL, 0x00 },
|
||||
{ WCD934X_HPH_NEW_INT_RDAC_MISC1, 0x00 },
|
||||
{ WCD934X_HPH_NEW_INT_PA_MISC1, 0x22 },
|
||||
{ WCD934X_HPH_NEW_INT_PA_MISC2, 0x00 },
|
||||
{ WCD934X_HPH_NEW_INT_PA_RDAC_MISC, 0x00 },
|
||||
{ WCD934X_HPH_NEW_INT_HPH_TIMER1, 0xFE },
|
||||
{ WCD934X_HPH_NEW_INT_HPH_TIMER2, 0x2 },
|
||||
{ WCD934X_HPH_NEW_INT_HPH_TIMER3, 0x4e},
|
||||
{ WCD934X_HPH_NEW_INT_HPH_TIMER4, 0x54 },
|
||||
{ WCD934X_HPH_NEW_INT_PA_RDAC_MISC2, 0x00 },
|
||||
{ WCD934X_HPH_NEW_INT_PA_RDAC_MISC3, 0x00 },
|
||||
};
|
||||
|
||||
static const struct tavil_reg_mask_val tavil_pa_disable[] = {
|
||||
{ WCD934X_CDC_RX1_RX_PATH_CTL, 0x30, 0x10 }, /* RX1 mute enable */
|
||||
{ WCD934X_CDC_RX2_RX_PATH_CTL, 0x30, 0x10 }, /* RX2 mute enable */
|
||||
{ WCD934X_HPH_CNP_WG_CTL, 0x80, 0x00 }, /* GM3 boost disable */
|
||||
{ WCD934X_ANA_HPH, 0x80, 0x00 }, /* HPHL PA disable */
|
||||
{ WCD934X_ANA_HPH, 0x40, 0x00 }, /* HPHR PA disable */
|
||||
{ WCD934X_ANA_HPH, 0x20, 0x00 }, /* HPHL REF dsable */
|
||||
{ WCD934X_ANA_HPH, 0x10, 0x00 }, /* HPHR REF disable */
|
||||
};
|
||||
|
||||
static const struct tavil_reg_mask_val tavil_ocp_en_seq[] = {
|
||||
{ WCD934X_RX_OCP_CTL, 0x0F, 0x01 }, /* OCP number of attempts is 1 */
|
||||
{ WCD934X_HPH_OCP_CTL, 0xFA, 0x3A }, /* OCP current limit */
|
||||
{ WCD934X_HPH_L_TEST, 0x01, 0x01 }, /* Enable HPHL OCP */
|
||||
{ WCD934X_HPH_R_TEST, 0x01, 0x01 }, /* Enable HPHR OCP */
|
||||
};
|
||||
|
||||
static const struct tavil_reg_mask_val tavil_ocp_en_seq_1[] = {
|
||||
{ WCD934X_RX_OCP_CTL, 0x0F, 0x01 }, /* OCP number of attempts is 1 */
|
||||
{ WCD934X_HPH_OCP_CTL, 0xFA, 0x3A }, /* OCP current limit */
|
||||
};
|
||||
|
||||
/* LO-HIFI */
|
||||
static const struct tavil_reg_mask_val tavil_pre_pa_en_lohifi[] = {
|
||||
{ WCD934X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x00 },
|
||||
{ WCD934X_HPH_NEW_INT_PA_MISC2, 0x20, 0x20 },
|
||||
{ WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, 0xf0, 0x40 },
|
||||
{ WCD934X_HPH_CNP_WG_CTL, 0x80, 0x00 },
|
||||
{ WCD934X_RX_BIAS_HPH_LOWPOWER, 0xf0, 0xc0 },
|
||||
{ WCD934X_HPH_PA_CTL1, 0x0e, 0x02 },
|
||||
{ WCD934X_HPH_REFBUFF_LP_CTL, 0x06, 0x06 },
|
||||
};
|
||||
|
||||
static const struct tavil_reg_mask_val tavil_pre_pa_en[] = {
|
||||
{ WCD934X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x00 },
|
||||
{ WCD934X_HPH_NEW_INT_PA_MISC2, 0x20, 0x0 },
|
||||
{ WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, 0xf0, 0x40 },
|
||||
{ WCD934X_HPH_CNP_WG_CTL, 0x80, 0x00 },
|
||||
{ WCD934X_RX_BIAS_HPH_LOWPOWER, 0xf0, 0x80 },
|
||||
{ WCD934X_HPH_PA_CTL1, 0x0e, 0x06 },
|
||||
{ WCD934X_HPH_REFBUFF_LP_CTL, 0x06, 0x06 },
|
||||
};
|
||||
|
||||
static const struct tavil_reg_mask_val tavil_post_pa_en[] = {
|
||||
{ WCD934X_HPH_L_TEST, 0x01, 0x01 }, /* Enable HPHL OCP */
|
||||
{ WCD934X_HPH_R_TEST, 0x01, 0x01 }, /* Enable HPHR OCP */
|
||||
{ WCD934X_CDC_RX1_RX_PATH_CTL, 0x30, 0x20 }, /* RX1 mute disable */
|
||||
{ WCD934X_CDC_RX2_RX_PATH_CTL, 0x30, 0x20 }, /* RX2 mute disable */
|
||||
{ WCD934X_HPH_CNP_WG_CTL, 0x80, 0x80 }, /* GM3 boost enable */
|
||||
{ WCD934X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x02 },
|
||||
};
|
||||
|
||||
static void tavil_codec_hph_reg_range_read(struct regmap *map, u8 *buf)
|
||||
{
|
||||
regmap_bulk_read(map, WCD934X_HPH_CNP_EN, buf, TAVIL_HPH_REG_RANGE_1);
|
||||
regmap_bulk_read(map, WCD934X_HPH_NEW_ANA_HPH2,
|
||||
buf + TAVIL_HPH_REG_RANGE_1, TAVIL_HPH_REG_RANGE_2);
|
||||
regmap_bulk_read(map, WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL,
|
||||
buf + TAVIL_HPH_REG_RANGE_1 + TAVIL_HPH_REG_RANGE_2,
|
||||
TAVIL_HPH_REG_RANGE_3);
|
||||
}
|
||||
|
||||
static void tavil_codec_hph_reg_recover(struct tavil_priv *tavil,
|
||||
struct regmap *map, int pa_status)
|
||||
{
|
||||
int i;
|
||||
|
||||
blocking_notifier_call_chain(&tavil->mbhc->notifier,
|
||||
WCD_EVENT_OCP_OFF,
|
||||
&tavil->mbhc->wcd_mbhc);
|
||||
|
||||
if (pa_status & 0xC0)
|
||||
goto pa_en_restore;
|
||||
|
||||
dev_dbg(tavil->dev, "%s: HPH PA in disable state (0x%x)\n",
|
||||
__func__, pa_status);
|
||||
|
||||
regmap_write_bits(map, WCD934X_CDC_RX1_RX_PATH_CTL, 0x10, 0x10);
|
||||
regmap_write_bits(map, WCD934X_CDC_RX2_RX_PATH_CTL, 0x10, 0x10);
|
||||
regmap_write_bits(map, WCD934X_ANA_HPH, 0xC0, 0x00);
|
||||
regmap_write_bits(map, WCD934X_ANA_HPH, 0x30, 0x00);
|
||||
regmap_write_bits(map, WCD934X_CDC_RX1_RX_PATH_CTL, 0x10, 0x00);
|
||||
regmap_write_bits(map, WCD934X_CDC_RX2_RX_PATH_CTL, 0x10, 0x00);
|
||||
|
||||
/* Restore to HW defaults */
|
||||
regmap_multi_reg_write(map, tavil_hph_reset_tbl,
|
||||
ARRAY_SIZE(tavil_hph_reset_tbl));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tavil_ocp_en_seq); i++)
|
||||
regmap_write_bits(map, tavil_ocp_en_seq[i].reg,
|
||||
tavil_ocp_en_seq[i].mask,
|
||||
tavil_ocp_en_seq[i].val);
|
||||
goto end;
|
||||
|
||||
|
||||
pa_en_restore:
|
||||
dev_dbg(tavil->dev, "%s: HPH PA in enable state (0x%x)\n",
|
||||
__func__, pa_status);
|
||||
|
||||
/* Disable PA and other registers before restoring */
|
||||
for (i = 0; i < ARRAY_SIZE(tavil_pa_disable); i++)
|
||||
regmap_write_bits(map, tavil_pa_disable[i].reg,
|
||||
tavil_pa_disable[i].mask,
|
||||
tavil_pa_disable[i].val);
|
||||
|
||||
regmap_multi_reg_write(map, tavil_hph_reset_tbl,
|
||||
ARRAY_SIZE(tavil_hph_reset_tbl));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tavil_ocp_en_seq_1); i++)
|
||||
regmap_write_bits(map, tavil_ocp_en_seq_1[i].reg,
|
||||
tavil_ocp_en_seq_1[i].mask,
|
||||
tavil_ocp_en_seq_1[i].val);
|
||||
|
||||
if (tavil->hph_mode == CLS_H_LOHIFI) {
|
||||
for (i = 0; i < ARRAY_SIZE(tavil_pre_pa_en_lohifi); i++)
|
||||
regmap_write_bits(map,
|
||||
tavil_pre_pa_en_lohifi[i].reg,
|
||||
tavil_pre_pa_en_lohifi[i].mask,
|
||||
tavil_pre_pa_en_lohifi[i].val);
|
||||
} else {
|
||||
for (i = 0; i < ARRAY_SIZE(tavil_pre_pa_en); i++)
|
||||
regmap_write_bits(map, tavil_pre_pa_en[i].reg,
|
||||
tavil_pre_pa_en[i].mask,
|
||||
tavil_pre_pa_en[i].val);
|
||||
}
|
||||
regmap_write_bits(map, WCD934X_ANA_HPH, 0x0C, pa_status & 0x0C);
|
||||
regmap_write_bits(map, WCD934X_ANA_HPH, 0x30, 0x30);
|
||||
/* wait for 100usec after HPH DAC is enabled */
|
||||
usleep_range(100, 110);
|
||||
regmap_write(map, WCD934X_ANA_HPH, pa_status);
|
||||
/* Sleep for 7msec after PA is enabled */
|
||||
usleep_range(7000, 7100);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tavil_post_pa_en); i++)
|
||||
regmap_write_bits(map, tavil_post_pa_en[i].reg,
|
||||
tavil_post_pa_en[i].mask,
|
||||
tavil_post_pa_en[i].val);
|
||||
|
||||
end:
|
||||
tavil->mbhc->is_hph_recover = true;
|
||||
blocking_notifier_call_chain(
|
||||
&tavil->mbhc->notifier,
|
||||
WCD_EVENT_OCP_ON,
|
||||
&tavil->mbhc->wcd_mbhc);
|
||||
}
|
||||
|
||||
static int tavil_codec_reset_hph_registers(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
|
||||
struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
|
||||
u8 cache_val[TAVIL_HPH_TOTAL_REG];
|
||||
u8 hw_val[TAVIL_HPH_TOTAL_REG];
|
||||
int pa_status;
|
||||
int ret;
|
||||
|
||||
dev_dbg(wcd9xxx->dev, "%s: event: %d\n", __func__, event);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
memset(cache_val, 0, TAVIL_HPH_TOTAL_REG);
|
||||
memset(hw_val, 0, TAVIL_HPH_TOTAL_REG);
|
||||
|
||||
regmap_read(wcd9xxx->regmap, WCD934X_ANA_HPH, &pa_status);
|
||||
|
||||
tavil_codec_hph_reg_range_read(wcd9xxx->regmap, cache_val);
|
||||
|
||||
/* Read register values from HW directly */
|
||||
regcache_cache_bypass(wcd9xxx->regmap, true);
|
||||
tavil_codec_hph_reg_range_read(wcd9xxx->regmap, hw_val);
|
||||
regcache_cache_bypass(wcd9xxx->regmap, false);
|
||||
|
||||
/* compare both the registers to know if there is corruption */
|
||||
ret = memcmp(cache_val, hw_val, TAVIL_HPH_TOTAL_REG);
|
||||
|
||||
/* If both the values are same, it means no corruption */
|
||||
if (ret) {
|
||||
dev_dbg(codec->dev, "%s: cache and hw reg are not same\n",
|
||||
__func__);
|
||||
tavil_codec_hph_reg_recover(tavil, wcd9xxx->regmap,
|
||||
pa_status);
|
||||
} else {
|
||||
dev_dbg(codec->dev, "%s: cache and hw reg are same\n",
|
||||
__func__);
|
||||
tavil->mbhc->is_hph_recover = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tavil_iir_enable_audio_mixer_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
|
@ -6152,6 +6409,14 @@ static const struct snd_soc_dapm_widget tavil_dapm_widgets[] = {
|
|||
tavil_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
|
||||
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
|
||||
/*
|
||||
* Not supply widget, this is used to recover HPH registers.
|
||||
* It is not connected to any other widgets
|
||||
*/
|
||||
SND_SOC_DAPM_SUPPLY("RESET_HPH_REGISTERS", SND_SOC_NOPM,
|
||||
0, 0, tavil_codec_reset_hph_registers,
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
|
||||
SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS1_STANDALONE, SND_SOC_NOPM, 0, 0,
|
||||
tavil_codec_force_enable_micbias,
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
|
@ -7340,6 +7605,10 @@ static const struct tavil_reg_mask_val tavil_codec_reg_defaults[] = {
|
|||
{WCD934X_CDC_TX6_TX_PATH_CFG1, 0x01, 0x00},
|
||||
{WCD934X_CDC_TX7_TX_PATH_CFG1, 0x01, 0x00},
|
||||
{WCD934X_CDC_TX8_TX_PATH_CFG1, 0x01, 0x00},
|
||||
{WCD934X_RX_OCP_CTL, 0x0F, 0x01}, /* OCP number of attempts is 1 */
|
||||
{WCD934X_HPH_OCP_CTL, 0xFF, 0x3A}, /* OCP current limit */
|
||||
{WCD934X_HPH_L_TEST, 0x01, 0x01},
|
||||
{WCD934X_HPH_R_TEST, 0x01, 0x01},
|
||||
};
|
||||
|
||||
static const struct tavil_reg_mask_val tavil_codec_reg_init_common_val[] = {
|
||||
|
|
Loading…
Add table
Reference in a new issue