Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 95288c59 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "ASoC: wcd9335: Update low hifi and low power modes for headphones"

parents 6a755854 912459be
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -340,4 +340,5 @@
#define WCD9XXX_CDC_RX1_RX_PATH_CTL			(0xB55)
#define WCD9XXX_CDC_RX2_RX_PATH_CTL			(0xB69)
#define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_CONTROL		(0xD41)
#define WCD9XXX_CLASSH_CTRL_CCL_1                       (0x69C)
#endif
+183 −18
Original line number Diff line number Diff line
@@ -335,6 +335,7 @@ enum {
	AIF4_SWITCH_VALUE,
	AUDIO_NOMINAL,
	CPE_NOMINAL,
	HPH_PA_DELAY,
};

enum {
@@ -757,6 +758,8 @@ struct tasha_priv {
	int spkr_mode;
	struct hpf_work tx_hpf_work[TASHA_NUM_DECIMATORS];
	struct tx_mute_work tx_mute_dwork[TASHA_NUM_DECIMATORS];
	int hph_l_gain;
	int hph_r_gain;
};

static int tasha_codec_vote_max_bw(struct snd_soc_codec *codec,
@@ -3518,22 +3521,80 @@ err:
	return ret;
}

static void tasha_codec_hph_post_pa_config(struct tasha_priv *tasha,
					   int mode, int event)
{
	u8 scale_val = 0;

	if (!TASHA_IS_2_0(tasha->wcd9xxx->version))
		return;

	switch (event) {
	case SND_SOC_DAPM_POST_PMU:
		switch (mode) {
		case CLS_H_HIFI:
			scale_val = 0x3;
			break;
		case CLS_H_LOHIFI:
			scale_val = 0x1;
			break;
		}
		break;
	case SND_SOC_DAPM_PRE_PMD:
		scale_val = 0x6;
		break;
	}

	if (scale_val)
		snd_soc_update_bits(tasha->codec, WCD9335_HPH_PA_CTL1, 0x0E,
				    scale_val << 1);
	if (SND_SOC_DAPM_EVENT_ON(event)) {
		if (tasha->comp_enabled[COMPANDER_1] ||
		    tasha->comp_enabled[COMPANDER_2]) {
			snd_soc_update_bits(tasha->codec, WCD9335_HPH_L_EN,
					    0x20, 0x00);
			snd_soc_update_bits(tasha->codec, WCD9335_HPH_R_EN,
					    0x20, 0x00);
			snd_soc_update_bits(tasha->codec, WCD9335_HPH_AUTO_CHOP,
					    0x20, 0x20);
		}
		snd_soc_update_bits(tasha->codec, WCD9335_HPH_L_EN, 0x1F,
				    tasha->hph_l_gain);
		snd_soc_update_bits(tasha->codec, WCD9335_HPH_R_EN, 0x1F,
				    tasha->hph_r_gain);
	}

	if (SND_SOC_DAPM_EVENT_OFF(event)) {
		snd_soc_update_bits(tasha->codec, WCD9335_HPH_AUTO_CHOP, 0x20,
				    0x00);
	}
}

static int tasha_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
				      struct snd_kcontrol *kcontrol,
				      int event)
{
	struct snd_soc_codec *codec = w->codec;
	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
	int hph_mode = tasha->hph_mode;
	int ret = 0;

	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);

	switch (event) {
	case SND_SOC_DAPM_PRE_PMU:
		set_bit(HPH_PA_DELAY, &tasha->status_mask);
		break;
	case SND_SOC_DAPM_POST_PMU:
		/* 5ms sleep is required after PA is enabled as per
		/*
		 * 7ms sleep is required after PA is enabled as per
		 * HW requirement
		 */
		usleep_range(5000, 5500);
		if (test_bit(HPH_PA_DELAY, &tasha->status_mask)) {
			usleep_range(7000, 7100);
			clear_bit(HPH_PA_DELAY, &tasha->status_mask);
		}
		tasha_codec_hph_post_pa_config(tasha, hph_mode, event);
		snd_soc_update_bits(codec, WCD9335_CDC_RX2_RX_PATH_CTL,
				    0x10, 0x00);
		/* Remove mix path mute if it is enabled */
@@ -3547,6 +3608,7 @@ static int tasha_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
		blocking_notifier_call_chain(&tasha->notifier,
					WCD_EVENT_PRE_HPHR_PA_OFF,
					&tasha->mbhc);
		tasha_codec_hph_post_pa_config(tasha, hph_mode, event);
		break;
	case SND_SOC_DAPM_POST_PMD:
		/* 5ms sleep is required after PA is disabled as per
@@ -3574,16 +3636,26 @@ static int tasha_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
{
	struct snd_soc_codec *codec = w->codec;
	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
	int hph_mode = tasha->hph_mode;
	int ret = 0;

	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);

	switch (event) {
	case SND_SOC_DAPM_PRE_PMU:
		set_bit(HPH_PA_DELAY, &tasha->status_mask);
		break;
	case SND_SOC_DAPM_POST_PMU:
		/* 5ms sleep is required after PA is enabled as per
		/*
		 * 7ms sleep is required after PA is enabled as per
		 * HW requirement
		 */
		usleep_range(5000, 5500);
		if (test_bit(HPH_PA_DELAY, &tasha->status_mask)) {
			usleep_range(7000, 7100);
			clear_bit(HPH_PA_DELAY, &tasha->status_mask);
		}

		tasha_codec_hph_post_pa_config(tasha, hph_mode, event);
		snd_soc_update_bits(codec, WCD9335_CDC_RX1_RX_PATH_CTL,
				    0x10, 0x00);
		/* Remove mix path mute if it is enabled */
@@ -3597,6 +3669,7 @@ static int tasha_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
		blocking_notifier_call_chain(&tasha->notifier,
					WCD_EVENT_PRE_HPHL_PA_OFF,
					&tasha->mbhc);
		tasha_codec_hph_post_pa_config(tasha, hph_mode, event);
		break;
	case SND_SOC_DAPM_POST_PMD:
		/* 5ms sleep is required after PA is disabled as per
@@ -3726,32 +3799,70 @@ static int tasha_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
	return ret;
}

static void tasha_codec_hph_mode_gain_opt(struct snd_soc_codec *codec,
					  u8 gain)
{
	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
	u8 hph_l_en, hph_r_en;
	u8 l_val, r_val;
	u8 hph_pa_status;
	bool is_hphl_pa, is_hphr_pa;

	hph_pa_status = snd_soc_read(codec, WCD9335_ANA_HPH);
	is_hphl_pa = hph_pa_status >> 7;
	is_hphr_pa = (hph_pa_status & 0x40) >> 6;

	hph_l_en = snd_soc_read(codec, WCD9335_HPH_L_EN);
	hph_r_en = snd_soc_read(codec, WCD9335_HPH_R_EN);

	l_val = (hph_l_en & 0xC0) | 0x20 | gain;
	r_val = (hph_r_en & 0xC0) | 0x20 | gain;

	/*
	 * Set HPH_L & HPH_R gain source selection to REGISTER
	 * for better click and pop only if corresponding PAs are
	 * not enabled. Also cache the values of the HPHL/R
	 * PA gains to be applied after PAs are enabled
	 */
	if ((l_val != hph_l_en) && !is_hphl_pa) {
		snd_soc_write(codec, WCD9335_HPH_L_EN, l_val);
		tasha->hph_l_gain = hph_l_en & 0x1F;
	}

	if ((r_val != hph_r_en) && !is_hphr_pa) {
		snd_soc_write(codec, WCD9335_HPH_R_EN, r_val);
		tasha->hph_r_gain = hph_r_en & 0x1F;
	}
}

