diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-03-19 13:32:06 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-03-19 15:08:17 -0400 |
commit | 22f8d055350066b4a87de4adea8c5213cac54534 (patch) | |
tree | 229a761bb0e5c4a9ee27db3d327bbd11905b9c96 /sound/soc/codecs/wm8994.c | |
parent | 6f8270cc9a43d767676c97df5773fdcede312a88 (diff) |
ASoC: wm8994: Provide VMID mode control and fix default sequence
The optimal management of VMID depends on a number of factors which vary
dynamically at runtime, for example the connection to a system docking
station. In some circumstances it is desirable to keep VMID enabled all
the time, in others it is desirable to aggressively power it up and down.
Provide a callback allowing machine driver to configure either the normal
power up/down mode (WM8994_VMID_MODE_NORMAL) or to maintain VMID even
when idle (WM8994_VMID_MODE_FORCE). This callback, wm8994_vmid_mode(),
should be called with the CODEC lock.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/wm8994.c')
-rw-r--r-- | sound/soc/codecs/wm8994.c | 186 |
1 files changed, 147 insertions, 39 deletions
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index b7f3cfc74e98..9685dff44dd8 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c | |||
@@ -777,36 +777,68 @@ static void vmid_reference(struct snd_soc_codec *codec) | |||
777 | 777 | ||
778 | if (wm8994->vmid_refcount == 1) { | 778 | if (wm8994->vmid_refcount == 1) { |
779 | snd_soc_update_bits(codec, WM8994_ANTIPOP_1, | 779 | snd_soc_update_bits(codec, WM8994_ANTIPOP_1, |
780 | WM8994_LINEOUT_VMID_BUF_ENA | | ||
781 | WM8994_LINEOUT1_DISCH | | 780 | WM8994_LINEOUT1_DISCH | |
782 | WM8994_LINEOUT2_DISCH, | 781 | WM8994_LINEOUT2_DISCH, 0); |
783 | WM8994_LINEOUT_VMID_BUF_ENA); | ||
784 | 782 | ||
785 | wm_hubs_vmid_ena(codec); | 783 | wm_hubs_vmid_ena(codec); |
786 | 784 | ||
787 | /* Startup bias, VMID ramp & buffer */ | 785 | switch (wm8994->vmid_mode) { |
788 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | 786 | default: |
789 | WM8994_BIAS_SRC | | 787 | WARN_ON(0 == "Invalid VMID mode"); |
790 | WM8994_VMID_DISCH | | 788 | case WM8994_VMID_NORMAL: |
791 | WM8994_STARTUP_BIAS_ENA | | 789 | /* Startup bias, VMID ramp & buffer */ |
792 | WM8994_VMID_BUF_ENA | | 790 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, |
793 | WM8994_VMID_RAMP_MASK, | 791 | WM8994_BIAS_SRC | |
794 | WM8994_BIAS_SRC | | 792 | WM8994_VMID_DISCH | |
795 | WM8994_STARTUP_BIAS_ENA | | 793 | WM8994_STARTUP_BIAS_ENA | |
796 | WM8994_VMID_BUF_ENA | | 794 | WM8994_VMID_BUF_ENA | |
797 | (0x2 << WM8994_VMID_RAMP_SHIFT)); | 795 | WM8994_VMID_RAMP_MASK, |
796 | WM8994_BIAS_SRC | | ||
797 | WM8994_STARTUP_BIAS_ENA | | ||
798 | WM8994_VMID_BUF_ENA | | ||
799 | (0x3 << WM8994_VMID_RAMP_SHIFT)); | ||
800 | |||
801 | /* Main bias enable, VMID=2x40k */ | ||
802 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, | ||
803 | WM8994_BIAS_ENA | | ||
804 | WM8994_VMID_SEL_MASK, | ||
805 | WM8994_BIAS_ENA | 0x2); | ||
806 | |||
807 | msleep(50); | ||
798 | 808 | ||
799 | /* Main bias enable, VMID=2x40k */ | 809 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, |
800 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, | 810 | WM8994_VMID_RAMP_MASK | |
801 | WM8994_BIAS_ENA | | 811 | WM8994_BIAS_SRC, |
802 | WM8994_VMID_SEL_MASK, | 812 | 0); |
803 | WM8994_BIAS_ENA | 0x2); | 813 | break; |
804 | 814 | ||
805 | msleep(50); | 815 | case WM8994_VMID_FORCE: |
816 | /* Startup bias, slow VMID ramp & buffer */ | ||
817 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | ||
818 | WM8994_BIAS_SRC | | ||
819 | WM8994_VMID_DISCH | | ||
820 | WM8994_STARTUP_BIAS_ENA | | ||
821 | WM8994_VMID_BUF_ENA | | ||
822 | WM8994_VMID_RAMP_MASK, | ||
823 | WM8994_BIAS_SRC | | ||
824 | WM8994_STARTUP_BIAS_ENA | | ||
825 | WM8994_VMID_BUF_ENA | | ||
826 | (0x2 << WM8994_VMID_RAMP_SHIFT)); | ||
827 | |||
828 | /* Main bias enable, VMID=2x40k */ | ||
829 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, | ||
830 | WM8994_BIAS_ENA | | ||
831 | WM8994_VMID_SEL_MASK, | ||
832 | WM8994_BIAS_ENA | 0x2); | ||
833 | |||
834 | msleep(400); | ||
806 | 835 | ||
807 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | 836 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, |
808 | WM8994_VMID_RAMP_MASK | WM8994_BIAS_SRC, | 837 | WM8994_VMID_RAMP_MASK | |
809 | 0); | 838 | WM8994_BIAS_SRC, |
839 | 0); | ||
840 | break; | ||
841 | } | ||
810 | } | 842 | } |
811 | } | 843 | } |
812 | 844 | ||
@@ -820,34 +852,55 @@ static void vmid_dereference(struct snd_soc_codec *codec) | |||
820 | wm8994->vmid_refcount); | 852 | wm8994->vmid_refcount); |
821 | 853 | ||
822 | if (wm8994->vmid_refcount == 0) { | 854 | if (wm8994->vmid_refcount == 0) { |
823 | /* Switch over to startup biases */ | 855 | if (wm8994->hubs.lineout1_se) |
856 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_3, | ||
857 | WM8994_LINEOUT1N_ENA | | ||
858 | WM8994_LINEOUT1P_ENA, | ||
859 | WM8994_LINEOUT1N_ENA | | ||
860 | WM8994_LINEOUT1P_ENA); | ||
861 | |||
862 | if (wm8994->hubs.lineout2_se) | ||
863 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_3, | ||
864 | WM8994_LINEOUT2N_ENA | | ||
865 | WM8994_LINEOUT2P_ENA, | ||
866 | WM8994_LINEOUT2N_ENA | | ||
867 | WM8994_LINEOUT2P_ENA); | ||
868 | |||
869 | /* Start discharging VMID */ | ||
824 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | 870 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, |
825 | WM8994_BIAS_SRC | | 871 | WM8994_BIAS_SRC | |
826 | WM8994_STARTUP_BIAS_ENA | | 872 | WM8994_VMID_DISCH, |
827 | WM8994_VMID_BUF_ENA | | ||
828 | WM8994_VMID_RAMP_MASK, | ||
829 | WM8994_BIAS_SRC | | 873 | WM8994_BIAS_SRC | |
830 | WM8994_STARTUP_BIAS_ENA | | 874 | WM8994_VMID_DISCH); |
831 | WM8994_VMID_BUF_ENA | | ||
832 | (1 << WM8994_VMID_RAMP_SHIFT)); | ||
833 | 875 | ||
834 | /* Disable main biases */ | 876 | switch (wm8994->vmid_mode) { |
835 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, | 877 | case WM8994_VMID_FORCE: |
836 | WM8994_BIAS_ENA | | 878 | msleep(350); |
837 | WM8994_VMID_SEL_MASK, 0); | 879 | break; |
880 | default: | ||
881 | break; | ||
882 | } | ||
838 | 883 | ||
839 | /* Discharge VMID */ | 884 | snd_soc_update_bits(codec, WM8994_ADDITIONAL_CONTROL, |
840 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | 885 | WM8994_VROI, WM8994_VROI); |
841 | WM8994_VMID_DISCH, WM8994_VMID_DISCH); | ||
842 | 886 | ||
843 | /* Discharge line */ | 887 | /* Active discharge */ |
844 | snd_soc_update_bits(codec, WM8994_ANTIPOP_1, | 888 | snd_soc_update_bits(codec, WM8994_ANTIPOP_1, |
845 | WM8994_LINEOUT1_DISCH | | 889 | WM8994_LINEOUT1_DISCH | |
846 | WM8994_LINEOUT2_DISCH, | 890 | WM8994_LINEOUT2_DISCH, |
847 | WM8994_LINEOUT1_DISCH | | 891 | WM8994_LINEOUT1_DISCH | |
848 | WM8994_LINEOUT2_DISCH); | 892 | WM8994_LINEOUT2_DISCH); |
849 | 893 | ||
850 | msleep(5); | 894 | msleep(150); |
895 | |||
896 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_3, | ||
897 | WM8994_LINEOUT1N_ENA | | ||
898 | WM8994_LINEOUT1P_ENA | | ||
899 | WM8994_LINEOUT2N_ENA | | ||
900 | WM8994_LINEOUT2P_ENA, 0); | ||
901 | |||
902 | snd_soc_update_bits(codec, WM8994_ADDITIONAL_CONTROL, | ||
903 | WM8994_VROI, 0); | ||
851 | 904 | ||
852 | /* Switch off startup biases */ | 905 | /* Switch off startup biases */ |
853 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | 906 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, |
@@ -855,6 +908,12 @@ static void vmid_dereference(struct snd_soc_codec *codec) | |||
855 | WM8994_STARTUP_BIAS_ENA | | 908 | WM8994_STARTUP_BIAS_ENA | |
856 | WM8994_VMID_BUF_ENA | | 909 | WM8994_VMID_BUF_ENA | |
857 | WM8994_VMID_RAMP_MASK, 0); | 910 | WM8994_VMID_RAMP_MASK, 0); |
911 | |||
912 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, | ||
913 | WM8994_BIAS_ENA | WM8994_VMID_SEL_MASK, 0); | ||
914 | |||
915 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | ||
916 | WM8994_VMID_RAMP_MASK, 0); | ||
858 | } | 917 | } |
859 | 918 | ||
860 | pm_runtime_put(codec->dev); | 919 | pm_runtime_put(codec->dev); |
@@ -2197,6 +2256,55 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec, | |||
2197 | return 0; | 2256 | return 0; |
2198 | } | 2257 | } |
2199 | 2258 | ||
2259 | int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode) | ||
2260 | { | ||
2261 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | ||
2262 | |||
2263 | switch (mode) { | ||
2264 | case WM8994_VMID_NORMAL: | ||
2265 | if (wm8994->hubs.lineout1_se) { | ||
2266 | snd_soc_dapm_disable_pin(&codec->dapm, | ||
2267 | "LINEOUT1N Driver"); | ||
2268 | snd_soc_dapm_disable_pin(&codec->dapm, | ||
2269 | "LINEOUT1P Driver"); | ||
2270 | } | ||
2271 | if (wm8994->hubs.lineout2_se) { | ||
2272 | snd_soc_dapm_disable_pin(&codec->dapm, | ||
2273 | "LINEOUT2N Driver"); | ||
2274 | snd_soc_dapm_disable_pin(&codec->dapm, | ||
2275 | "LINEOUT2P Driver"); | ||
2276 | } | ||
2277 | |||
2278 | /* Do the sync with the old mode to allow it to clean up */ | ||
2279 | snd_soc_dapm_sync(&codec->dapm); | ||
2280 | wm8994->vmid_mode = mode; | ||
2281 | break; | ||
2282 | |||
2283 | case WM8994_VMID_FORCE: | ||
2284 | if (wm8994->hubs.lineout1_se) { | ||
2285 | snd_soc_dapm_force_enable_pin(&codec->dapm, | ||
2286 | "LINEOUT1N Driver"); | ||
2287 | snd_soc_dapm_force_enable_pin(&codec->dapm, | ||
2288 | "LINEOUT1P Driver"); | ||
2289 | } | ||
2290 | if (wm8994->hubs.lineout2_se) { | ||
2291 | snd_soc_dapm_force_enable_pin(&codec->dapm, | ||
2292 | "LINEOUT2N Driver"); | ||
2293 | snd_soc_dapm_force_enable_pin(&codec->dapm, | ||
2294 | "LINEOUT2P Driver"); | ||
2295 | } | ||
2296 | |||
2297 | wm8994->vmid_mode = mode; | ||
2298 | snd_soc_dapm_sync(&codec->dapm); | ||
2299 | break; | ||
2300 | |||
2301 | default: | ||
2302 | return -EINVAL; | ||
2303 | } | ||
2304 | |||
2305 | return 0; | ||
2306 | } | ||
2307 | |||
2200 | static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | 2308 | static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
2201 | { | 2309 | { |
2202 | struct snd_soc_codec *codec = dai->codec; | 2310 | struct snd_soc_codec *codec = dai->codec; |