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

Commit 38017b21 authored by Bhalchandra Gajare's avatar Bhalchandra Gajare
Browse files

ASoC: wcd9xxx-resmgr-v2: Fix the clock enable sequence



When the external codec clock is enabled while the internal codec clock
is already active, the current sequence of enabling clock is incorrect
and is actually not enabling the clock to some of the codec blocks. This
results in slimbus overflow if playback is started when internal clock
is already enabled. Fix this issue by correcting the clock enable
sequence.

CRs-fixed: 889502
Change-Id: I4668e5e2aa2c9d1159b7a827e39c7bde2aa2f2ea
Signed-off-by: default avatarBhalchandra Gajare <gajare@codeaurora.org>
parent 40b49a34
Loading
Loading
Loading
Loading
+41 −23
Original line number Original line Diff line number Diff line
@@ -45,6 +45,19 @@ static int wcd_resmgr_codec_reg_update_bits(struct wcd9xxx_resmgr_v2 *resmgr,
	return change;
	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()
 * wcd_resmgr_get_clk_type()
 * Returns clk type that is currently enabled
 * 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;
		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,
		wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_CLK_TOP,
						 0x80, 0x80);
						 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,
		wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_CLK_TOP,
						 0x04, 0x04);
						 0x04, 0x04);
		wcd_resmgr_codec_reg_update_bits(resmgr,
		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
		 * as per HW requirement
		 */
		 */
		usleep_range(10, 15);
		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;
	resmgr->clk_type = WCD_CLK_MCLK;


	pr_debug("%s: mclk_users: %d, clk_type: %s\n", __func__,
	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;
		return -EINVAL;
	}
	}


	resmgr->clk_mclk_users--;
	if (--resmgr->clk_mclk_users == 0) {
	if ((resmgr->clk_mclk_users == 0) && (resmgr->clk_rco_users > 0)) {
		if (resmgr->clk_rco_users > 0) {
			/* MCLK to RCO switch */
			/* MCLK to RCO switch */
			wcd_resmgr_codec_reg_update_bits(resmgr,
			wcd_resmgr_codec_reg_update_bits(resmgr,
					WCD9335_ANA_CLK_TOP,
					WCD9335_ANA_CLK_TOP,
					0x08, 0x08);
					0x08, 0x08);
			resmgr->clk_type = WCD_CLK_RCO;
			resmgr->clk_type = WCD_CLK_RCO;
	} else if ((resmgr->clk_mclk_users == 0) &&
		} else {
		   (resmgr->clk_rco_users == 0)) {
			wcd_resmgr_codec_reg_update_bits(resmgr,
		/* Turn off MCLK */
					WCD9335_ANA_CLK_TOP,
		wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_CLK_TOP,
					0x04, 0x00);
					0x04, 0x00);
			resmgr->clk_type = WCD_CLK_OFF;
		}

		wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_CLK_TOP,
		wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_CLK_TOP,
						 0x80, 0x00);
						 0x80, 0x00);
		resmgr->clk_type = WCD_CLK_OFF;
	}
	}

	pr_debug("%s: mclk_users: %d, clk_type: %s\n", __func__,
	pr_debug("%s: mclk_users: %d, clk_type: %s\n", __func__,
		 resmgr->clk_mclk_users,
		 resmgr->clk_mclk_users,
		 wcd_resmgr_clk_type_to_str(resmgr->clk_type));
		 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)
static int wcd_resmgr_enable_clk_rco(struct wcd9xxx_resmgr_v2 *resmgr)
{
{
	bool rco_cal_done = true;

	resmgr->clk_rco_users++;
	resmgr->clk_rco_users++;
	if ((resmgr->clk_rco_users == 1) &&
	if ((resmgr->clk_rco_users == 1) &&
	    ((resmgr->clk_type == WCD_CLK_OFF) ||
	    ((resmgr->clk_type == WCD_CLK_OFF) ||
@@ -281,9 +292,16 @@ static int wcd_resmgr_enable_clk_rco(struct wcd9xxx_resmgr_v2 *resmgr)
		/* RCO Calibration */
		/* RCO Calibration */
		wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_RCO,
		wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_RCO,
						 0x04, 0x04);
						 0x04, 0x04);
		wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_RCO,
						 0x04, 0x00);

		/* RCO calibration takes app. 5ms to complete */
		/* RCO calibration takes app. 5ms to complete */
		usleep_range(WCD9XXX_RCO_CALIBRATION_DELAY_INC_US,
		usleep_range(WCD9XXX_RCO_CALIBRATION_DELAY_INC_US,
		       WCD9XXX_RCO_CALIBRATION_DELAY_INC_US + 100);
		       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 */
		/* Switch MUX to RCO */
		if (resmgr->clk_mclk_users == 1) {
		if (resmgr->clk_mclk_users == 1) {