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

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

Merge "ASoC: wcd9330: add support for impedance detection"

parents 193e5269 19730f21
Loading
Loading
Loading
Loading
+17 −8
Original line number Diff line number Diff line
@@ -2966,8 +2966,8 @@ static int msm8x10_wcd_setup_zdet(struct wcd9xxx_mbhc *mbhc,
	 } while (0)

	switch (stage) {
	case PRE_MEAS:
		dev_dbg(codec->dev, "%s: PRE_MEAS\n", __func__);
	case MBHC_ZDET_PRE_MEASURE:
		dev_dbg(codec->dev, "%s: MBHC_ZDET_PRE_MEASURE\n", __func__);
		INIT_LIST_HEAD(&wcd_priv->reg_save_restore);
		/* Configure PA */
		msm8x10_wcd_prepare_hph_pa(mbhc->codec,
@@ -3020,8 +3020,8 @@ static int msm8x10_wcd_setup_zdet(struct wcd9xxx_mbhc *mbhc,
		msm8x10_wcd_enable_static_pa(mbhc->codec, true);
		break;

	case POST_MEAS:
		dev_dbg(codec->dev, "%s: POST_MEAS\n", __func__);
	case MBHC_ZDET_POST_MEASURE:
		dev_dbg(codec->dev, "%s: MBHC_ZDET_POST_MEASURE\n", __func__);
		/* Turn off ICAL */
		snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_2, 0xF0);

@@ -3067,24 +3067,33 @@ static int msm8x10_wcd_setup_zdet(struct wcd9xxx_mbhc *mbhc,
		usleep_range(mux_wait_us,
				mux_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
		break;
	case PA_DISABLE:
		dev_dbg(codec->dev, "%s: PA_DISABLE\n", __func__);
	case MBHC_ZDET_PA_DISABLE:
		dev_dbg(codec->dev, "%s: MBHC_ZDET_PA_DISABLE\n", __func__);
		msm8x10_wcd_enable_static_pa(mbhc->codec, false);
		wcd9xxx_restore_registers(codec, &wcd_priv->reg_save_restore);
		break;
	default:
		dev_dbg(codec->dev, "%s: Case %d not supported\n",
			__func__, stage);
		break;
	}
#undef __wr

	return ret;
}

static void msm8x10_wcd_compute_impedance(s16 *l, s16 *r, uint32_t *zl,
					  uint32_t *zr)
static void msm8x10_wcd_compute_impedance(struct wcd9xxx_mbhc *mbhc, s16 *l,
					  s16 *r, uint32_t *zl, uint32_t *zr)
{
	int zln, zld;
	int zrn, zrd;
	int rl = 0, rr = 0;

	if (!mbhc) {
		pr_err("%s: NULL pointer for MBHC", __func__);
		return;
	}

	zln = (l[1] - l[0]) * MSM8X10_WCD_ZDET_MUL_FACTOR;
	zld = (l[2] - l[0]);
	if (zld)
+14 −4
Original line number Diff line number Diff line
@@ -5580,7 +5580,7 @@ static int tapan_setup_zdet(struct wcd9xxx_mbhc *mbhc,

	switch (stage) {

	case PRE_MEAS:
	case MBHC_ZDET_PRE_MEASURE:
		INIT_LIST_HEAD(&tapan->reg_save_restore);
		/* Configure PA */
		wcd9xxx_prepare_hph_pa(mbhc, &tapan->reg_save_restore);
@@ -5640,7 +5640,7 @@ static int tapan_setup_zdet(struct wcd9xxx_mbhc *mbhc,
		/* Enable the HPHL and HPHR PA */
		wcd9xxx_enable_static_pa(mbhc, true);
		break;
	case POST_MEAS:
	case MBHC_ZDET_POST_MEASURE:
		/* Turn off ICAL */
		snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_2, 0xF0);

@@ -5686,23 +5686,33 @@ static int tapan_setup_zdet(struct wcd9xxx_mbhc *mbhc,
		usleep_range(mux_wait_us,
				mux_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
		break;
	case PA_DISABLE:
	case MBHC_ZDET_PA_DISABLE:
		if (!mbhc->hph_pa_dac_state)
			wcd9xxx_enable_static_pa(mbhc, false);
		wcd9xxx_restore_registers(codec, &tapan->reg_save_restore);
		break;
	default:
		dev_dbg(codec->dev, "%s: Case %d not supported\n",
			__func__, stage);
		break;
	}
#undef __wr

	return ret;
}

static void tapan_compute_impedance(s16 *l, s16 *r, uint32_t *zl, uint32_t *zr)
static void tapan_compute_impedance(struct wcd9xxx_mbhc *mbhc, s16 *l, s16 *r,
					uint32_t *zl, uint32_t *zr)
{
	int zln, zld;
	int zrn, zrd;
	int rl = 0, rr = 0;

	if (!mbhc) {
		pr_err("%s: NULL pointer for MBHC", __func__);
		return;
	}

	zln = (l[1] - l[0]) * TAPAN_ZDET_MUL_FACTOR;
	zld = (l[2] - l[0]);
	if (zld)
+14 −4
Original line number Diff line number Diff line
@@ -6885,7 +6885,7 @@ static int taiko_setup_zdet(struct wcd9xxx_mbhc *mbhc,

	switch (stage) {

	case PRE_MEAS:
	case MBHC_ZDET_PRE_MEASURE:
		INIT_LIST_HEAD(&taiko->reg_save_restore);
		wcd9xxx_prepare_static_pa(mbhc, &taiko->reg_save_restore);
		wcd9xxx_enable_static_pa(mbhc, true);
@@ -6929,7 +6929,7 @@ static int taiko_setup_zdet(struct wcd9xxx_mbhc *mbhc,
		/* Set HPH_MBHC for zdet */
		__wr(WCD9XXX_A_MBHC_HPH, 0xB3, 0x80);
		break;
	case POST_MEAS:
	case MBHC_ZDET_POST_MEASURE:
		/* Phase 2 */
		/* Start the PA ramp on HPH L and R */
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x05);
@@ -6943,7 +6943,7 @@ static int taiko_setup_zdet(struct wcd9xxx_mbhc *mbhc,
		usleep_range(ramp_wait_us,
				ramp_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
		break;
	case PA_DISABLE:
	case MBHC_ZDET_PA_DISABLE:
		/* Ramp HPH L & R back to Zero */
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x0A);
		/* Ramp generator takes ~17ms */
@@ -6958,13 +6958,18 @@ static int taiko_setup_zdet(struct wcd9xxx_mbhc *mbhc,
			wcd9xxx_enable_static_pa(mbhc, false);
		wcd9xxx_restore_registers(codec, &taiko->reg_save_restore);
		break;
	default:
		dev_dbg(codec->dev, "%s: Case %d not supported\n",
			__func__, stage);
		break;
	}
#undef __wr

	return ret;
}

static void taiko_compute_impedance(s16 *l, s16 *r, uint32_t *zl, uint32_t *zr)
static void taiko_compute_impedance(struct wcd9xxx_mbhc *mbhc, s16 *l, s16 *r,
					uint32_t *zl, uint32_t *zr)
{

	int64_t rl, rr = 0; /* milliohm */
@@ -6974,6 +6979,11 @@ static void taiko_compute_impedance(s16 *l, s16 *r, uint32_t *zl, uint32_t *zr)
	const int rref = 11333; /* not scaled up */
	const int shift = 16;

	if (!mbhc) {
		pr_err("%s: NULL pointer for MBHC", __func__);
		return;
	}

	rl = (int)(l[0] - l[1]) * 1000 / (l[0] - l[2]);
	rl = rl * rref * alphal;
	rl = rl >> shift;
+305 −85
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@
#define TOMTOM_MAD_MASTER_SLIM_TX 140
#define TOMTOM_HPH_PA_SETTLE_COMP_ON 3000
#define TOMTOM_HPH_PA_SETTLE_COMP_OFF 13000
#define TOMTOM_HPH_PA_RAMP_DELAY 30000

#define DAPM_MICBIAS2_EXTERNAL_STANDALONE "MIC BIAS2 External Standalone"

@@ -262,6 +263,13 @@ static struct afe_param_id_clip_bank_sel clip_bank_sel = {
#define TOMTOM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)

#define TOMTOM_SLIM_PGD_PORT_INT_TX_EN0 (TOMTOM_SLIM_PGD_PORT_INT_EN0 + 2)
#define TOMTOM_ZDET_BOX_CAR_AVG_LOOP_COUNT 1
#define TOMTOM_ZDET_MUL_FACTOR_1X 7218
#define TOMTOM_ZDET_MUL_FACTOR_10X (TOMTOM_ZDET_MUL_FACTOR_1X * 10)
#define TOMTOM_ZDET_MUL_FACTOR_100X (TOMTOM_ZDET_MUL_FACTOR_1X * 100)
#define TOMTOM_ZDET_ERROR_APPROX_MUL_FACTOR 655
#define TOMTOM_ZDET_ERROR_APPROX_SHIFT 16
#define TOMTOM_ZDET_ZONE_3_DEFAULT_VAL 1000000

enum {
	AIF1_PB = 0,
@@ -472,6 +480,9 @@ struct tomtom_priv {

	/* UHQA (class AB) mode */
	u8 uhqa_mode;

	/* Multiplication factor used for impedance detection */
	int zdet_gain_mul_fact;
};

static const u32 comp_shift[] = {
@@ -7019,40 +7030,79 @@ static int wcd9xxx_prepare_static_pa(struct wcd9xxx_mbhc *mbhc,
{
	int i;
	struct snd_soc_codec *codec = mbhc->codec;
	u32 delay;

	const struct wcd9xxx_reg_mask_val reg_set_paon[] = {
		{WCD9XXX_A_RX_HPH_OCP_CTL, 0x18, 0x00},
		{WCD9XXX_A_RX_HPH_L_TEST, 0x1, 0x0},
		{WCD9XXX_A_RX_HPH_R_TEST, 0x1, 0x0},
		{WCD9XXX_A_RX_HPH_BIAS_WG_OCP, 0xff, 0x1A},
		{WCD9XXX_A_RX_HPH_CNP_WG_CTL, 0xff, 0xDB},
		{WCD9XXX_A_RX_HPH_CNP_WG_TIME, 0xff, 0x15},
		{TOMTOM_A_TX_COM_BIAS, 0xff, 0xF0},
		{WCD9XXX_A_CDC_RX1_B6_CTL, 0xff, 0x81},
		{WCD9XXX_A_CDC_CLK_RX_B1_CTL, 0x01, 0x01},
		{WCD9XXX_A_RX_HPH_CHOP_CTL, 0xff, 0xA4},
		{WCD9XXX_A_RX_HPH_L_GAIN, 0xff, 0x2C},
		{WCD9XXX_A_BUCK_MODE_2, 0xff, 0xEF},
		{WCD9XXX_A_BUCK_MODE_2, 0xff, 0xEE},
		{TOMTOM_A_NCP_DTEST, 0xff, 0x20},
		{WCD9XXX_A_CDC_CLK_OTHR_CTL, 0xff, 0x21},
		{WCD9XXX_A_CDC_RX2_B6_CTL, 0xff, 0x81},
		{WCD9XXX_A_CDC_CLK_RX_B1_CTL, 0x02, 0x02},
		{WCD9XXX_A_RX_HPH_R_GAIN, 0xff, 0x2C},

		{WCD9XXX_A_BUCK_MODE_2, 0xff, 0xAE},
		{WCD9XXX_A_BUCK_MODE_2, 0xff, 0xAA},
		{WCD9XXX_A_NCP_CLK, 0xff, 0x9C},
		{WCD9XXX_A_NCP_CLK, 0xff, 0xFC},
		{WCD9XXX_A_BUCK_CTRL_CCL_3, 0xff, 0x60},
		{WCD9XXX_A_RX_COM_BIAS, 0xff, 0x80},
		{WCD9XXX_A_RX_COM_BIAS, 0xff, 0xA0},
		{WCD9XXX_A_BUCK_MODE_3, 0xff, 0xC6},
		{WCD9XXX_A_BUCK_MODE_4, 0xff, 0xE6},
		{WCD9XXX_A_BUCK_MODE_5, 0xff, 0x02},
		{WCD9XXX_A_BUCK_MODE_1, 0xff, 0xA1},
		/* Add a delay of 1ms after this reg write */

		{WCD9XXX_A_NCP_STATIC, 0xff, 0x28},
		{WCD9XXX_A_NCP_EN, 0xff, 0xFF},
		{WCD9XXX_A_BUCK_MODE_5, 0xff, 0x7B},
		/* Add a delay of 1ms after this reg write */

		/* set HPHL */
		{WCD9XXX_A_RX_HPH_L_TEST, 0xff, 0x00},
		{TOMTOM_A_RX_HPH_L_PA_CTL, 0xff, 0x42},
		{TOMTOM_A_RX_HPH_BIAS_LDO, 0xff, 0x8C},
		{TOMTOM_A_RX_HPH_CHOP_CTL, 0xff, 0xA4},
		{WCD9XXX_A_RX_HPH_L_GAIN, 0xff, 0xE0},
		{WCD9XXX_A_RX_HPH_L_GAIN, 0xff, 0xEC},

		/* set HPHR */
		{WCD9XXX_A_RX_HPH_R_TEST, 0xff, 0x00},
		{TOMTOM_A_RX_HPH_R_PA_CTL, 0xff, 0x42},
		{WCD9XXX_A_RX_HPH_R_GAIN, 0xff, 0x20},
		{WCD9XXX_A_RX_HPH_R_GAIN, 0xff, 0x2C},

		/* set HPH PAs */
		{WCD9XXX_A_RX_HPH_BIAS_WG_OCP, 0xff, 0x2A},
		{WCD9XXX_A_RX_HPH_CNP_WG_CTL, 0xff, 0xDA},
		{WCD9XXX_A_RX_HPH_CNP_WG_TIME, 0xff, 0x15},
		{WCD9XXX_A_CDC_CLSH_B1_CTL, 0xff, 0xE6},
		{WCD9XXX_A_RX_HPH_L_DAC_CTL, 0xff, 0x40},
		{WCD9XXX_A_RX_HPH_L_DAC_CTL, 0xff, 0xC0},
		{WCD9XXX_A_RX_HPH_R_DAC_CTL, 0xff, 0x40},
		{WCD9XXX_A_RX_HPH_R_DAC_CTL, 0xff, 0xC0},

		{TOMTOM_A_RX_HPH_L_ATEST, 0xff, 0x00},
		{TOMTOM_A_RX_HPH_R_ATEST, 0xff, 0x00},
	};

	for (i = 0; i < ARRAY_SIZE(reg_set_paon); i++)
	for (i = 0; i < ARRAY_SIZE(reg_set_paon); i++) {
		/*
		 * Some of the codec registers like BUCK_MODE_1
		 * and NCP_EN requires 1ms wait time for them
		 * to take effect. Other register writes for
		 * PA configuration do not require any wait time.
		 */
		if (reg_set_paon[i].reg == WCD9XXX_A_BUCK_MODE_1 ||
		    reg_set_paon[i].reg == WCD9XXX_A_NCP_EN)
			delay = 1000;
		else
			delay = 0;
		wcd9xxx_soc_update_bits_push(codec, lh,
					     reg_set_paon[i].reg,
					     reg_set_paon[i].mask,
					     reg_set_paon[i].val, 0);
					     reg_set_paon[i].val, delay);
	}
	pr_debug("%s: PAs are prepared\n", __func__);

	return 0;
@@ -7065,7 +7115,7 @@ static int wcd9xxx_enable_static_pa(struct wcd9xxx_mbhc *mbhc, bool enable)
			    TOMTOM_WG_TIME_FACTOR_US;

	snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CNP_EN, 0x30,
			    enable ? 0x30 : 0x0);
			    enable ? 0x30 : 0x00);
	/* Wait for wave gen time to avoid pop noise */
	usleep_range(wg_time, wg_time + WCD9XXX_USLEEP_RANGE_MARGIN_US);
	pr_debug("%s: PAs are %s as static mode (wg_time %d)\n", __func__,
@@ -7079,7 +7129,6 @@ static int tomtom_setup_zdet(struct wcd9xxx_mbhc *mbhc,
	int ret = 0;
	struct snd_soc_codec *codec = mbhc->codec;
	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
	const int ramp_wait_us = 18 * 1000;

#define __wr(reg, mask, value)						  \
	do {								  \
@@ -7092,18 +7141,40 @@ static int tomtom_setup_zdet(struct wcd9xxx_mbhc *mbhc,

	switch (stage) {

	case PRE_MEAS:
	case MBHC_ZDET_PRE_MEASURE:
		INIT_LIST_HEAD(&tomtom->reg_save_restore);
		wcd9xxx_prepare_static_pa(mbhc, &tomtom->reg_save_restore);
		/* Set HPH_MBHC for zdet */
		__wr(WCD9XXX_A_MBHC_HPH, 0xff, 0xC4);
		usleep_range(10, 10 + WCD9XXX_USLEEP_RANGE_MARGIN_US);
		wcd9xxx_enable_static_pa(mbhc, true);

		/*
		 * save old value of registers and write the new value to
		 * restore old value back, WCD9XXX_A_CDC_PA_RAMP_B{1,2,3,4}_CTL
		 * registers don't need to be restored as those are solely used
		 * by impedance detection.
		 */
		/* Phase 1 */
		/* save old value of registers and write the new value */
		__wr(WCD9XXX_A_RX_HPH_OCP_CTL, 0xff, 0x69);
		__wr(WCD9XXX_A_CDC_RX1_B6_CTL, 0xff, 0x80);
		__wr(WCD9XXX_A_CDC_RX2_B6_CTL, 0xff, 0x80);
		/* Enable MBHC MUX, Set MUX current to 37.5uA and ADC7 */
		__wr(WCD9XXX_A_MBHC_SCALING_MUX_1, 0xff, 0xC0);
		__wr(WCD9XXX_A_MBHC_SCALING_MUX_2, 0xff, 0xF0);
		__wr(TOMTOM_A_TX_7_TXFE_CLKDIV, 0xff, 0x8B);
		__wr(WCD9XXX_A_TX_7_MBHC_TEST_CTL, 0xff, 0x78);
		__wr(WCD9XXX_A_TX_7_MBHC_EN, 0xff, 0x8C);
		__wr(WCD9XXX_A_CDC_MBHC_B1_CTL, 0xff, 0xDC);
		/* Reset MBHC and set it up for STA */
		__wr(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xff, 0x0A);
		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x00);
		__wr(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xff, 0x02);
		__wr(WCD9XXX_A_CDC_MBHC_TIMER_B5_CTL, 0xff, 0x80);
		__wr(WCD9XXX_A_CDC_MBHC_TIMER_B4_CTL, 0xff, 0x25);
		/* Wait for ~50us to let MBHC hardware settle down */
		usleep_range(50, 50 + WCD9XXX_USLEEP_RANGE_MARGIN_US);
		break;
	case MBHC_ZDET_POST_MEASURE:
		/* 0x69 for 105 number of samples for PA RAMP */
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B4_CTL, 0x69);
		/* Program the PA Ramp to FS_16K, L shift 1 */
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B3_CTL,
			      0x1 << 4 | 0x6);
		/* Reset the PA Ramp */
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x1C);
		/*
@@ -7112,56 +7183,84 @@ static int tomtom_setup_zdet(struct wcd9xxx_mbhc *mbhc,
		 */
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x1F);
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x03);

		/* Start the PA ramp on HPH L and R */
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x05);
		/* Ramp generator takes ~30ms */
		usleep_range(TOMTOM_HPH_PA_RAMP_DELAY,
			     TOMTOM_HPH_PA_RAMP_DELAY +
			     WCD9XXX_USLEEP_RANGE_MARGIN_US);

		/*
		 * Program the PA Ramp to FS_48K, L shift 1 and sample
		 * num to 24
		 * Set the multiplication factor for zdet calculation
		 * based on the Ramp voltage and Gain used
		 */
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B3_CTL,
			      0x3 << 4 | 0x6);
		/* 0x56 for 10mv.  0xC0 is for 50mv */
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B4_CTL, 0xC0);
		/* Enable MBHC MUX, Set MUX current to 37.5uA and ADC7 */
		__wr(WCD9XXX_A_MBHC_SCALING_MUX_1, 0xFF, 0xC0);
		__wr(WCD9XXX_A_MBHC_SCALING_MUX_2, 0xFF, 0xF0);
		__wr(WCD9XXX_A_TX_7_MBHC_TEST_CTL, 0xFF, 0x78);
		__wr(WCD9XXX_A_TX_7_MBHC_EN, 0xFF, 0x8C);
		/* Change NSA and NAVG */
		__wr(WCD9XXX_A_CDC_MBHC_TIMER_B4_CTL, 0x4 << 4, 0x4 << 4);
		__wr(WCD9XXX_A_CDC_MBHC_TIMER_B5_CTL, 0xFF, 0x10);
		/* Reset MBHC and set it up for STA */
		__wr(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x0A);
		__wr(WCD9XXX_A_CDC_MBHC_EN_CTL, 0xFF, 0x02);
		__wr(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x02);
		tomtom->zdet_gain_mul_fact = TOMTOM_ZDET_MUL_FACTOR_1X;
		break;
	case MBHC_ZDET_GAIN_1:
		/* Set Gain at 10x */
		snd_soc_write(codec, TOMTOM_A_RX_HPH_L_ATEST, 0x10);
		snd_soc_write(codec, TOMTOM_A_RX_HPH_R_ATEST, 0x00);
		snd_soc_write(codec, TOMTOM_A_RX_HPH_L_PA_CTL, 0x42);
		/* Allow 100us for gain registers to settle */
		usleep_range(100,
			     100 + WCD9XXX_USLEEP_RANGE_MARGIN_US);

		/* Set HPH_MBHC for zdet */
		__wr(WCD9XXX_A_MBHC_HPH, 0xB3, 0x80);
		/*
		 * Set the multiplication factor for zdet calculation
		 * based on the Gain value used
		 */
		tomtom->zdet_gain_mul_fact = TOMTOM_ZDET_MUL_FACTOR_10X;
		break;
	case POST_MEAS:
		/* Phase 2 */
		/* Start the PA ramp on HPH L and R */
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x05);
		/* Ramp generator takes ~17ms */
		usleep_range(ramp_wait_us,
				ramp_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
	case MBHC_ZDET_GAIN_2:
		/* Set Gain at 100x */
		snd_soc_write(codec, TOMTOM_A_RX_HPH_L_ATEST, 0x00);
		snd_soc_write(codec, TOMTOM_A_RX_HPH_R_ATEST, 0x10);
		snd_soc_write(codec, TOMTOM_A_RX_HPH_L_PA_CTL, 0x43);
		/* Allow 100us for gain registers to settle */
		usleep_range(100,
			     100 + WCD9XXX_USLEEP_RANGE_MARGIN_US);

		/* Disable Ical */
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x00);
		/* Ramp generator takes ~17ms */
		usleep_range(ramp_wait_us,
				ramp_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
		/*
		 * Set the multiplication factor for zdet calculation
		 * based on the Gain value used
		 */
		tomtom->zdet_gain_mul_fact = TOMTOM_ZDET_MUL_FACTOR_100X;
		break;
	case PA_DISABLE:
	case MBHC_ZDET_RAMP_DISABLE:
		/* Ramp HPH L & R back to Zero */
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x0A);
		/* Ramp generator takes ~17ms */
		usleep_range(ramp_wait_us,
				ramp_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x00);
		/* 0x69 for 105 number of samples for PA RAMP */
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B4_CTL, 0x69);
		/* Program the PA Ramp to FS_16K, L shift 1 */
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B3_CTL,
			      0x1 << 4 | 0x6);
		/* Reset the PA Ramp */
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x17);
		/*
		 * Connect the PA Ramp to PA chain and release reset with
		 * keep it connected.
		 */
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x03);
		/* Start the PA ramp on HPH L and R */
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x0A);
		/* Ramp generator takes ~30ms to settle down */
		usleep_range(TOMTOM_HPH_PA_RAMP_DELAY,
			     TOMTOM_HPH_PA_RAMP_DELAY +
			     WCD9XXX_USLEEP_RANGE_MARGIN_US);
		break;
	case MBHC_ZDET_PA_DISABLE:
		/* Disable PA */
		if (!mbhc->hph_pa_dac_state)
			wcd9xxx_enable_static_pa(mbhc, false);

		/* Clean up starts */
		/* Turn off PA ramp generator */
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x0);
		wcd9xxx_enable_static_pa(mbhc, false);
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x00);
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x00);
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B3_CTL, 0x00);
		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B4_CTL, 0x00);

		/* Restore registers */
		wcd9xxx_restore_registers(codec, &tomtom->reg_save_restore);
		break;
	}
