summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c26
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.h5
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x.c60
3 files changed, 91 insertions, 0 deletions
diff --git a/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c b/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c
index 306a4352ca46..225b3a755f66 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c
+++ b/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c
@@ -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;
@@ -912,6 +931,13 @@ void wcd_dsp_cntl_init(struct snd_soc_codec *codec,
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.
* Hence, the data pointer should be assigned before component_add,
diff --git a/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.h b/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.h
index caa7edc02da8..3d6db776a0b5 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.h
+++ b/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.h
@@ -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,
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index 26059caba07a..364aa17ea7e6 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -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);