aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorLiam Girdwood <lg@opensource.wolfsonmicro.com>2007-01-31 08:14:57 -0500
committerJaroslav Kysela <perex@suse.cz>2007-02-09 03:03:27 -0500
commit965ac42ce919db225ee64678f0be02f2fdf5b5e4 (patch)
tree832436b24c8a02a879de8efc7869bbfe06de2018 /sound
parentbeb60119bcc9cbd80bc5b4f7feec419e067d3e46 (diff)
[ALSA] ASoC force running of delayed PM work at suspend() and remove()
This patch fixes a bug whereby the power management delayed work would never be run at driver suspend() or module remove(). Delayed work would be created (after audio had finished) with a long delay (~5 secs) and was sometimes never queued before flush_scheduled_work() was being called at suspend or module remove. This caused the delayed work to queued after the module had been removed or after resume. This patch forces any delayed work to complete by cancelling it (timer cannot fire and add it to queue later), scheduling it for now and waiting on it's completion. This is something I probably would like to add to workqueue.c in the next merge window, however it's here atm because it can oops. Signed-off-by: Liam Girdwood <lg@opensource.wolfsonmicro.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/soc-core.c23
1 files changed, 22 insertions, 1 deletions
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 736949fbb4d5..e5aa1c20dddb 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -77,6 +77,25 @@ static int pmdown_time = 5000;
77module_param(pmdown_time, int, 0); 77module_param(pmdown_time, int, 0);
78MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); 78MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)");
79 79
80/*
81 * This function forces any delayed work to be queued and run.
82 */
83static int run_delayed_work(struct delayed_work *dwork)
84{
85 int ret;
86
87 /* cancel any work waiting to be queued. */
88 ret = cancel_delayed_work(dwork);
89
90 /* if there was any work waiting then we run it now and
91 * wait for it's completion */
92 if (ret) {
93 schedule_delayed_work(dwork, 0);
94 flush_scheduled_work();
95 }
96 return ret;
97}
98
80#ifdef CONFIG_SND_SOC_AC97_BUS 99#ifdef CONFIG_SND_SOC_AC97_BUS
81/* unregister ac97 codec */ 100/* unregister ac97 codec */
82static int soc_ac97_dev_unregister(struct snd_soc_codec *codec) 101static int soc_ac97_dev_unregister(struct snd_soc_codec *codec)
@@ -1101,7 +1120,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state)
1101 } 1120 }
1102 1121
1103 /* close any waiting streams and save state */ 1122 /* close any waiting streams and save state */
1104 flush_scheduled_work(); 1123 run_delayed_work(&socdev->delayed_work);
1105 codec->suspend_dapm_state = codec->dapm_state; 1124 codec->suspend_dapm_state = codec->dapm_state;
1106 1125
1107 for(i = 0; i < codec->num_dai; i++) { 1126 for(i = 0; i < codec->num_dai; i++) {
@@ -1255,6 +1274,8 @@ static int soc_remove(struct platform_device *pdev)
1255 struct snd_soc_platform *platform = socdev->platform; 1274 struct snd_soc_platform *platform = socdev->platform;
1256 struct snd_soc_codec_device *codec_dev = socdev->codec_dev; 1275 struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
1257 1276
1277 run_delayed_work(&socdev->delayed_work);
1278
1258 if (platform->remove) 1279 if (platform->remove)
1259 platform->remove(pdev); 1280 platform->remove(pdev);
1260 1281