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

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

ASoC: wcd934x: add low power mode support for codec



Codec goes to digital power collapse state and disables the external
clock when there is no audio usecase active. It is possible certain
low power audio usecases need the codec to be out of digital core
power collapse but can run using the internal codec clock. Change
adds support to turn on codec digital core without turning on the
external clock if the clock mode is set to internal.

Change-Id: I74c296d9b967ea56c3f03514022b259856533d9b
Signed-off-by: default avatarBhalchandra Gajare <gajare@codeaurora.org>
parent 2d19be1f
Loading
Loading
Loading
Loading
+86 −0
Original line number Diff line number Diff line
@@ -180,6 +180,8 @@ enum {
	ANC_MIC_AMIC2,
	ANC_MIC_AMIC3,
	ANC_MIC_AMIC4,
	CLK_INTERNAL,
	CLK_MODE,
};

enum {
@@ -1071,6 +1073,40 @@ static int tavil_codec_enable_anc(struct snd_soc_dapm_widget *w,
	return ret;
}

static int tavil_get_clkmode(struct snd_kcontrol *kcontrol,
			     struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
	struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec);

	if (test_bit(CLK_MODE, &tavil_p->status_mask))
		ucontrol->value.enumerated.item[0] = 1;
	else
		ucontrol->value.enumerated.item[0] = 0;

	dev_dbg(codec->dev, "%s: is_low_power_clock: %s\n", __func__,
		test_bit(CLK_MODE, &tavil_p->status_mask) ? "true" : "false");

	return 0;
}

static int tavil_put_clkmode(struct snd_kcontrol *kcontrol,
			     struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
	struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec);

	if (ucontrol->value.enumerated.item[0])
		set_bit(CLK_MODE, &tavil_p->status_mask);
	else
		clear_bit(CLK_MODE, &tavil_p->status_mask);

	dev_dbg(codec->dev, "%s: is_low_power_clock: %s\n", __func__,
		test_bit(CLK_MODE, &tavil_p->status_mask) ? "true" : "false");

	return 0;
}

static int tavil_vi_feed_mixer_get(struct snd_kcontrol *kcontrol,
				   struct snd_ctl_elem_value *ucontrol)
{
@@ -5547,6 +5583,9 @@ static const char *const tavil_anc_func_text[] = {"OFF", "ON"};
static const struct soc_enum tavil_anc_func_enum =
	SOC_ENUM_SINGLE_EXT(2, tavil_anc_func_text);

static const char *const tavil_clkmode_text[] = {"EXTERNAL", "INTERNAL"};
static SOC_ENUM_SINGLE_EXT_DECL(tavil_clkmode_enum, tavil_clkmode_text);

/* Cutoff frequency for high pass filter */
static const char * const cf_text[] = {
	"CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ"
@@ -5726,6 +5765,9 @@ static const struct snd_kcontrol_new tavil_snd_controls[] = {
	SOC_ENUM_EXT("ANC Function", tavil_anc_func_enum, tavil_get_anc_func,
		tavil_put_anc_func),

	SOC_ENUM_EXT("CLK MODE", tavil_clkmode_enum, tavil_get_clkmode,
		     tavil_put_clkmode),

	SOC_ENUM("TX0 HPF cut off", cf_dec0_enum),
	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
	SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
@@ -8316,6 +8358,50 @@ static int tavil_codec_internal_rco_ctrl(struct snd_soc_codec *codec,
	return ret;
}

/*
 * tavil_cdc_mclk_tx_enable: Enable/Disable codec's clock for TX path
 * @codec: Handle to codec
 * @enable: Indicates whether clock should be enabled or disabled
 */
int tavil_cdc_mclk_tx_enable(struct snd_soc_codec *codec, bool enable)
{
	struct tavil_priv *tavil_p;
	int ret = 0;
	bool clk_mode;
	bool clk_internal;

	if (!codec)
		return -EINVAL;

	tavil_p = snd_soc_codec_get_drvdata(codec);
	clk_mode = test_bit(CLK_MODE, &tavil_p->status_mask);
	clk_internal = test_bit(CLK_INTERNAL, &tavil_p->status_mask);

	dev_dbg(codec->dev, "%s: clkmode: %d, enable: %d, clk_internal: %d\n",
		__func__, clk_mode, enable, clk_internal);

	if (clk_mode || clk_internal) {
		if (enable) {
			wcd_resmgr_enable_master_bias(tavil_p->resmgr);
			tavil_dig_core_power_collapse(tavil_p, POWER_RESUME);
			tavil_vote_svs(tavil_p, true);
			ret = tavil_codec_internal_rco_ctrl(codec, enable);
			set_bit(CLK_INTERNAL, &tavil_p->status_mask);
		} else {
			clear_bit(CLK_INTERNAL, &tavil_p->status_mask);
			tavil_codec_internal_rco_ctrl(codec, enable);
			tavil_vote_svs(tavil_p, false);
			tavil_dig_core_power_collapse(tavil_p, POWER_COLLAPSE);
			wcd_resmgr_disable_master_bias(tavil_p->resmgr);
		}
	} else {
		ret = __tavil_cdc_mclk_enable(tavil_p, enable);
	}

	return ret;
}
EXPORT_SYMBOL(tavil_cdc_mclk_tx_enable);

static const struct wcd_resmgr_cb tavil_resmgr_cb = {
	.cdc_rco_ctrl = __tavil_codec_internal_rco_ctrl,
};
+1 −0
Original line number Diff line number Diff line
@@ -137,6 +137,7 @@ struct tavil_reg_mask_val {
extern void *tavil_get_afe_config(struct snd_soc_codec *codec,
				  enum afe_config_type config_type);
extern int tavil_cdc_mclk_enable(struct snd_soc_codec *codec, bool enable);
extern int tavil_cdc_mclk_tx_enable(struct snd_soc_codec *codec, bool enable);
extern int tavil_set_spkr_mode(struct snd_soc_codec *codec, int mode);
extern int tavil_set_spkr_gain_offset(struct snd_soc_codec *codec, int offset);
extern struct wcd_dsp_cntl *tavil_get_wcd_dsp_cntl(struct device *dev);