static void tasha_codec_hph_lohifi_config(struct snd_soc_codec *codec,
					  struct tasha_priv *tasha,
					  int event)
{
	if (SND_SOC_DAPM_EVENT_ON(event)) {
		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL1, 0x0E, 0x02);
		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x08, 0x08);
		snd_soc_update_bits(codec, WCD9335_RX_BIAS_HPH_PA, 0x0F, 0x06);
		snd_soc_update_bits(codec, WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2,
				    0xF0, 0x40);
		snd_soc_update_bits(codec, WCD9335_HPH_CNP_WG_CTL, 0x07, 0x03);
		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x08, 0x08);
		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL1, 0x0E, 0x0C);
		tasha_codec_hph_mode_gain_opt(codec, 0x11);
	}

	if (SND_SOC_DAPM_EVENT_OFF(event)) {
		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x08, 0x00);
		snd_soc_update_bits(codec, WCD9335_HPH_CNP_WG_CTL, 0x07, 0x02);
		snd_soc_write(codec, WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2, 0x8A);
		snd_soc_update_bits(codec, WCD9335_RX_BIAS_HPH_PA, 0x0F, 0x0A);
		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL1, 0x0E, 0x06);
		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x08, 0x00);
	}
}

static void tasha_codec_hph_lp_config(struct snd_soc_codec *codec,
				      struct tasha_priv *tasha,
				      int event)
{
	if (SND_SOC_DAPM_EVENT_ON(event)) {
		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL1, 0x0E, 0x0C);
		tasha_codec_hph_mode_gain_opt(codec, 0x10);
		snd_soc_update_bits(codec, WCD9335_HPH_CNP_WG_CTL, 0x07, 0x03);
		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x08, 0x08);
		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x04, 0x04);
		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x20, 0x20);
