ASoC: Add support for automatically going to BIAS_OFF on suspend
authorLars-Peter Clausen <lars@metafoo.de>
Thu, 4 Sep 2014 17:44:06 +0000 (19:44 +0200)
committerMark Brown <broonie@kernel.org>
Thu, 4 Sep 2014 19:10:25 +0000 (20:10 +0100)
There is a substantial amount of drivers that in go to SND_SOC_BIAS_OFF on
suspend and go back to SND_SOC_BIAS_SUSPEND on resume (Often this is even
the only thing done in the suspend and resume handlers). This patch
introduces a new suspend_bias_off flag, which when set by a driver will let
the ASoC core automatically put the device's DAPM context at the
SND_SOC_BIAS_OFF level during suspend. Once the device is resumed the DAPM
context will go back to SND_SOC_BIAS_STANDBY (if the context is idle,
otherwise to SND_SOC_BIAS_ON).

This will allow us to remove a fair bit of duplicated code from the drivers.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Mark Brown <broonie@kernel.org>
include/sound/soc-dapm.h
include/sound/soc.h
sound/soc/soc-core.c
sound/soc/soc-dapm.c

index aac04ff84eea5674279fd22984db6ca9b79ba8c7..f955d65c5656abe2258decc1073b04fd9efa7d00 100644 (file)
@@ -587,7 +587,8 @@ struct snd_soc_dapm_context {
        enum snd_soc_bias_level suspend_bias_level;
        struct delayed_work delayed_work;
        unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
-
+       /* Go to BIAS_OFF in suspend if the DAPM context is idle */
+       unsigned int suspend_bias_off:1;
        void (*seq_notifier)(struct snd_soc_dapm_context *,
                             enum snd_soc_dapm_type, int);
 
index ce09302bfd6d68686b57268b44ddce1f1ece73c4..ac99fc083eecad03b80121e713f7a6f7d7a26178 100644 (file)
@@ -848,6 +848,7 @@ struct snd_soc_codec_driver {
        int (*set_bias_level)(struct snd_soc_codec *,
                              enum snd_soc_bias_level level);
        bool idle_bias_off;
+       bool suspend_bias_off;
 
        void (*seq_notifier)(struct snd_soc_dapm_context *,
                             enum snd_soc_dapm_type, int);
index 068785fa1a0668c0dfd0706029450d4f56269a33..2bdf9a4ac2b4c25d59b0a26a9eab67e9e34b5347 100644 (file)
@@ -4402,6 +4402,7 @@ int snd_soc_register_codec(struct device *dev,
        codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time;
        codec->dapm.codec = codec;
        codec->dapm.idle_bias_off = codec_drv->idle_bias_off;
+       codec->dapm.suspend_bias_off = codec_drv->suspend_bias_off;
        if (codec_drv->seq_notifier)
                codec->dapm.seq_notifier = codec_drv->seq_notifier;
        if (codec_drv->set_bias_level)
index 8348352dc2c62c484a1efba6f04c290367b93864..a2025a6b6a2956917ba767dd3ae874296e232fbc 100644 (file)
@@ -1683,6 +1683,22 @@ static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
        }
 }
 
+static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm)
+{
+       if (dapm->idle_bias_off)
+               return true;
+
+       switch (snd_power_get_state(dapm->card->snd_card)) {
+       case SNDRV_CTL_POWER_D3hot:
+       case SNDRV_CTL_POWER_D3cold:
+               return dapm->suspend_bias_off;
+       default:
+               break;
+       }
+
+       return false;
+}
+
 /*
  * Scan each dapm widget for complete audio path.
  * A complete path is a route that has valid endpoints i.e.:-
@@ -1706,7 +1722,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event)
        trace_snd_soc_dapm_start(card);
 
        list_for_each_entry(d, &card->dapm_list, list) {
-               if (d->idle_bias_off)
+               if (dapm_idle_bias_off(d))
                        d->target_bias_level = SND_SOC_BIAS_OFF;
                else
                        d->target_bias_level = SND_SOC_BIAS_STANDBY;
@@ -1772,7 +1788,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event)
                if (d->target_bias_level > bias)
                        bias = d->target_bias_level;
        list_for_each_entry(d, &card->dapm_list, list)
-               if (!d->idle_bias_off)
+               if (!dapm_idle_bias_off(d))
                        d->target_bias_level = bias;
 
        trace_snd_soc_dapm_walk_done(card);