diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-01-26 17:37:11 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-02-04 05:42:07 -0500 |
commit | c133421800d9d1dfec0c98de6c9da0a7a99e0573 (patch) | |
tree | 4ee82f1a6548ac7b2b2aae8008ec8008f49fbaed /sound | |
parent | cf56f62746c3e2f70bfad3d6fd051427a0022368 (diff) |
ASoC: Add support for BIAS_OFF when idle to WM8904
As well as disabling the biases of the CODEC the drop into BIAS_OFF will
also disable all the regulators powering the CODEC, allowing even greater
power savings on appropriately configured systems.
Since the regulator API does not currently provide notification when
regulators are disabled we assume that this always happens when we stop
using the regulators. Once 2.6.34 is merged this code can be optimised
to only sync the cache when power was actually removed.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/codecs/wm8904.c | 52 |
1 files changed, 39 insertions, 13 deletions
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 992a7f23df5c..dc782c43a7cb 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c | |||
@@ -2033,11 +2033,37 @@ static int wm8904_digital_mute(struct snd_soc_dai *codec_dai, int mute) | |||
2033 | return 0; | 2033 | return 0; |
2034 | } | 2034 | } |
2035 | 2035 | ||
2036 | static void wm8904_sync_cache(struct snd_soc_codec *codec) | ||
2037 | { | ||
2038 | struct wm8904_priv *wm8904 = codec->private_data; | ||
2039 | int i; | ||
2040 | |||
2041 | if (!codec->cache_sync) | ||
2042 | return; | ||
2043 | |||
2044 | codec->cache_only = 0; | ||
2045 | |||
2046 | /* Sync back cached values if they're different from the | ||
2047 | * hardware default. | ||
2048 | */ | ||
2049 | for (i = 1; i < ARRAY_SIZE(wm8904->reg_cache); i++) { | ||
2050 | if (!wm8904_access[i].writable) | ||
2051 | continue; | ||
2052 | |||
2053 | if (wm8904->reg_cache[i] == wm8904_reg[i]) | ||
2054 | continue; | ||
2055 | |||
2056 | snd_soc_write(codec, i, wm8904->reg_cache[i]); | ||
2057 | } | ||
2058 | |||
2059 | codec->cache_sync = 0; | ||
2060 | } | ||
2061 | |||
2036 | static int wm8904_set_bias_level(struct snd_soc_codec *codec, | 2062 | static int wm8904_set_bias_level(struct snd_soc_codec *codec, |
2037 | enum snd_soc_bias_level level) | 2063 | enum snd_soc_bias_level level) |
2038 | { | 2064 | { |
2039 | struct wm8904_priv *wm8904 = codec->private_data; | 2065 | struct wm8904_priv *wm8904 = codec->private_data; |
2040 | int ret, i; | 2066 | int ret; |
2041 | 2067 | ||
2042 | switch (level) { | 2068 | switch (level) { |
2043 | case SND_SOC_BIAS_ON: | 2069 | case SND_SOC_BIAS_ON: |
@@ -2065,18 +2091,7 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec, | |||
2065 | return ret; | 2091 | return ret; |
2066 | } | 2092 | } |
2067 | 2093 | ||
2068 | /* Sync back cached values if they're | 2094 | wm8904_sync_cache(codec); |
2069 | * different from the hardware default. | ||
2070 | */ | ||
2071 | for (i = 1; i < ARRAY_SIZE(wm8904->reg_cache); i++) { | ||
2072 | if (!wm8904_access[i].writable) | ||
2073 | continue; | ||
2074 | |||
2075 | if (wm8904->reg_cache[i] == wm8904_reg[i]) | ||
2076 | continue; | ||
2077 | |||
2078 | snd_soc_write(codec, i, wm8904->reg_cache[i]); | ||
2079 | } | ||
2080 | 2095 | ||
2081 | /* Enable bias */ | 2096 | /* Enable bias */ |
2082 | snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0, | 2097 | snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0, |
@@ -2112,6 +2127,15 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec, | |||
2112 | snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0, | 2127 | snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0, |
2113 | WM8904_BIAS_ENA, 0); | 2128 | WM8904_BIAS_ENA, 0); |
2114 | 2129 | ||
2130 | #ifdef CONFIG_REGULATOR | ||
2131 | /* Post 2.6.34 we will be able to get a callback when | ||
2132 | * the regulators are disabled which we can use but | ||
2133 | * for now just assume that the power will be cut if | ||
2134 | * the regulator API is in use. | ||
2135 | */ | ||
2136 | codec->cache_sync = 1; | ||
2137 | #endif | ||
2138 | |||
2115 | regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), | 2139 | regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), |
2116 | wm8904->supplies); | 2140 | wm8904->supplies); |
2117 | break; | 2141 | break; |
@@ -2365,6 +2389,8 @@ static int wm8904_register(struct wm8904_priv *wm8904, | |||
2365 | codec->reg_cache_size = WM8904_MAX_REGISTER; | 2389 | codec->reg_cache_size = WM8904_MAX_REGISTER; |
2366 | codec->reg_cache = &wm8904->reg_cache; | 2390 | codec->reg_cache = &wm8904->reg_cache; |
2367 | codec->volatile_register = wm8904_volatile_register; | 2391 | codec->volatile_register = wm8904_volatile_register; |
2392 | codec->cache_sync = 1; | ||
2393 | codec->idle_bias_off = 1; | ||
2368 | 2394 | ||
2369 | memcpy(codec->reg_cache, wm8904_reg, sizeof(wm8904_reg)); | 2395 | memcpy(codec->reg_cache, wm8904_reg, sizeof(wm8904_reg)); |
2370 | 2396 | ||