@@ -3766,14 +3877,30 @@ static void tasha_codec_hph_lp_config(struct snd_soc_codec *codec,
	}

	if (SND_SOC_DAPM_EVENT_OFF(event)) {
		snd_soc_update_bits(codec, WCD9335_HPH_R_EN, 0xC0, 0x80);
		snd_soc_update_bits(codec, WCD9335_HPH_L_EN, 0xC0, 0x80);
		snd_soc_write(codec, WCD9335_RX_BIAS_HPH_RDAC_LDO, 0x88);
		snd_soc_write(codec, WCD9335_HPH_RDAC_LDO_CTL, 0x33);
		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x20, 0x00);
		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x04, 0x00);
		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x08, 0x00);
		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL1, 0x0E, 0x06);
		snd_soc_update_bits(codec, WCD9335_HPH_CNP_WG_CTL, 0x07, 0x02);
		snd_soc_update_bits(codec, WCD9335_HPH_R_EN, 0xC0, 0x80);
		snd_soc_update_bits(codec, WCD9335_HPH_L_EN, 0xC0, 0x80);
	}
}

static void tasha_codec_hph_hifi_config(struct snd_soc_codec *codec,
					int event)
{
	if (SND_SOC_DAPM_EVENT_ON(event)) {
		snd_soc_update_bits(codec, WCD9335_HPH_CNP_WG_CTL, 0x07, 0x03);
		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x08, 0x08);
		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL1, 0x0E, 0x0C);
		tasha_codec_hph_mode_gain_opt(codec, 0x11);
	}

	if (SND_SOC_DAPM_EVENT_OFF(event)) {
		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x08, 0x00);
		snd_soc_update_bits(codec, WCD9335_HPH_CNP_WG_CTL, 0x07, 0x02);
	}
}

@@ -3787,10 +3914,13 @@ static void tasha_codec_hph_mode_config(struct snd_soc_codec *codec,

	switch (mode) {
	case CLS_H_LP:
		tasha_codec_hph_lp_config(codec, tasha, event);
		tasha_codec_hph_lp_config(codec, event);
		break;
	case CLS_H_LOHIFI:
		tasha_codec_hph_lohifi_config(codec, tasha, event);
		tasha_codec_hph_lohifi_config(codec, event);
		break;
	case CLS_H_HIFI:
		tasha_codec_hph_hifi_config(codec, event);
		break;
	}
}
@@ -4127,6 +4257,38 @@ static u16 tasha_interp_get_primary_reg(u16 reg, u16 *ind)
	return prim_int_reg;
}

