ASoC: OMAP ABE: Update for PM.
Update OMAP ABE driver in order to manage correctly Power
Managment and OFF mode.
Signed-off-by: Sebastien Guiriec <s-guiriec@ti.com>
diff --git a/sound/soc/omap/omap-abe-dsp.c b/sound/soc/omap/omap-abe-dsp.c
index 042fcdb..9636002 100644
--- a/sound/soc/omap/omap-abe-dsp.c
+++ b/sound/soc/omap/omap-abe-dsp.c
@@ -1730,14 +1730,11 @@
.buffer_bytes_max = 24 * 1024 * 2,
};
-static int aess_set_runtime_opp_level(struct abe_data *abe)
+
+static int abe_set_opp_mode(struct abe_data *abe)
{
int i, opp = 0;
- mutex_lock(&abe->opp_mutex);
-
- pm_runtime_get_sync(abe->dev);
-
/* now calculate OPP level based upon DAPM widget status */
for (i = 0; i < ABE_NUM_WIDGETS; i++) {
if (abe->widget_opp[ABE_WIDGET(i)]) {
@@ -1784,6 +1781,15 @@
abe->opp = opp;
dev_dbg(abe->dev, "new OPP level is %d\n", opp);
+ return 0;
+}
+
+static int aess_set_runtime_opp_level(struct abe_data *abe)
+{
+ mutex_lock(&abe->opp_mutex);
+
+ pm_runtime_get_sync(abe->dev);
+ abe_set_opp_mode(abe);
pm_runtime_put_sync(abe->dev);
mutex_unlock(&abe->opp_mutex);
@@ -1791,6 +1797,102 @@
return 0;
}
+static int aess_save_context(struct abe_data *abe)
+{
+ struct omap4_abe_dsp_pdata *pdata = abe->abe_pdata;
+
+ /* TODO: Find a better way to save/retore gains after OFF mode */
+
+ abe_mute_gain(MIXSDT, MIX_SDT_INPUT_UP_MIXER);
+ abe_mute_gain(MIXSDT, MIX_SDT_INPUT_DL1_MIXER);
+ abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_MM_DL);
+ abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_TONES);
+ abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_UPLINK);
+ abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_VX_DL);
+ abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_TONES);
+ abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_DL);
+ abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_MM_DL);
+ abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_UL);
+ abe_mute_gain(MIXDL1, MIX_DL1_INPUT_MM_DL);
+ abe_mute_gain(MIXDL1, MIX_DL1_INPUT_MM_UL2);
+ abe_mute_gain(MIXDL1, MIX_DL1_INPUT_VX_DL);
+ abe_mute_gain(MIXDL1, MIX_DL1_INPUT_TONES);
+ abe_mute_gain(MIXDL2, MIX_DL2_INPUT_TONES);
+ abe_mute_gain(MIXDL2, MIX_DL2_INPUT_VX_DL);
+ abe_mute_gain(MIXDL2, MIX_DL2_INPUT_MM_DL);
+ abe_mute_gain(MIXDL2, MIX_DL2_INPUT_MM_UL2);
+ abe_mute_gain(MIXECHO, MIX_ECHO_DL1);
+ abe_mute_gain(MIXECHO, MIX_ECHO_DL2);
+ abe_mute_gain(GAINS_DMIC1, GAIN_LEFT_OFFSET);
+ abe_mute_gain(GAINS_DMIC1, GAIN_RIGHT_OFFSET);
+ abe_mute_gain(GAINS_DMIC2, GAIN_LEFT_OFFSET);
+ abe_mute_gain(GAINS_DMIC2, GAIN_RIGHT_OFFSET);
+ abe_mute_gain(GAINS_DMIC3, GAIN_LEFT_OFFSET);
+ abe_mute_gain(GAINS_DMIC3, GAIN_RIGHT_OFFSET);
+ abe_mute_gain(GAINS_AMIC, GAIN_LEFT_OFFSET);
+ abe_mute_gain(GAINS_AMIC, GAIN_RIGHT_OFFSET);
+
+ if (pdata->get_context_loss_count)
+ abe->loss_count = pdata->get_context_loss_count(abe->dev);
+
+ return 0;
+}
+
+static int aess_restore_context(struct abe_data *abe)
+{
+ struct omap4_abe_dsp_pdata *pdata = abe->abe_pdata;
+ int loss_count = 0;
+
+ omap_device_set_rate(&abe->dev, &abe->dev, 98000000);
+
+ if (pdata->get_context_loss_count)
+ loss_count = pdata->get_context_loss_count(abe->dev);
+
+ if (loss_count != the_abe->loss_count)
+ abe_reload_fw();
+
+ /* TODO: Find a better way to save/retore gains after dor OFF mode */
+ abe_unmute_gain(MIXSDT, MIX_SDT_INPUT_UP_MIXER);
+ abe_unmute_gain(MIXSDT, MIX_SDT_INPUT_DL1_MIXER);
+ abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_MM_DL);
+ abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_TONES);
+ abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_UPLINK);
+ abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_VX_DL);
+ abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_TONES);
+ abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_DL);
+ abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_MM_DL);
+ abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_UL);
+ abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_MM_DL);
+ abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_MM_UL2);
+ abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_VX_DL);
+ abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_TONES);
+ abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_TONES);
+ abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_VX_DL);
+ abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_MM_DL);
+ abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_MM_UL2);
+ abe_unmute_gain(MIXECHO, MIX_ECHO_DL1);
+ abe_unmute_gain(MIXECHO, MIX_ECHO_DL2);
+ abe_unmute_gain(GAINS_DMIC1, GAIN_LEFT_OFFSET);
+ abe_unmute_gain(GAINS_DMIC1, GAIN_RIGHT_OFFSET);
+ abe_unmute_gain(GAINS_DMIC2, GAIN_LEFT_OFFSET);
+ abe_unmute_gain(GAINS_DMIC2, GAIN_RIGHT_OFFSET);
+ abe_unmute_gain(GAINS_DMIC3, GAIN_LEFT_OFFSET);
+ abe_unmute_gain(GAINS_DMIC3, GAIN_RIGHT_OFFSET);
+ abe_unmute_gain(GAINS_AMIC, GAIN_LEFT_OFFSET);
+ abe_unmute_gain(GAINS_AMIC, GAIN_RIGHT_OFFSET);
+/*
+ abe_dsp_set_equalizer(EQ1, abe->dl1_equ_profile);
+ abe_dsp_set_equalizer(EQ2L, abe->dl20_equ_profile);
+ abe_dsp_set_equalizer(EQ2R, abe->dl21_equ_profile);
+ abe_dsp_set_equalizer(EQAMIC, abe->amic_equ_profile);
+ abe_dsp_set_equalizer(EQDMIC, abe->dmic_equ_profile);
+ abe_dsp_set_equalizer(EQSDT, abe->sdt_equ_profile);
+*/
+ abe_set_router_configuration(UPROUTE, 0, (u32 *)abe->router);
+
+ return 0;
+}
+
static int aess_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -1805,8 +1907,12 @@
pm_runtime_get_sync(abe->dev);
- if (!abe->active++)
+ if (!abe->active++) {
+ abe->opp = 0;
+ aess_restore_context(abe);
+ abe_set_opp_mode(abe);
abe_wakeup();
+ }
switch (dai->id) {
case ABE_FRONTEND_DAI_MODEM:
@@ -1906,10 +2012,12 @@
if (!--abe->active) {
abe_disable_irq();
+ aess_save_context(abe);
abe_dsp_shutdown();
- pm_runtime_put_sync(abe->dev);
}
+ pm_runtime_put_sync(abe->dev);
+
mutex_unlock(&abe->mutex);
return 0;
}
@@ -1964,84 +2072,24 @@
static int aess_suspend(struct device *dev)
{
struct abe_data *abe = dev_get_drvdata(dev);
- struct omap4_abe_dsp_pdata *pdata = abe->abe_pdata;
pm_runtime_get_sync(abe->dev);
- if (abe->active && abe_check_activity()) {
- dev_dbg(abe->dev, "Suspend in a middle of ABE activity!\n");
- goto no_suspend;
- }
+ aess_save_context(abe);
- /* TODO: Find a better way to save/retore gains after dor OFF mode */
- abe_mute_gain(MIXSDT, MIX_SDT_INPUT_UP_MIXER);
- abe_mute_gain(MIXSDT, MIX_SDT_INPUT_DL1_MIXER);
- abe_mute_gain(MIXECHO, MIX_ECHO_DL1);
- abe_mute_gain(MIXECHO, MIX_ECHO_DL2);
- abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_MM_DL);
- abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_TONES);
- abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_UPLINK);
- abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_VX_DL);
- abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_TONES);
- abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_DL);
- abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_MM_DL);
- abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_UL);
-
-no_suspend:
pm_runtime_put_sync(abe->dev);
- /*
- * force setting OPP after suspend/resume to ensure
- * ABE freq/volt are set to proper values
- */
- abe->opp = 0;
-
- if (pdata->get_context_loss_count)
- abe->loss_count = pdata->get_context_loss_count(dev);
-
return 0;
}
static int aess_resume(struct device *dev)
{
struct abe_data *abe = dev_get_drvdata(dev);
- struct omap4_abe_dsp_pdata *pdata = abe->abe_pdata;
- int loss_count = 0;
-
- if (pdata->get_context_loss_count)
- loss_count = pdata->get_context_loss_count(dev);
pm_runtime_get_sync(abe->dev);
- if (abe->active && abe_check_activity()) {
- dev_dbg(abe->dev, "Resume in a middle of ABE activity!\n");
- goto no_resume;
- }
+ aess_restore_context(abe);
- if (loss_count != abe->loss_count)
- abe_reload_fw();
-
- /* TODO: Find a better way to save/retore gains after dor OFF mode */
- abe_unmute_gain(MIXSDT, MIX_SDT_INPUT_UP_MIXER);
- abe_unmute_gain(MIXSDT, MIX_SDT_INPUT_DL1_MIXER);
- abe_unmute_gain(MIXECHO, MIX_ECHO_DL1);
- abe_unmute_gain(MIXECHO, MIX_ECHO_DL2);
- abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_MM_DL);
- abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_TONES);
- abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_UPLINK);
- abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_VX_DL);
- abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_TONES);
- abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_DL);
- abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_MM_DL);
- abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_UL);
-// abe_dsp_set_equalizer(EQ1, abe->dl1_equ_profile);
-// abe_dsp_set_equalizer(EQ2L, abe->dl20_equ_profile);
-// abe_dsp_set_equalizer(EQ2R, abe->dl21_equ_profile);
-// abe_dsp_set_equalizer(EQAMIC, abe->amic_equ_profile);
-// abe_dsp_set_equalizer(EQDMIC, abe->dmic_equ_profile);
-// abe_dsp_set_equalizer(EQSDT, abe->sdt_equ_profile);
-
-no_resume:
pm_runtime_put_sync(abe->dev);
return 0;