Commit d23031a4 authored by Mark Brown's avatar Mark Brown

ASoC: wm8962: Convert to runtime PM for bias off management

This allows userspace control of final power off, allowing policy decisions
for register configuration retention.
Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
parent a968d9db
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -2479,9 +2480,6 @@ static void wm8962_configure_bclk(struct snd_soc_codec *codec) ...@@ -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, static int wm8962_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
int ret;
if (level == codec->dapm.bias_level) if (level == codec->dapm.bias_level)
return 0; return 0;
...@@ -2498,51 +2496,15 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec, ...@@ -2498,51 +2496,15 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec,
break; break;
case SND_SOC_BIAS_STANDBY: 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 */ /* VMID 2*250k */
snd_soc_update_bits(codec, WM8962_PWR_MGMT_1, snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
WM8962_VMID_SEL_MASK, 0x100); WM8962_VMID_SEL_MASK, 0x100);
break; break;
case SND_SOC_BIAS_OFF: 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; break;
} }
codec->dapm.bias_level = level; codec->dapm.bias_level = level;
return 0; return 0;
} }
...@@ -2844,6 +2806,8 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source, ...@@ -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, snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
WM8962_FLL_ENA, 0); WM8962_FLL_ENA, 0);
pm_runtime_put(codec->dev);
return 0; return 0;
} }
...@@ -2892,6 +2856,7 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source, ...@@ -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); try_wait_for_completion(&wm8962->fll_lock);
pm_runtime_get_sync(codec->dev);
snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
WM8962_FLL_FRAC | WM8962_FLL_REFCLK_SRC_MASK | WM8962_FLL_FRAC | WM8962_FLL_REFCLK_SRC_MASK |
...@@ -3689,7 +3654,9 @@ static __devinit int wm8962_i2c_probe(struct i2c_client *i2c, ...@@ -3689,7 +3654,9 @@ static __devinit int wm8962_i2c_probe(struct i2c_client *i2c,
ret); 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, ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm8962, &wm8962_dai, 1); &soc_codec_dev_wm8962, &wm8962_dai, 1);
...@@ -3721,6 +3688,69 @@ static __devexit int wm8962_i2c_remove(struct i2c_client *client) ...@@ -3721,6 +3688,69 @@ static __devexit int wm8962_i2c_remove(struct i2c_client *client)
return 0; 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[] = { static const struct i2c_device_id wm8962_i2c_id[] = {
{ "wm8962", 0 }, { "wm8962", 0 },
{ } { }
...@@ -3731,6 +3761,7 @@ static struct i2c_driver wm8962_i2c_driver = { ...@@ -3731,6 +3761,7 @@ static struct i2c_driver wm8962_i2c_driver = {
.driver = { .driver = {
.name = "wm8962", .name = "wm8962",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = &wm8962_pm,
}, },
.probe = wm8962_i2c_probe, .probe = wm8962_i2c_probe,
.remove = __devexit_p(wm8962_i2c_remove), .remove = __devexit_p(wm8962_i2c_remove),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment