aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2010-01-26 17:37:11 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2010-02-04 05:42:07 -0500
commitc133421800d9d1dfec0c98de6c9da0a7a99e0573 (patch)
tree4ee82f1a6548ac7b2b2aae8008ec8008f49fbaed /sound
parentcf56f62746c3e2f70bfad3d6fd051427a0022368 (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.c52
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
2036static 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
2036static int wm8904_set_bias_level(struct snd_soc_codec *codec, 2062static 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