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

Commit 6ed085d4 authored by Bhalchandra Gajare's avatar Bhalchandra Gajare Committed by Gerrit - the friendly Code Review server
Browse files

ASoC: wcd934x: Add support for voltage scaling



WCD934X audio codec supports static voltage scaling (SVS) mode, which
puts the codec into lowest power state. The codec has different power
states (SVS2, SVS and Nominal). Add support in codec driver to vote
for SVS when audio usecases are enabled and remove vote for SVS when
audio usecases are disabled. The codec driver only votes for SVS or
no SVS and the hardware internally manages to go into Nominal mode.

CRs-Fixed: 1049012
Change-Id: I6f66d3136e3c49da54f5919184bc113267105463
Signed-off-by: default avatarBhalchandra Gajare <gajare@codeaurora.org>
parent cacf1949
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
@@ -466,6 +466,11 @@ static void wcd_cntl_do_shutdown(struct wcd_dsp_cntl *cntl)
	/* Put WDSP in reset state */
	snd_soc_update_bits(codec, WCD934X_CPE_SS_CPE_CTL,
			    0x02, 0x00);

	/* If DSP transitions from boot to shutdown, then vote for SVS */
	if (cntl->is_wdsp_booted)
		cntl->cdc_cb->cdc_vote_svs(codec, true);
	cntl->is_wdsp_booted = false;
}

static int wcd_cntl_do_boot(struct wcd_dsp_cntl *cntl)
@@ -507,6 +512,7 @@ static int wcd_cntl_do_boot(struct wcd_dsp_cntl *cntl)
	if (cntl->debug_mode) {
		wait_for_completion(&cntl->boot_complete);
		dev_dbg(codec->dev, "%s: WDSP booted in dbg mode\n", __func__);
		cntl->is_wdsp_booted = true;
		goto done;
	}

@@ -521,11 +527,16 @@ static int wcd_cntl_do_boot(struct wcd_dsp_cntl *cntl)
	}

	dev_dbg(codec->dev, "%s: WDSP booted in normal mode\n", __func__);
	cntl->is_wdsp_booted = true;

	/* Enable WDOG */
	snd_soc_update_bits(codec, WCD934X_CPE_SS_WDOG_CFG,
			    0x10, 0x10);
done:
	/* If dsp booted up, then remove vote on SVS */
	if (cntl->is_wdsp_booted)
		cntl->cdc_cb->cdc_vote_svs(codec, false);

	return ret;
err_boot:
	/* call shutdown to perform cleanup */
@@ -899,6 +910,14 @@ void wcd_dsp_cntl_init(struct snd_soc_codec *codec,
		return;
	}

	if (!params->cb || !params->cb->cdc_clk_en ||
	    !params->cb->cdc_vote_svs) {
		dev_err(codec->dev,
			"%s: clk_en and vote_svs callbacks must be provided\n",
			__func__);
		return;
	}

	control = kzalloc(sizeof(*control), GFP_KERNEL);
	if (!(control))
		return;
@@ -911,6 +930,13 @@ void wcd_dsp_cntl_init(struct snd_soc_codec *codec,
	init_completion(&control->boot_complete);
	mutex_init(&control->clk_mutex);

	/*
	 * The default state of WDSP is in SVS mode.
	 * Vote for SVS now, the vote will be removed only
	 * after DSP is booted up.
	 */
	control->cdc_cb->cdc_vote_svs(codec, true);

	/*
	 * If this is the last component needed by master to be ready,
	 * then component_bind will be called within the component_add.
+5 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@
struct wcd_dsp_cdc_cb {
	/* Callback to enable codec clock */
	int (*cdc_clk_en)(struct snd_soc_codec *, bool);
	/* Callback to vote and unvote for SVS2 mode */
	void (*cdc_vote_svs)(struct snd_soc_codec *, bool);
};