@@ -7170,29 +7269,149 @@ static int tomtom_setup_zdet(struct wcd9xxx_mbhc *mbhc,
	return ret;
}

static void tomtom_compute_impedance(s16 *l, s16 *r, uint32_t *zl, uint32_t *zr)
/* Calculate final impedance values for HPH left and right based on formulae */
static void tomtom_compute_impedance(struct wcd9xxx_mbhc *mbhc, s16 *l, s16 *r,
					 uint32_t *zl, uint32_t *zr)
{
	s64 zln, zrn;
	int zld, zrd;
	s64 rl = 0, rr = 0;
	struct snd_soc_codec *codec;
	struct tomtom_priv *tomtom;

	if (!l || !r || !zl || !zr || !mbhc) {
		pr_err("%s: Invalid parameters l = %p, r = %p zl = %p zr = %p, mbhc = %p\n",
			__func__, l, r, zl, zr, mbhc);
		return;
	}
	codec = mbhc->codec;
	tomtom = snd_soc_codec_get_drvdata(codec);

	zln = (s64) (l[1] - l[0]) * tomtom->zdet_gain_mul_fact;
	zld = (l[2] - l[0]);
	if (zld)
		rl = div_s64(zln, zld);
	else
		/* If L0 and L2 are same, Z has to be on Zone 3. Assign
		 * a default value so that atleast the value is read again
		 * with Ramp-up
		 */
		rl = TOMTOM_ZDET_ZONE_3_DEFAULT_VAL;

	zrn = (s64) (r[1] - r[0]) * tomtom->zdet_gain_mul_fact;
	zrd = (r[2] - r[0]);
	if (zrd)
		rr = div_s64(zrn, zrd);
	else
		/* If R0 and R2 are same, Z has to be on Zone 3. Assign
		 * a default value so that atleast the value is read again
		 * with Ramp-up
		 */
		rr = TOMTOM_ZDET_ZONE_3_DEFAULT_VAL;

	/* 32-bit LSBs are enough to hold Impedance values */
	*zl = (u32) rl;
	*zr = (u32) rr;

	tomtom->zdet_gain_mul_fact = 0;
}