static void tasha_codec_hd2_control(struct snd_soc_codec *codec,
				    u16 prim_int_reg, int event)
{
	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
	u16 hd2_scale_reg;
	u16 hd2_enable_reg = 0;

	if (!TASHA_IS_2_0(tasha->wcd9xxx->version))
		return;

	if (prim_int_reg == WCD9335_CDC_RX1_RX_PATH_CTL) {
		hd2_scale_reg = WCD9335_CDC_RX1_RX_PATH_SEC3;
		hd2_enable_reg = WCD9335_CDC_RX1_RX_PATH_CFG0;
	}
	if (prim_int_reg == WCD9335_CDC_RX2_RX_PATH_CTL) {
		hd2_scale_reg = WCD9335_CDC_RX2_RX_PATH_SEC3;
		hd2_enable_reg = WCD9335_CDC_RX2_RX_PATH_CFG0;
	}

	if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) {
		snd_soc_update_bits(codec, hd2_scale_reg, 0x3C, 0x10);
		snd_soc_update_bits(codec, hd2_scale_reg, 0x03, 0x01);
		snd_soc_update_bits(codec, hd2_enable_reg, 0x04, 0x04);
	}

	if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) {
		snd_soc_update_bits(codec, hd2_enable_reg, 0x04, 0x00);
		snd_soc_update_bits(codec, hd2_scale_reg, 0x03, 0x00);
		snd_soc_update_bits(codec, hd2_scale_reg, 0x3C, 0x00);
	}
}

static int tasha_codec_enable_prim_interpolator(
				struct snd_soc_codec *codec,
				u16 reg, int event)
@@ -4143,6 +4305,7 @@ static int tasha_codec_enable_prim_interpolator(
		if (tasha->prim_int_users[ind] == 1) {
			snd_soc_update_bits(codec, prim_int_reg,
					    0x10, 0x10);
			tasha_codec_hd2_control(codec, prim_int_reg, event);
			snd_soc_update_bits(codec, prim_int_reg,
					    1 << 0x5, 1 << 0x5);
		}
@@ -4159,6 +4322,7 @@ static int tasha_codec_enable_prim_interpolator(
					0x40, 0x40);
			snd_soc_update_bits(codec, prim_int_reg,
					0x40, 0x00);
			tasha_codec_hd2_control(codec, prim_int_reg, event);
		}
		break;
	};
