aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2012-01-26 12:28:49 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-01-26 13:39:24 -0500
commit62c1c40127e351de7fbc1d8c782f7508f8314aab (patch)
tree10f0a111dfc209c9c9473ccae90b557e91384fea /sound
parent17e3e57b65720628754e9afc6919e30776c0c822 (diff)
ASoC: wm5100: Use pm_runtime for powerdown managment
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>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/wm5100.c116
1 files changed, 56 insertions, 60 deletions
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index 39de946bf259..c6c382197fe2 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -18,6 +18,7 @@
18#include <linux/gcd.h> 18#include <linux/gcd.h>
19#include <linux/gpio.h> 19#include <linux/gpio.h>
20#include <linux/i2c.h> 20#include <linux/i2c.h>
21#include <linux/pm_runtime.h>
21#include <linux/regulator/consumer.h> 22#include <linux/regulator/consumer.h>
22#include <linux/regulator/fixed.h> 23#include <linux/regulator/fixed.h>
23#include <linux/slab.h> 24#include <linux/slab.h>
@@ -1261,54 +1262,6 @@ static const __devinitdata struct reg_default wm5100_reva_patches[] = {
1261 { WM5100_AUDIO_IF_3_19, 1 }, 1262 { WM5100_AUDIO_IF_3_19, 1 },
1262}; 1263};
1263 1264
1264static int wm5100_set_bias_level(struct snd_soc_codec *codec,
1265 enum snd_soc_bias_level level)
1266{
1267 struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
1268 int ret;
1269
1270 switch (level) {
1271 case SND_SOC_BIAS_ON:
1272 break;
1273
1274 case SND_SOC_BIAS_PREPARE:
1275 break;
1276
1277 case SND_SOC_BIAS_STANDBY:
1278 if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
1279 ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies),
1280 wm5100->core_supplies);
1281 if (ret != 0) {
1282 dev_err(codec->dev,
1283 "Failed to enable supplies: %d\n",
1284 ret);
1285 return ret;
1286 }
1287
1288 if (wm5100->pdata.ldo_ena) {
1289 gpio_set_value_cansleep(wm5100->pdata.ldo_ena,
1290 1);
1291 msleep(2);
1292 }
1293
1294 regcache_cache_only(wm5100->regmap, false);
1295 regcache_sync(wm5100->regmap);
1296 }
1297 break;
1298
1299 case SND_SOC_BIAS_OFF:
1300 regcache_cache_only(wm5100->regmap, true);
1301 if (wm5100->pdata.ldo_ena)
1302 gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
1303 regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
1304 wm5100->core_supplies);
1305 break;
1306 }
1307 codec->dapm.bias_level = level;
1308
1309 return 0;
1310}
1311
1312static int wm5100_dai_to_base(struct snd_soc_dai *dai) 1265static int wm5100_dai_to_base(struct snd_soc_dai *dai)
1313{ 1266{
1314 switch (dai->id) { 1267 switch (dai->id) {
@@ -1836,6 +1789,8 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
1836 1789
1837 if (!Fout) { 1790 if (!Fout) {
1838 dev_dbg(codec->dev, "FLL%d disabled", fll_id); 1791 dev_dbg(codec->dev, "FLL%d disabled", fll_id);
1792 if (fll->fout)
1793 pm_runtime_put(codec->dev);
1839 fll->fout = 0; 1794 fll->fout = 0;
1840 snd_soc_update_bits(codec, base + 1, WM5100_FLL1_ENA, 0); 1795 snd_soc_update_bits(codec, base + 1, WM5100_FLL1_ENA, 0);
1841 return 0; 1796 return 0;
@@ -1880,6 +1835,8 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
1880 /* Clear any pending completions */ 1835 /* Clear any pending completions */
1881 try_wait_for_completion(&fll->lock); 1836 try_wait_for_completion(&fll->lock);
1882 1837
1838 pm_runtime_get_sync(codec->dev);
1839
1883 snd_soc_update_bits(codec, base + 1, WM5100_FLL1_ENA, WM5100_FLL1_ENA); 1840 snd_soc_update_bits(codec, base + 1, WM5100_FLL1_ENA, WM5100_FLL1_ENA);
1884 1841
1885 if (i2c->irq) 1842 if (i2c->irq)
@@ -1914,6 +1871,7 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
1914 } 1871 }
1915 if (i == timeout) { 1872 if (i == timeout) {
1916 dev_err(codec->dev, "FLL%d lock timed out\n", fll_id); 1873 dev_err(codec->dev, "FLL%d lock timed out\n", fll_id);
1874 pm_runtime_put(codec->dev);
1917 return -ETIMEDOUT; 1875 return -ETIMEDOUT;
1918 } 1876 }
1919 1877
@@ -2377,9 +2335,6 @@ static int wm5100_probe(struct snd_soc_codec *codec)
2377 return ret; 2335 return ret;
2378 } 2336 }
2379 2337
2380 regcache_cache_only(wm5100->regmap, true);
2381
2382
2383 for (i = 0; i < ARRAY_SIZE(wm5100_dig_vu); i++) 2338 for (i = 0; i < ARRAY_SIZE(wm5100_dig_vu); i++)
2384 snd_soc_update_bits(codec, wm5100_dig_vu[i], WM5100_OUT_VU, 2339 snd_soc_update_bits(codec, wm5100_dig_vu[i], WM5100_OUT_VU,
2385 WM5100_OUT_VU); 2340 WM5100_OUT_VU);
@@ -2405,14 +2360,6 @@ static int wm5100_probe(struct snd_soc_codec *codec)
2405 } 2360 }
2406 } 2361 }
2407 2362
2408 /* We'll get woken up again when the system has something useful
2409 * for us to do.
2410 */
2411 if (wm5100->pdata.ldo_ena)
2412 gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
2413 regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
2414 wm5100->core_supplies);
2415
2416 return 0; 2363 return 0;
2417 2364
2418err_gpio: 2365err_gpio:
@@ -2444,7 +2391,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5100 = {
2444 2391
2445 .set_sysclk = wm5100_set_sysclk, 2392 .set_sysclk = wm5100_set_sysclk,
2446 .set_pll = wm5100_set_fll, 2393 .set_pll = wm5100_set_fll,
2447 .set_bias_level = wm5100_set_bias_level,
2448 .idle_bias_off = 1, 2394 .idle_bias_off = 1,
2449 .reg_cache_size = WM5100_MAX_REGISTER, 2395 .reg_cache_size = WM5100_MAX_REGISTER,
2450 .volatile_register = wm5100_soc_volatile, 2396 .volatile_register = wm5100_soc_volatile,
@@ -2661,6 +2607,10 @@ static __devinit int wm5100_i2c_probe(struct i2c_client *i2c,
2661 } 2607 }
2662 } 2608 }
2663 2609
2610 pm_runtime_set_active(&i2c->dev);
2611 pm_runtime_enable(&i2c->dev);
2612 pm_request_idle(&i2c->dev);
2613
2664 ret = snd_soc_register_codec(&i2c->dev, 2614 ret = snd_soc_register_codec(&i2c->dev,
2665 &soc_codec_dev_wm5100, wm5100_dai, 2615 &soc_codec_dev_wm5100, wm5100_dai,
2666 ARRAY_SIZE(wm5100_dai)); 2616 ARRAY_SIZE(wm5100_dai));
@@ -2714,6 +2664,51 @@ static __devexit int wm5100_i2c_remove(struct i2c_client *i2c)
2714 return 0; 2664 return 0;
2715} 2665}
2716 2666
2667#ifdef CONFIG_PM_RUNTIME
2668static int wm5100_runtime_suspend(struct device *dev)
2669{
2670 struct wm5100_priv *wm5100 = dev_get_drvdata(dev);
2671
2672 regcache_cache_only(wm5100->regmap, true);
2673 regcache_mark_dirty(wm5100->regmap);
2674 if (wm5100->pdata.ldo_ena)
2675 gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
2676 regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
2677 wm5100->core_supplies);
2678
2679 return 0;
2680}
2681
2682static int wm5100_runtime_resume(struct device *dev)
2683{
2684 struct wm5100_priv *wm5100 = dev_get_drvdata(dev);
2685 int ret;
2686
2687 ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies),
2688 wm5100->core_supplies);
2689 if (ret != 0) {
2690 dev_err(dev, "Failed to enable supplies: %d\n",
2691 ret);
2692 return ret;
2693 }
2694
2695 if (wm5100->pdata.ldo_ena) {
2696 gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 1);
2697 msleep(2);
2698 }
2699
2700 regcache_cache_only(wm5100->regmap, false);
2701 regcache_sync(wm5100->regmap);
2702
2703 return 0;
2704}
2705#endif
2706
2707static struct dev_pm_ops wm5100_pm = {
2708 SET_RUNTIME_PM_OPS(wm5100_runtime_suspend, wm5100_runtime_resume,
2709 NULL)
2710};
2711
2717static const struct i2c_device_id wm5100_i2c_id[] = { 2712static const struct i2c_device_id wm5100_i2c_id[] = {
2718 { "wm5100", 0 }, 2713 { "wm5100", 0 },
2719 { } 2714 { }
@@ -2724,6 +2719,7 @@ static struct i2c_driver wm5100_i2c_driver = {
2724 .driver = { 2719 .driver = {
2725 .name = "wm5100", 2720 .name = "wm5100",
2726 .owner = THIS_MODULE, 2721 .owner = THIS_MODULE,
2722 .pm = &wm5100_pm,
2727 }, 2723 },
2728 .probe = wm5100_i2c_probe, 2724 .probe = wm5100_i2c_probe,
2729 .remove = __devexit_p(wm5100_i2c_remove), 2725 .remove = __devexit_p(wm5100_i2c_remove),