/*
 * Calculate error approximation of impedance values for HPH left
 * and HPH right based on QFuse values
 */
static void tomtom_zdet_error_approx(struct wcd9xxx_mbhc *mbhc, uint32_t *zl,
				     uint32_t *zr)
{
	struct snd_soc_codec *codec;
	struct tomtom_priv *tomtom;
	s8 q1_t, q2_t;
	s8 q1_m, q2_m;
	s8 q1, q2;
	u8 div_shift;
	int rl_alpha = 0, rr_alpha = 0;
	int rl_beta = 0, rr_beta = 0;
	u64 rl = 0, rr = 0;
	const int mult_factor = TOMTOM_ZDET_ERROR_APPROX_MUL_FACTOR;
	const int shift = TOMTOM_ZDET_ERROR_APPROX_SHIFT;

	if (!zl || !zr || !mbhc) {
		pr_err("%s: Invalid parameters zl = %p zr = %p, mbhc = %p\n",
			__func__, zl, zr, mbhc);
		return;
	}
	codec = mbhc->codec;
	tomtom = snd_soc_codec_get_drvdata(codec);

	if ((tomtom->zdet_gain_mul_fact == TOMTOM_ZDET_MUL_FACTOR_1X) ||
	    (tomtom->zdet_gain_mul_fact == TOMTOM_ZDET_MUL_FACTOR_10X)) {
		q1_t = ((snd_soc_read(codec, TOMTOM_A_QFUSE_DATA_OUT0) &
			0x3) << 0x5);
		q1_t |= ((snd_soc_read(codec, TOMTOM_A_QFUSE_DATA_OUT1) &
			0xF8) >> 0x3);
		q2_t = ((snd_soc_read(codec, TOMTOM_A_QFUSE_DATA_OUT1) &
			0x7) << 0x4);
		q2_t |= ((snd_soc_read(codec, TOMTOM_A_QFUSE_DATA_OUT2) &
			0xF0) >> 0x4);
		/* Take out the numeric part of the Qfuse value */
		q1_m = q1_t & 0x3F;
		q2_m = q2_t & 0x3F;
		/* Check the sign part of the Qfuse and adjust value */
		q1 = (q1_t & 0x40) ? -q1_m : q1_m;
		q2 = (q2_t & 0x40) ? -q2_m : q2_m;
		div_shift = 1;
	} else {
		q1_t = ((snd_soc_read(codec, TOMTOM_A_QFUSE_DATA_OUT2) &
			0xF) << 0x2);
		q1_t |= ((snd_soc_read(codec, TOMTOM_A_QFUSE_DATA_OUT3) &
			0xC0) >> 0x6);
		q2_t = (snd_soc_read(codec, TOMTOM_A_QFUSE_DATA_OUT3) & 0x3F);
		/* Take out the numeric part of the Qfuse value */
		q1_m = q1_t & 0x1F;
		q2_m = q2_t & 0x1F;
		/* Check the sign part of the Qfuse and adjust value */
		q1 = (q1_t & 0x20) ? -q1_m : q1_m;
		q2 = (q2_t & 0x20) ? -q2_m : q2_m;
		div_shift = 0;
	}

	dev_dbg(codec->dev, "%s: qfuse1 = %d, qfuse2 = %d\n",
		__func__, q1, q2);
	if (!q1 && !q2) {
		dev_dbg(codec->dev, "%s: qfuse1 and qfuse2 are 0. Exiting\n",
			__func__);
		return;
	}

	/*
	 * Use multiplication and shift to avoid floating point math
	 * The Z value is calculated with the below formulae using
	 * the Qfuse value-
	 * zl = zl * [1 - {(Q1 / div) / 100}] (Include sign for Q1)
	 * zr = zr * [1 - {(Q2 / div) / 100}] (Include sign for Q2)
	 * We multiply by 65536 and shift 16 times to get the approx result
	 * div = 4 for 1x gain, div = 2 for 10x/100x gain
	 */
	/* Q1/4 */
	rl_alpha = q1 >> div_shift;
	rl_alpha = 100 - rl_alpha;
	/* {rl_alpha/100} * 65536 */
	rl_beta = rl_alpha * mult_factor;
	rl = (u64) *zl * rl_beta;
	/* rl/65536 */
	rl = (u64) rl >> shift;

	int64_t rl, rr = 0; /* milliohm */
	const int alphal = 364; /* 0.005555 * 65536 = 364.05 */
	const int alphar = 364; /* 0.005555 * 65536 = 364.05 */
	const int beta = 3855; /* 0.011765 * 5 * 65536 = 3855.15 */
	const int rref = 11333; /* not scaled up */
	const int shift = 16;
	rr_alpha = q2 >> div_shift;
	rr_alpha = 100 - rr_alpha;
	rr_beta = rr_alpha * mult_factor;
	rr = (u64) *zr * rr_beta;
	rr = (u64) rr >> shift;

	rl = (int)(l[0] - l[1]) * 1000 / (l[0] - l[2]);
	rl = rl * rref * alphal;
	rl = rl >> shift;
	rl = rl * beta;
	rl = rl >> shift;
	*zl = rl;
	dev_dbg(codec->dev, "%s: rl = 0x%llx (%lld) \t rr = 0x%llx (%lld)\n",
		__func__, rl, rl, rr, rr);

	rr = (int)(r[0] - r[1]) * 1000 / (r[0] - r[2]);
	rr = rr * rref  * alphar;
	rr = rr >> shift;
	rr = rr * beta;
	rr = rr >> shift;
	*zr = rr;
	*zl = (u32) rl;
	*zr = (u32) rr;
}

static enum wcd9xxx_cdc_type tomtom_get_cdc_type(void)
@@ -7226,6 +7445,7 @@ static const struct wcd9xxx_mbhc_cb mbhc_cb = {
	.get_cdc_type = tomtom_get_cdc_type,
	.setup_zdet = tomtom_setup_zdet,
	.compute_impedance = tomtom_compute_impedance,
	.zdet_error_approx = tomtom_zdet_error_approx,
	.insert_rem_status = tomtom_mbhc_ins_rem_status,
	.micbias_pulldown_ctrl = tomtom_mbhc_micb_pulldown_ctrl,
	.codec_rco_ctrl = tomtom_codec_internal_rco_ctrl,
+337 −29

File changed.

Preview size limit exceeded, changes collapsed.

Loading