struct wcd_dsp_irq_info {
@@ -83,6 +85,9 @@ struct wcd_dsp_cntl {
	/* clk related */
	struct mutex clk_mutex;
	bool is_clk_enabled;

	/* Keep track of WDSP boot status */
	bool is_wdsp_booted;
};

void wcd_dsp_cntl_init(struct snd_soc_codec *codec,
+60 −0
Original line number Diff line number Diff line
@@ -488,6 +488,10 @@ struct tavil_priv {

	/* cal info for codec */
	struct fw_info *fw_data;

	/* SVS voting related */
	struct mutex svs_mutex;
	int svs_ref_cnt;
};

static const struct tavil_reg_mask_val tavil_spkr_default[] = {
@@ -715,6 +719,36 @@ void *tavil_get_afe_config(struct snd_soc_codec *codec,
}
EXPORT_SYMBOL(tavil_get_afe_config);

static void tavil_vote_svs(struct tavil_priv *tavil, bool vote)
{
	struct wcd9xxx *wcd9xxx;

	wcd9xxx = tavil->wcd9xxx;

	mutex_lock(&tavil->svs_mutex);
	if (vote) {
		tavil->svs_ref_cnt++;
		if (tavil->svs_ref_cnt == 1)
			regmap_update_bits(wcd9xxx->regmap,
					   WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_0,
					   0x01, 0x01);
	} else {
		/* Do not decrement ref count if it is already 0 */
		if (tavil->svs_ref_cnt == 0)
			goto done;

		tavil->svs_ref_cnt--;
		if (tavil->svs_ref_cnt == 0)
			regmap_update_bits(wcd9xxx->regmap,
					   WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_0,
					   0x01, 0x00);
	}
done:
	dev_dbg(tavil->dev, "%s: vote = %s, updated ref cnt = %u\n", __func__,
		vote ? "vote" : "Unvote", tavil->svs_ref_cnt);
	mutex_unlock(&tavil->svs_mutex);
}

static int tavil_vi_feed_mixer_get(struct snd_kcontrol *kcontrol,
				   struct snd_ctl_elem_value *ucontrol)
{
@@ -5664,6 +5698,7 @@ static int __tavil_cdc_mclk_enable_locked(struct tavil_priv *tavil,
	dev_dbg(tavil->dev, "%s: mclk_enable = %u\n", __func__, enable);

	if (enable) {
		tavil_vote_svs(tavil, true);
		ret = tavil_cdc_req_mclk_enable(tavil, true);
		if (ret)
			goto done;
@@ -5671,6 +5706,7 @@ static int __tavil_cdc_mclk_enable_locked(struct tavil_priv *tavil,
		set_bit(AUDIO_NOMINAL, &tavil->status_mask);
	} else {
		tavil_cdc_req_mclk_enable(tavil, false);
		tavil_vote_svs(tavil, false);
	}

done:
@@ -6148,8 +6184,16 @@ static void tavil_enable_sido_buck(struct snd_soc_codec *codec)
	tavil->resmgr->sido_input_src = SIDO_SOURCE_RCO_BG;
}

static void tavil_cdc_vote_svs(struct snd_soc_codec *codec, bool vote)
{
	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);

	return tavil_vote_svs(tavil, vote);
}

struct wcd_dsp_cdc_cb cdc_cb = {
	.cdc_clk_en = tavil_codec_internal_rco_ctrl,
	.cdc_vote_svs = tavil_cdc_vote_svs,
};

static int tavil_wdsp_initialize(struct snd_soc_codec *codec)
@@ -6326,6 +6370,12 @@ static int tavil_soc_codec_probe(struct snd_soc_codec *codec)

	tavil_wdsp_initialize(codec);

	/*
	 * Once the codec initialization is completed, the svs vote
	 * can be released allowing the codec to go to SVS2.
	 */
	tavil_vote_svs(tavil, false);

	return ret;

err_pdata:
@@ -6870,6 +6920,14 @@ static int tavil_probe(struct platform_device *pdev)
	mutex_init(&tavil->swr.write_mutex);
	mutex_init(&tavil->swr.clk_mutex);
	mutex_init(&tavil->codec_mutex);
	mutex_init(&tavil->svs_mutex);

	/*
	 * Codec hardware by default comes up in SVS mode.
	 * Initialize the svs_ref_cnt to 1 to reflect the hardware
	 * state in the driver.
	 */
	tavil->svs_ref_cnt = 1;

	/*
	 * Init resource manager so that if child nodes such as SoundWire
@@ -6932,6 +6990,7 @@ err_clk:
	wcd_resmgr_remove(tavil->resmgr);
err_resmgr:
	mutex_destroy(&tavil->micb_lock);
	mutex_destroy(&tavil->svs_mutex);
	mutex_destroy(&tavil->codec_mutex);
	mutex_destroy(&tavil->swr.read_mutex);
	mutex_destroy(&tavil->swr.write_mutex);
@@ -6950,6 +7009,7 @@ static int tavil_remove(struct platform_device *pdev)
		return -EINVAL;

	mutex_destroy(&tavil->micb_lock);
	mutex_destroy(&tavil->svs_mutex);
	mutex_destroy(&tavil->codec_mutex);
	mutex_destroy(&tavil->swr.read_mutex);
	mutex_destroy(&tavil->swr.write_mutex);