ASoC: Add a shutdown callback
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Mon, 22 Jun 2009 12:16:51 +0000 (13:16 +0100)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Tue, 23 Jun 2009 22:48:53 +0000 (23:48 +0100)
Ensure that the audio subsystem is powered down cleanly when the system
shuts down by providing a shutdown operation. This ensures that all the
components have been returned to an off state cleanly which should avoid
audio issues from partially charged capacitors or noise on digital inputs
if the system is restarted quickly.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Tested-by: Ben Dooks <ben-linux@fluff.org>
include/sound/soc-dapm.h
sound/soc/soc-core.c
sound/soc/soc-dapm.c

index ec8a45f9a06950f6bf1cfa0ea0d46ed3ca5200f0..35814ced2d2258276543e2241c364a1c49cf2737 100644 (file)
@@ -279,6 +279,7 @@ int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
 /* dapm events */
 int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream,
        int event);
+void snd_soc_dapm_shutdown(struct snd_soc_device *socdev);
 
 /* dapm sys fs - used by the core */
 int snd_soc_dapm_sys_add(struct device *dev);
index 44141178ff4a9f425941e57fc45c2ea5ecf305d0..55d45c43ba16dc64326d5606f3d03fca968554db 100644 (file)
@@ -1020,6 +1020,21 @@ static int soc_remove(struct platform_device *pdev)
        return 0;
 }
 
+static void soc_shutdown(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_card *card = socdev->card;
+
+       if (!card->instantiated)
+               return;
+
+       /* Flush out pmdown_time work - we actually do want to run it
+        * now, we're shutting down so no imminent restart. */
+       run_delayed_work(&card->delayed_work);
+
+       snd_soc_dapm_shutdown(socdev);
+}
+
 /* ASoC platform driver */
 static struct platform_driver soc_driver = {
        .driver         = {
@@ -1030,6 +1045,7 @@ static struct platform_driver soc_driver = {
        .remove         = soc_remove,
        .suspend        = soc_suspend,
        .resume         = soc_resume,
+       .shutdown       = soc_shutdown,
 };
 
 /* create a new pcm */
index 653435930ad8731ccf0a9280cf8630c170b72e8c..b9129efeedf325dc1c7775fe9148d66375e622fe 100644 (file)
@@ -2032,6 +2032,35 @@ void snd_soc_dapm_free(struct snd_soc_device *socdev)
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
 
+/*
+ * snd_soc_dapm_shutdown - callback for system shutdown
+ */
+void snd_soc_dapm_shutdown(struct snd_soc_device *socdev)
+{
+       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_dapm_widget *w;
+       LIST_HEAD(down_list);
+       int powerdown = 0;
+
+       list_for_each_entry(w, &codec->dapm_widgets, list) {
+               if (w->power) {
+                       dapm_seq_insert(w, &down_list, dapm_down_seq);
+                       powerdown = 1;
+               }
+       }
+
+       /* If there were no widgets to power down we're already in
+        * standby.
+        */
+       if (powerdown) {
+               snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_PREPARE);
+               dapm_seq_run(codec, &down_list, 0, dapm_down_seq);
+               snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_STANDBY);
+       }
+
+       snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_OFF);
+}
+
 /* Module information */
 MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
 MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");