ASoC: wm5100: Use pm_runtime for powerdown managment
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Thu, 26 Jan 2012 17:28:49 +0000 (17:28 +0000)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Thu, 26 Jan 2012 18:39:24 +0000 (18:39 +0000)
Using pm_runtime to decide if the device should go into full power down
has the dual advantage of allowing easier integration with non-DAPM
reasons to power on the device (like the FLL) and allowing userspace to
control the final power down which is useful for tuning retention of
DSP firmware.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
sound/soc/codecs/wm5100.c

index 39de946bf259cc46bb2611bf059d7d8a66bd7427..c6c382197fe2e14dba6c79bddfed7e569c00fb0b 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/gcd.h>
 #include <linux/gpio.h>
 #include <linux/i2c.h>
+#include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 #include <linux/regulator/fixed.h>
 #include <linux/slab.h>
@@ -1261,54 +1262,6 @@ static const __devinitdata struct reg_default wm5100_reva_patches[] = {
        { WM5100_AUDIO_IF_3_19, 1 },
 };
 
-static int wm5100_set_bias_level(struct snd_soc_codec *codec,
-                                enum snd_soc_bias_level level)
-{
-       struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
-       int ret;
-
-       switch (level) {
-       case SND_SOC_BIAS_ON:
-               break;
-
-       case SND_SOC_BIAS_PREPARE:
-               break;
-
-       case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
-                       ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies),
-                                                   wm5100->core_supplies);
-                       if (ret != 0) {
-                               dev_err(codec->dev,
-                                       "Failed to enable supplies: %d\n",
-                                       ret);
-                               return ret;
-                       }
-
-                       if (wm5100->pdata.ldo_ena) {
-                               gpio_set_value_cansleep(wm5100->pdata.ldo_ena,
-                                                       1);
-                               msleep(2);
-                       }
-
-                       regcache_cache_only(wm5100->regmap, false);
-                       regcache_sync(wm5100->regmap);
-               }
-               break;
-
-       case SND_SOC_BIAS_OFF:
-               regcache_cache_only(wm5100->regmap, true);
-               if (wm5100->pdata.ldo_ena)
-                       gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
-               regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
-                                      wm5100->core_supplies);
-               break;
-       }
-       codec->dapm.bias_level = level;
-
-       return 0;
-}
-
 static int wm5100_dai_to_base(struct snd_soc_dai *dai)
 {
        switch (dai->id) {
@@ -1836,6 +1789,8 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 
        if (!Fout) {
                dev_dbg(codec->dev, "FLL%d disabled", fll_id);
+               if (fll->fout)
+                       pm_runtime_put(codec->dev);
                fll->fout = 0;
                snd_soc_update_bits(codec, base + 1, WM5100_FLL1_ENA, 0);
                return 0;
@@ -1880,6 +1835,8 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
        /* Clear any pending completions */
        try_wait_for_completion(&fll->lock);
 
+       pm_runtime_get_sync(codec->dev);
+
        snd_soc_update_bits(codec, base + 1, WM5100_FLL1_ENA, WM5100_FLL1_ENA);
 
        if (i2c->irq)
@@ -1914,6 +1871,7 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
        }
        if (i == timeout) {
                dev_err(codec->dev, "FLL%d lock timed out\n", fll_id);
+               pm_runtime_put(codec->dev);
                return -ETIMEDOUT;
        }
 
@@ -2377,9 +2335,6 @@ static int wm5100_probe(struct snd_soc_codec *codec)
                return ret;
        }
 
-       regcache_cache_only(wm5100->regmap, true);
-
-
        for (i = 0; i < ARRAY_SIZE(wm5100_dig_vu); i++)
                snd_soc_update_bits(codec, wm5100_dig_vu[i], WM5100_OUT_VU,
                                    WM5100_OUT_VU);
@@ -2405,14 +2360,6 @@ static int wm5100_probe(struct snd_soc_codec *codec)
                }
        }
 
-       /* We'll get woken up again when the system has something useful
-        * for us to do.
-        */
-       if (wm5100->pdata.ldo_ena)
-               gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
-       regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
-                              wm5100->core_supplies);
-
        return 0;
 
 err_gpio:
@@ -2444,7 +2391,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5100 = {
 
        .set_sysclk = wm5100_set_sysclk,
        .set_pll = wm5100_set_fll,
-       .set_bias_level = wm5100_set_bias_level,
        .idle_bias_off = 1,
        .reg_cache_size = WM5100_MAX_REGISTER,
        .volatile_register = wm5100_soc_volatile,
@@ -2661,6 +2607,10 @@ static __devinit int wm5100_i2c_probe(struct i2c_client *i2c,
                }
        }
 
+       pm_runtime_set_active(&i2c->dev);
+       pm_runtime_enable(&i2c->dev);
+       pm_request_idle(&i2c->dev);
+
        ret = snd_soc_register_codec(&i2c->dev,
                                     &soc_codec_dev_wm5100, wm5100_dai,
                                     ARRAY_SIZE(wm5100_dai));
@@ -2714,6 +2664,51 @@ static __devexit int wm5100_i2c_remove(struct i2c_client *i2c)
        return 0;
 }
 
+#ifdef CONFIG_PM_RUNTIME
+static int wm5100_runtime_suspend(struct device *dev)
+{
+       struct wm5100_priv *wm5100 = dev_get_drvdata(dev);
+
+       regcache_cache_only(wm5100->regmap, true);
+       regcache_mark_dirty(wm5100->regmap);
+       if (wm5100->pdata.ldo_ena)
+               gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
+       regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
+                              wm5100->core_supplies);
+
+       return 0;
+}
+
+static int wm5100_runtime_resume(struct device *dev)
+{
+       struct wm5100_priv *wm5100 = dev_get_drvdata(dev);
+       int ret;
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies),
+                                   wm5100->core_supplies);
+       if (ret != 0) {
+               dev_err(dev, "Failed to enable supplies: %d\n",
+                       ret);
+               return ret;
+       }
+
+       if (wm5100->pdata.ldo_ena) {
+               gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 1);
+               msleep(2);
+       }
+
+       regcache_cache_only(wm5100->regmap, false);
+       regcache_sync(wm5100->regmap);
+
+       return 0;
+}
+#endif
+
+static struct dev_pm_ops wm5100_pm = {
+       SET_RUNTIME_PM_OPS(wm5100_runtime_suspend, wm5100_runtime_resume,
+                          NULL)
+};
+
 static const struct i2c_device_id wm5100_i2c_id[] = {
        { "wm5100", 0 },
        { }
@@ -2724,6 +2719,7 @@ static struct i2c_driver wm5100_i2c_driver = {
        .driver = {
                .name = "wm5100",
                .owner = THIS_MODULE,
+               .pm = &wm5100_pm,
        },
        .probe =    wm5100_i2c_probe,
        .remove =   __devexit_p(wm5100_i2c_remove),