diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-02-03 12:55:55 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-02-04 05:41:54 -0500 |
commit | cf56f62746c3e2f70bfad3d6fd051427a0022368 (patch) | |
tree | 5bd6c2fb2d7112d180892caec28e1835253e5334 /sound/soc | |
parent | b37e399bfc7fcb5b523e3e2e74686c8cc95c0cba (diff) |
ASoC: Disable WM8993 regulators when turning bias off
While the regulators are disabled we cache all register writes.
Currently we assume that the regulator disable actually takes
effect, after the merge with the regulator tree in 2.6.34 the
regulator API will be able to notify us if the power is actually
removed (due to constraints or regulator sharing it may not be).
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/codecs/wm8993.c | 54 |
1 files changed, 45 insertions, 9 deletions
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index e97b3f45b24b..bf022f68b84f 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c | |||
@@ -923,10 +923,33 @@ static const struct snd_soc_dapm_route routes[] = { | |||
923 | { "Right Headphone Mux", "DAC", "DACR" }, | 923 | { "Right Headphone Mux", "DAC", "DACR" }, |
924 | }; | 924 | }; |
925 | 925 | ||
926 | static void wm8993_cache_restore(struct snd_soc_codec *codec) | ||
927 | { | ||
928 | u16 *cache = codec->reg_cache; | ||
929 | int i; | ||
930 | |||
931 | if (!codec->cache_sync) | ||
932 | return; | ||
933 | |||
934 | /* Reenable hardware writes */ | ||
935 | codec->cache_only = 0; | ||
936 | |||
937 | /* Restore the register settings */ | ||
938 | for (i = 1; i < WM8993_MAX_REGISTER; i++) { | ||
939 | if (cache[i] == wm8993_reg_defaults[i]) | ||
940 | continue; | ||
941 | snd_soc_write(codec, i, cache[i]); | ||
942 | } | ||
943 | |||
944 | /* We're in sync again */ | ||
945 | codec->cache_sync = 0; | ||
946 | } | ||
947 | |||
926 | static int wm8993_set_bias_level(struct snd_soc_codec *codec, | 948 | static int wm8993_set_bias_level(struct snd_soc_codec *codec, |
927 | enum snd_soc_bias_level level) | 949 | enum snd_soc_bias_level level) |
928 | { | 950 | { |
929 | struct wm8993_priv *wm8993 = codec->private_data; | 951 | struct wm8993_priv *wm8993 = codec->private_data; |
952 | int ret; | ||
930 | 953 | ||
931 | switch (level) { | 954 | switch (level) { |
932 | case SND_SOC_BIAS_ON: | 955 | case SND_SOC_BIAS_ON: |
@@ -940,6 +963,13 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec, | |||
940 | 963 | ||
941 | case SND_SOC_BIAS_STANDBY: | 964 | case SND_SOC_BIAS_STANDBY: |
942 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | 965 | if (codec->bias_level == SND_SOC_BIAS_OFF) { |
966 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies), | ||
967 | wm8993->supplies); | ||
968 | if (ret != 0) | ||
969 | return ret; | ||
970 | |||
971 | wm8993_cache_restore(codec); | ||
972 | |||
943 | /* Tune DC servo configuration */ | 973 | /* Tune DC servo configuration */ |
944 | snd_soc_write(codec, 0x44, 3); | 974 | snd_soc_write(codec, 0x44, 3); |
945 | snd_soc_write(codec, 0x56, 3); | 975 | snd_soc_write(codec, 0x56, 3); |
@@ -992,6 +1022,18 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec, | |||
992 | snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, | 1022 | snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, |
993 | WM8993_VMID_SEL_MASK | WM8993_BIAS_ENA, | 1023 | WM8993_VMID_SEL_MASK | WM8993_BIAS_ENA, |
994 | 0); | 1024 | 0); |
1025 | |||
1026 | #ifdef CONFIG_REGULATOR | ||
1027 | /* Post 2.6.34 we will be able to get a callback when | ||
1028 | * the regulators are disabled which we can use but | ||
1029 | * for now just assume that the power will be cut if | ||
1030 | * the regulator API is in use. | ||
1031 | */ | ||
1032 | codec->cache_sync = 1; | ||
1033 | #endif | ||
1034 | |||
1035 | regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), | ||
1036 | wm8993->supplies); | ||
995 | break; | 1037 | break; |
996 | } | 1038 | } |
997 | 1039 | ||
@@ -1460,15 +1502,7 @@ static int wm8993_resume(struct platform_device *pdev) | |||
1460 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1502 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1461 | struct snd_soc_codec *codec = socdev->card->codec; | 1503 | struct snd_soc_codec *codec = socdev->card->codec; |
1462 | struct wm8993_priv *wm8993 = codec->private_data; | 1504 | struct wm8993_priv *wm8993 = codec->private_data; |
1463 | u16 *cache = wm8993->reg_cache; | 1505 | int ret; |
1464 | int i, ret; | ||
1465 | |||
1466 | /* Restore the register settings */ | ||
1467 | for (i = 1; i < WM8993_MAX_REGISTER; i++) { | ||
1468 | if (cache[i] == wm8993_reg_defaults[i]) | ||
1469 | continue; | ||
1470 | snd_soc_write(codec, i, cache[i]); | ||
1471 | } | ||
1472 | 1506 | ||
1473 | wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1507 | wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1474 | 1508 | ||
@@ -1584,6 +1618,8 @@ static int wm8993_i2c_probe(struct i2c_client *i2c, | |||
1584 | if (ret != 0) | 1618 | if (ret != 0) |
1585 | goto err_enable; | 1619 | goto err_enable; |
1586 | 1620 | ||
1621 | codec->cache_only = 1; | ||
1622 | |||
1587 | /* By default we're using the output mixers */ | 1623 | /* By default we're using the output mixers */ |
1588 | wm8993->class_w_users = 2; | 1624 | wm8993->class_w_users = 2; |
1589 | 1625 | ||