From 62c1c40127e351de7fbc1d8c782f7508f8314aab Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 26 Jan 2012 17:28:49 +0000 Subject: [PATCH] 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 --- sound/soc/codecs/wm5100.c | 116 ++++++++++++++++++++++------------------------ 1 file changed, 56 insertions(+), 60 deletions(-) diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 39de946..c6c3821 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -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), -- 2.7.4