From 4031802c9ca18b9f678e6a796b6693baa9fb20b9 Mon Sep 17 00:00:00 2001 From: Misael Lopez Cruz Date: Fri, 29 Jul 2011 03:07:32 -0500 Subject: ASoC: DSP: Add suspend/resume for FEs Currently, FEs were suspending/resuming their BE clients but were not suspending/resuming themselves. Change-Id: Ic23b23755ebace644604f37d73c6849166428862 Signed-off-by: Misael Lopez Cruz --- sound/soc/soc-core.c | 6 ++---- sound/soc/soc-dsp.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1de7a50..19ea797 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1192,8 +1192,7 @@ int snd_soc_suspend(struct device *dev) continue; if (card->rtd[i].dai_link->dynamic) { - soc_dsp_be_cpu_dai_suspend(&card->rtd[i]); - soc_dsp_be_platform_suspend(&card->rtd[i]); + soc_dsp_fe_suspend(&card->rtd[i]); } else { if (cpu_dai->driver->suspend && !cpu_dai->driver->ac97_control) cpu_dai->driver->suspend(cpu_dai); @@ -1363,8 +1362,7 @@ static void soc_resume_deferred(struct work_struct *work) continue; if (card->rtd[i].dai_link->dynamic) { - soc_dsp_be_cpu_dai_resume(&card->rtd[i]); - soc_dsp_be_platform_resume(&card->rtd[i]); + soc_dsp_fe_resume(&card->rtd[i]); } else { if (cpu_dai->driver->resume && !cpu_dai->driver->ac97_control) cpu_dai->driver->resume(cpu_dai); diff --git a/sound/soc/soc-dsp.c b/sound/soc/soc-dsp.c index 1770ee8..50e5e17 100644 --- a/sound/soc/soc-dsp.c +++ b/sound/soc/soc-dsp.c @@ -1318,6 +1318,27 @@ int soc_dsp_be_platform_suspend(struct snd_soc_pcm_runtime *fe) return 0; } +int soc_dsp_fe_suspend(struct snd_soc_pcm_runtime *fe) +{ + struct snd_soc_dai *dai = fe->cpu_dai; + struct snd_soc_dai_driver *dai_drv = dai->driver; + struct snd_soc_platform *platform = fe->platform; + struct snd_soc_platform_driver *plat_drv = platform->driver; + + if (dai_drv->suspend && !dai_drv->ac97_control) + dai_drv->suspend(dai); + + if (plat_drv->suspend && !platform->suspended) { + plat_drv->suspend(dai); + platform->suspended = 1; + } + + soc_dsp_be_cpu_dai_suspend(fe); + soc_dsp_be_platform_suspend(fe); + + return 0; +} + int soc_dsp_be_cpu_dai_resume(struct snd_soc_pcm_runtime *fe) { struct snd_soc_dsp_params *dsp_params; @@ -1453,6 +1474,27 @@ int soc_dsp_be_platform_resume(struct snd_soc_pcm_runtime *fe) return 0; } +int soc_dsp_fe_resume(struct snd_soc_pcm_runtime *fe) +{ + struct snd_soc_dai *dai = fe->cpu_dai; + struct snd_soc_dai_driver *dai_drv = dai->driver; + struct snd_soc_platform *platform = fe->platform; + struct snd_soc_platform_driver *plat_drv = platform->driver; + + soc_dsp_be_cpu_dai_resume(fe); + soc_dsp_be_platform_resume(fe); + + if (dai_drv->resume && !dai_drv->ac97_control) + dai_drv->resume(dai); + + if (plat_drv->resume && platform->suspended) { + plat_drv->resume(dai); + platform->suspended = 0; + } + + return 0; +} + /* called when opening FE stream */ int soc_dsp_fe_dai_open(struct snd_pcm_substream *fe_substream) { -- cgit v1.1 From fb64bd3215ec018e8dcd86226c9b7051c09caf0c Mon Sep 17 00:00:00 2001 From: Misael Lopez Cruz Date: Thu, 28 Jul 2011 13:40:11 -0500 Subject: ASoC: ABE: Add DAI driver suspend/resume Add suspend and resume handlers for ABE DAI driver. DAI related gains will be saved/muted if that particular DAI gets suspended, otherwise gains are kept (ignore suspend usecase). Gains are restored/unmuted upon resume. Change-Id: Ib84278618745a474f627f41d765bbbfb1de74d9f Signed-off-by: Misael Lopez Cruz --- sound/soc/omap/omap-abe.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/omap/omap-abe.h | 4 +- 2 files changed, 103 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/omap/omap-abe.c b/sound/soc/omap/omap-abe.c index 6555a82..0c48828 100644 --- a/sound/soc/omap/omap-abe.c +++ b/sound/soc/omap/omap-abe.c @@ -56,6 +56,9 @@ struct omap_abe_data { /* BE & FE Ports */ struct omap_abe_port *port[OMAP_ABE_MAX_PORT_ID + 1]; + + int active_dais; + int suspended_dais; }; /* @@ -782,6 +785,8 @@ static int omap_abe_dai_startup(struct snd_pcm_substream *substream, dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + abe_priv->active_dais++; + if (dai->id == ABE_FRONTEND_DAI_MODEM) { ret = modem_get_dai(substream, dai); @@ -1065,7 +1070,88 @@ static void omap_abe_dai_shutdown(struct snd_pcm_substream *substream, snd_soc_dai_shutdown(abe_priv->modem_substream[substream->stream], abe_priv->modem_dai); } + + abe_priv->active_dais--; +} + +#ifdef CONFIG_PM +static int omap_abe_dai_suspend(struct snd_soc_dai *dai) +{ + struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai); + + dev_dbg(dai->dev, "%s: %s active %d\n", + __func__, dai->name, dai->active); + + if (!dai->active) + return 0; + + if (++abe_priv->suspended_dais < abe_priv->active_dais) + return 0; + + 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); + + return 0; +} + +static int omap_abe_dai_resume(struct snd_soc_dai *dai) +{ + struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai); + + dev_dbg(dai->dev, "%s: %s active %d\n", + __func__, dai->name, dai->active); + + if (!dai->active) + return 0; + + if (abe_priv->suspended_dais-- < abe_priv->active_dais) + return 0; + + 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); + + return 0; } +#else +#define omap_abe_dai_suspend NULL +#define omap_abe_dai_resume NULL +#endif static int omap_abe_dai_probe(struct snd_soc_dai *dai) { @@ -1125,6 +1211,8 @@ static struct snd_soc_dai_driver omap_abe_dai[] = { .name = "MultiMedia1", .probe = omap_abe_dai_probe, .remove = omap_abe_dai_remove, + .suspend = omap_abe_dai_suspend, + .resume = omap_abe_dai_resume, .playback = { .stream_name = "MultiMedia1 Playback", .channels_min = 1, @@ -1143,6 +1231,8 @@ static struct snd_soc_dai_driver omap_abe_dai[] = { }, { /* Multimedia Capture */ .name = "MultiMedia2", + .suspend = omap_abe_dai_suspend, + .resume = omap_abe_dai_resume, .capture = { .stream_name = "MultiMedia2 Capture", .channels_min = 1, @@ -1154,6 +1244,8 @@ static struct snd_soc_dai_driver omap_abe_dai[] = { }, { /* Voice Playback and Capture */ .name = "Voice", + .suspend = omap_abe_dai_suspend, + .resume = omap_abe_dai_resume, .playback = { .stream_name = "Voice Playback", .channels_min = 1, @@ -1172,6 +1264,8 @@ static struct snd_soc_dai_driver omap_abe_dai[] = { }, { /* Tones Playback */ .name = "Tones", + .suspend = omap_abe_dai_suspend, + .resume = omap_abe_dai_resume, .playback = { .stream_name = "Tones Playback", .channels_min = 1, @@ -1183,6 +1277,8 @@ static struct snd_soc_dai_driver omap_abe_dai[] = { }, { /* Vibra */ .name = "Vibra", + .suspend = omap_abe_dai_suspend, + .resume = omap_abe_dai_resume, .playback = { .stream_name = "Vibra Playback", .channels_min = 2, @@ -1194,6 +1290,8 @@ static struct snd_soc_dai_driver omap_abe_dai[] = { }, { /* MODEM Voice Playback and Capture */ .name = "MODEM", + .suspend = omap_abe_dai_suspend, + .resume = omap_abe_dai_resume, .playback = { .stream_name = "Voice Playback", .channels_min = 1, @@ -1212,6 +1310,8 @@ static struct snd_soc_dai_driver omap_abe_dai[] = { }, { /* Low Power HiFi Playback */ .name = "MultiMedia1 LP", + .suspend = omap_abe_dai_suspend, + .resume = omap_abe_dai_resume, .playback = { .stream_name = "MultiMedia1 LP Playback", .channels_min = 2, diff --git a/sound/soc/omap/omap-abe.h b/sound/soc/omap/omap-abe.h index 7aca33e..5bdab50 100644 --- a/sound/soc/omap/omap-abe.h +++ b/sound/soc/omap/omap-abe.h @@ -30,7 +30,8 @@ #define ABE_FRONTEND_DAI_TONES 3 #define ABE_FRONTEND_DAI_VIBRA 4 #define ABE_FRONTEND_DAI_MODEM 5 -#define ABE_FRONTEND_DAI_LP_MEDIA 6 +#define ABE_FRONTEND_DAI_LP_MEDIA 6 +#define ABE_FRONTEND_DAI_NUM 7 /* This must currently match the BE order in DSP */ #define OMAP_ABE_DAI_PDM_UL 0 @@ -43,6 +44,7 @@ #define OMAP_ABE_DAI_DMIC0 7 #define OMAP_ABE_DAI_DMIC1 8 #define OMAP_ABE_DAI_DMIC2 9 +#define OMAP_ABE_DAI_NUM 10 #define OMAP_ABE_BE_PDM_DL1 "PDM-DL1" #define OMAP_ABE_BE_PDM_UL1 "PDM-UL1" -- cgit v1.1 From bbdfc12da28c8df052e5e94ca0efbdf6cefb2199 Mon Sep 17 00:00:00 2001 From: Misael Lopez Cruz Date: Thu, 28 Jul 2011 13:40:42 -0500 Subject: ASoC: ABE DSP: Add platform driver suspend/resume ABE backends gains will be saved/muted if that particular BE gets suspended, otherwise gains are kept (ignore suspend usecase). Gains are restored/unmuted upon resume. Change-Id: I93577952011aae8acba3da76e3d4ceea44d7be13 Signed-off-by: Misael Lopez Cruz --- sound/soc/omap/omap-abe-dsp.c | 157 ++++++++++++++++++++++++++++++++---------- 1 file changed, 119 insertions(+), 38 deletions(-) (limited to 'sound') diff --git a/sound/soc/omap/omap-abe-dsp.c b/sound/soc/omap/omap-abe-dsp.c index 953d25e..007b87d 100644 --- a/sound/soc/omap/omap-abe-dsp.c +++ b/sound/soc/omap/omap-abe-dsp.c @@ -2058,43 +2058,6 @@ static struct snd_pcm_ops omap_aess_pcm_ops = { .mmap = aess_mmap, }; -#if CONFIG_PM -static int aess_suspend(struct device *dev) -{ - struct abe_data *abe = dev_get_drvdata(dev); - - pm_runtime_get_sync(abe->dev); - - aess_save_context(abe); - - pm_runtime_put_sync(abe->dev); - - return 0; -} - -static int aess_resume(struct device *dev) -{ - struct abe_data *abe = dev_get_drvdata(dev); - - pm_runtime_get_sync(abe->dev); - - aess_restore_context(abe); - - pm_runtime_put_sync(abe->dev); - - return 0; -} - -#else -#define aess_suspend NULL -#define aess_resume NULL -#endif - -static const struct dev_pm_ops aess_pm_ops = { - .suspend = aess_suspend, - .resume = aess_resume, -}; - static int aess_stream_event(struct snd_soc_dapm_context *dapm) { struct snd_soc_platform *platform = dapm->platform; @@ -2159,6 +2122,123 @@ static int abe_add_widgets(struct snd_soc_platform *platform) return 0; } +#ifdef CONFIG_PM +static int abe_suspend(struct snd_soc_dai *dai) +{ + struct abe_data *abe = the_abe; + struct omap4_abe_dsp_pdata *pdata = abe->abe_pdata; + int ret = 0; + + dev_dbg(dai->dev, "%s: %s active %d\n", + __func__, dai->name, dai->active); + + if (!dai->active) + return 0; + + pm_runtime_get_sync(abe->dev); + + switch (dai->id) { + case OMAP_ABE_DAI_PDM_UL: + abe_mute_gain(GAINS_AMIC, GAIN_LEFT_OFFSET); + abe_mute_gain(GAINS_AMIC, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_PDM_DL1: + case OMAP_ABE_DAI_PDM_DL2: + case OMAP_ABE_DAI_PDM_VIB: + case OMAP_ABE_DAI_BT_VX: + case OMAP_ABE_DAI_MM_FM: + case OMAP_ABE_DAI_MODEM: + break; + case OMAP_ABE_DAI_DMIC0: + abe_mute_gain(GAINS_DMIC1, GAIN_LEFT_OFFSET); + abe_mute_gain(GAINS_DMIC1, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_DMIC1: + abe_mute_gain(GAINS_DMIC2, GAIN_LEFT_OFFSET); + abe_mute_gain(GAINS_DMIC2, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_DMIC2: + abe_mute_gain(GAINS_DMIC3, GAIN_LEFT_OFFSET); + abe_mute_gain(GAINS_DMIC3, GAIN_RIGHT_OFFSET); + break; + default: + dev_err(dai->dev, "%s: invalid DAI id %d\n", + __func__, dai->id); + ret = -EINVAL; + goto out; + } + + if (pdata->get_context_loss_count) + abe->loss_count = pdata->get_context_loss_count(abe->dev); + +out: + pm_runtime_put_sync(abe->dev); + return ret; +} + +static int abe_resume(struct snd_soc_dai *dai) +{ + struct abe_data *abe = the_abe; + struct omap4_abe_dsp_pdata *pdata = abe->abe_pdata; + int loss_count = 0, ret = 0; + + dev_dbg(dai->dev, "%s: %s active %d\n", + __func__, dai->name, dai->active); + + if (!dai->active) + return 0; + + if (pdata->get_context_loss_count) + loss_count = pdata->get_context_loss_count(abe->dev); + + pm_runtime_get_sync(abe->dev); + omap_device_set_rate(&abe->dev, &abe->dev, 98000000); + + if (loss_count != abe->loss_count) + abe_reload_fw(); + + switch (dai->id) { + case OMAP_ABE_DAI_PDM_UL: + abe_unmute_gain(GAINS_AMIC, GAIN_LEFT_OFFSET); + abe_unmute_gain(GAINS_AMIC, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_PDM_DL1: + case OMAP_ABE_DAI_PDM_DL2: + case OMAP_ABE_DAI_PDM_VIB: + case OMAP_ABE_DAI_BT_VX: + case OMAP_ABE_DAI_MM_FM: + case OMAP_ABE_DAI_MODEM: + break; + case OMAP_ABE_DAI_DMIC0: + abe_unmute_gain(GAINS_DMIC1, GAIN_LEFT_OFFSET); + abe_unmute_gain(GAINS_DMIC1, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_DMIC1: + abe_unmute_gain(GAINS_DMIC2, GAIN_LEFT_OFFSET); + abe_unmute_gain(GAINS_DMIC2, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_DMIC2: + abe_unmute_gain(GAINS_DMIC3, GAIN_LEFT_OFFSET); + abe_unmute_gain(GAINS_DMIC3, GAIN_RIGHT_OFFSET); + break; + default: + dev_err(dai->dev, "%s: invalid DAI id %d\n", + __func__, dai->id); + ret = -EINVAL; + goto out; + } + + abe_set_router_configuration(UPROUTE, 0, (u32 *)abe->router); + +out: + pm_runtime_put_sync(abe->dev); + return ret; +} +#else +#define abe_suspend NULL +#define abe_resume NULL +#endif + static int abe_probe(struct snd_soc_platform *platform) { struct abe_data *abe = snd_soc_platform_get_drvdata(platform); @@ -2323,6 +2403,8 @@ static struct snd_soc_platform_driver omap_aess_platform = { .ops = &omap_aess_pcm_ops, .probe = abe_probe, .remove = abe_remove, + .suspend = abe_suspend, + .resume = abe_resume, .read = abe_dsp_read, .write = abe_dsp_write, .stream_event = aess_stream_event, @@ -2403,7 +2485,6 @@ static struct platform_driver omap_aess_driver = { .driver = { .name = "aess", .owner = THIS_MODULE, - .pm = &aess_pm_ops, }, .probe = abe_engine_probe, .remove = __devexit_p(abe_engine_remove), -- cgit v1.1 From 42fe5ffe2507ab7c9283d704ce21d0911e32667c Mon Sep 17 00:00:00 2001 From: Misael Lopez Cruz Date: Fri, 29 Jul 2011 05:40:50 -0500 Subject: ASoC: sdp4430: Ignore suspend for legacy DAI links Allow ignore suspend for legacy DAI links in order to prevent legacy links to interfere with modem voice call usecase where TWL6040 is expected to remain on. Change-Id: I241ae34d7a17755e0db645b9b9e32586ed4dd935 Signed-off-by: Francois Mazard Signed-off-by: Misael Lopez Cruz --- sound/soc/omap/sdp4430.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/omap/sdp4430.c b/sound/soc/omap/sdp4430.c index b84399a..f9cc8cd 100644 --- a/sound/soc/omap/sdp4430.c +++ b/sound/soc/omap/sdp4430.c @@ -580,6 +580,7 @@ static struct snd_soc_dai_link sdp4430_dai[] = { .no_codec = 1, /* TODO: have a dummy CODEC */ .ops = &sdp4430_mcbsp_ops, + .ignore_suspend = 1, }, { .name = "Legacy McPDM", @@ -594,6 +595,7 @@ static struct snd_soc_dai_link sdp4430_dai[] = { .codec_name = "twl6040-codec", .ops = &sdp4430_mcpdm_ops, + .ignore_suspend = 1, }, /* -- cgit v1.1