@@ -9749,11 +9913,11 @@ static const struct snd_soc_dapm_widget tasha_dapm_widgets[] = {
			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
	SND_SOC_DAPM_PGA_E("ANC HPHL PA", WCD9335_ANA_HPH, 7, 0, NULL, 0,
			   tasha_codec_enable_hphl_pa,
			   SND_SOC_DAPM_POST_PMU |
			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
	SND_SOC_DAPM_PGA_E("ANC HPHR PA", WCD9335_ANA_HPH, 6, 0, NULL, 0,
			   tasha_codec_enable_hphr_pa,
			   SND_SOC_DAPM_POST_PMU |
			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
	SND_SOC_DAPM_PGA_E("ANC LINEOUT1 PA", WCD9335_ANA_LO_1_2,
				7, 0, NULL, 0,
@@ -10805,7 +10969,6 @@ static const struct tasha_reg_mask_val tasha_codec_reg_init_val_2_0[] = {
	{WCD9335_HPH_OCP_CTL, 0xFF, 0x5A},
	{WCD9335_HPH_L_TEST, 0x01, 0x01},
	{WCD9335_HPH_R_TEST, 0x01, 0x01},
	{WCD9335_FLYBACK_VNEG_DAC_CTRL_2, 0xE0, 0x20},
	{WCD9335_CDC_BOOST0_BOOST_CFG1, 0x3F, 0x12},
	{WCD9335_CDC_BOOST0_BOOST_CFG2, 0x1C, 0x08},
	{WCD9335_CDC_COMPANDER7_CTL7, 0x1E, 0x18},
@@ -10814,6 +10977,8 @@ static const struct tasha_reg_mask_val tasha_codec_reg_init_val_2_0[] = {
	{WCD9335_CDC_COMPANDER8_CTL7, 0x1E, 0x18},
	{WCD9335_CDC_TX0_TX_PATH_SEC7, 0xFF, 0x45},
	{WCD9335_CDC_RX0_RX_PATH_SEC0, 0xFC, 0xF4},
	{WCD9335_HPH_REFBUFF_LP_CTL, 0x08, 0x08},
	{WCD9335_HPH_REFBUFF_LP_CTL, 0x06, 0x02},
};

static const struct tasha_reg_mask_val tasha_codec_reg_defaults[] = {
+23 −7
Original line number Diff line number Diff line
@@ -40,6 +40,15 @@ enum {
	VREF_FILT_R_100KOHM,
};

enum {
	DELTA_I_0MA,
	DELTA_I_10MA,
	DELTA_I_20MA,
	DELTA_I_30MA,
	DELTA_I_40MA,
	DELTA_I_50MA,
};

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);
@@ -284,6 +293,7 @@ static void wcd_clsh_set_hph_mode(struct snd_soc_codec *codec,
	u8 val;
	u8 gain;
	u8 res_val = VREF_FILT_R_0OHM;
	u8 ipeak = DELTA_I_50MA;

	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);

@@ -292,18 +302,21 @@ static void wcd_clsh_set_hph_mode(struct snd_soc_codec *codec,
		res_val = VREF_FILT_R_50KOHM;
		val = 0x00;
		gain = DAC_GAIN_0DB;
		ipeak = DELTA_I_50MA;
		break;
	case CLS_AB:
		val = 0x00;
		gain = DAC_GAIN_0DB;
		ipeak = DELTA_I_50MA;
		break;
	case CLS_H_HIFI:
		val = 0x08;
		gain = DAC_GAIN_M0P2DB;
		ipeak = DELTA_I_50MA;
		break;
	case CLS_H_LP:
		val = 0x04;
		gain = DAC_GAIN_0P2DB;
		ipeak = DELTA_I_30MA;
		break;
	};

@@ -311,8 +324,11 @@ static void wcd_clsh_set_hph_mode(struct snd_soc_codec *codec,
	if (TASHA_IS_2_0(wcd9xxx->version)) {
		snd_soc_update_bits(codec, WCD9XXX_CLASSH_CTRL_VCL_2,
				    0x30, (res_val << 4));
		if (mode != CLS_H_LP)
			snd_soc_update_bits(codec, WCD9XXX_HPH_REFBUFF_UHQA_CTL,
					    0x07, gain);
		snd_soc_update_bits(codec, WCD9XXX_CLASSH_CTRL_CCL_1,
				    0xF0, (ipeak << 4));
	}
}

@@ -660,13 +676,13 @@ static void wcd_clsh_state_hph_r(struct snd_soc_codec *codec,
					    0x40, 0x40);
		}
		wcd_clsh_set_buck_regulator_mode(codec, mode);
		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_set_buck_mode(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);
		wcd_clsh_set_gain_path(codec, mode);
	} else {
		wcd_clsh_set_hph_mode(codec, CLS_H_NORMAL);

@@ -714,13 +730,13 @@ static void wcd_clsh_state_hph_l(struct snd_soc_codec *codec,
					    0x40, 0x40);
		}
		wcd_clsh_set_buck_regulator_mode(codec, mode);
		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_set_buck_mode(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);
		wcd_clsh_set_gain_path(codec, mode);
	} else {
		wcd_clsh_set_hph_mode(codec, CLS_H_NORMAL);