ASoC: wm8962: Convert to runtime PM for bias off management
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Wed, 1 Feb 2012 12:48:59 +0000 (12:48 +0000)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Fri, 17 Feb 2012 06:32:04 +0000 (22:32 -0800)
This allows userspace control of final power off, allowing policy decisions
for register configuration retention.

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

index 3dba53ace6bd5b082a46f65c250345436d4e1504..28d2e74ed01f6d7dbc131ea06473bc0695eeb5f8 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
@@ -2479,9 +2480,6 @@ static void wm8962_configure_bclk(struct snd_soc_codec *codec)
 static int wm8962_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
-       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
-       int ret;
-
        if (level == codec->dapm.bias_level)
                return 0;
 
@@ -2498,51 +2496,15 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
-                       ret = regulator_bulk_enable(ARRAY_SIZE(wm8962->supplies),
-                                                   wm8962->supplies);
-                       if (ret != 0) {
-                               dev_err(codec->dev,
-                                       "Failed to enable supplies: %d\n",
-                                       ret);
-                               return ret;
-                       }
-
-                       regcache_cache_only(wm8962->regmap, false);
-                       regcache_sync(wm8962->regmap);
-
-                       snd_soc_update_bits(codec, WM8962_ANTI_POP,
-                                           WM8962_STARTUP_BIAS_ENA |
-                                           WM8962_VMID_BUF_ENA,
-                                           WM8962_STARTUP_BIAS_ENA |
-                                           WM8962_VMID_BUF_ENA);
-
-                       /* Bias enable at 2*50k for ramp */
-                       snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
-                                           WM8962_VMID_SEL_MASK |
-                                           WM8962_BIAS_ENA,
-                                           WM8962_BIAS_ENA | 0x180);
-
-                       msleep(5);
-               }
-
                /* VMID 2*250k */
                snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
                                    WM8962_VMID_SEL_MASK, 0x100);
                break;
 
        case SND_SOC_BIAS_OFF:
-               snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
-                                   WM8962_VMID_SEL_MASK | WM8962_BIAS_ENA, 0);
-
-               snd_soc_update_bits(codec, WM8962_ANTI_POP,
-                                   WM8962_STARTUP_BIAS_ENA |
-                                   WM8962_VMID_BUF_ENA, 0);
-
-               regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies),
-                                      wm8962->supplies);
                break;
        }
+
        codec->dapm.bias_level = level;
        return 0;
 }
@@ -2844,6 +2806,8 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
                snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
                                    WM8962_FLL_ENA, 0);
 
+               pm_runtime_put(codec->dev);
+
                return 0;
        }
 
@@ -2892,6 +2856,7 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 
        try_wait_for_completion(&wm8962->fll_lock);
 
+       pm_runtime_get_sync(codec->dev);
 
        snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
                            WM8962_FLL_FRAC | WM8962_FLL_REFCLK_SRC_MASK |
@@ -3689,7 +3654,9 @@ static __devinit int wm8962_i2c_probe(struct i2c_client *i2c,
                                ret);
        }
 
-       regcache_cache_only(wm8962->regmap, true);
+       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_wm8962, &wm8962_dai, 1);
@@ -3721,6 +3688,69 @@ static __devexit int wm8962_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
+#ifdef CONFIG_PM_RUNTIME
+static int wm8962_runtime_resume(struct device *dev)
+{
+       struct wm8962_priv *wm8962 = dev_get_drvdata(dev);
+       int ret;
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8962->supplies),
+                                   wm8962->supplies);
+       if (ret != 0) {
+               dev_err(dev,
+                       "Failed to enable supplies: %d\n", ret);
+               return ret;
+       }
+
+       regcache_cache_only(wm8962->regmap, false);
+       regcache_sync(wm8962->regmap);
+
+       regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP,
+                          WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA,
+                          WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA);
+
+       /* Bias enable at 2*50k for ramp */
+       regmap_update_bits(wm8962->regmap, WM8962_PWR_MGMT_1,
+                          WM8962_VMID_SEL_MASK | WM8962_BIAS_ENA,
+                          WM8962_BIAS_ENA | 0x180);
+
+       msleep(5);
+
+       /* VMID back to 2x250k for standby */
+       regmap_update_bits(wm8962->regmap, WM8962_PWR_MGMT_1,
+                          WM8962_VMID_SEL_MASK, 0x100);
+
+       dev_crit(dev, "RESUME\n");
+
+       return 0;
+}
+
+static int wm8962_runtime_suspend(struct device *dev)
+{
+       struct wm8962_priv *wm8962 = dev_get_drvdata(dev);
+
+       dev_crit(dev, "SUSPEND\n");
+
+       regmap_update_bits(wm8962->regmap, WM8962_PWR_MGMT_1,
+                          WM8962_VMID_SEL_MASK | WM8962_BIAS_ENA, 0);
+
+       regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP,
+                          WM8962_STARTUP_BIAS_ENA |
+                          WM8962_VMID_BUF_ENA, 0);
+
+       regcache_cache_only(wm8962->regmap, true);
+
+       regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies),
+                              wm8962->supplies);
+
+       return 0;
+}
+#endif
+
+static struct dev_pm_ops wm8962_pm = {
+       SET_RUNTIME_PM_OPS(wm8962_runtime_suspend, wm8962_runtime_resume, NULL)
+};
+
 static const struct i2c_device_id wm8962_i2c_id[] = {
        { "wm8962", 0 },
        { }
@@ -3731,6 +3761,7 @@ static struct i2c_driver wm8962_i2c_driver = {
        .driver = {
                .name = "wm8962",
                .owner = THIS_MODULE,
+               .pm = &wm8962_pm,
        },
        .probe =    wm8962_i2c_probe,
        .remove =   __devexit_p(wm8962_i2c_remove),