Commit 22f8d055350066b4a87de4adea8c5213cac54534
1 parent
6f8270cc9a
Exists in
master
and in
20 other branches
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>
Showing 2 changed files with 155 additions and 39 deletions Side-by-side Diff
sound/soc/codecs/wm8994.c
... | ... | @@ -777,36 +777,68 @@ |
777 | 777 | |
778 | 778 | if (wm8994->vmid_refcount == 1) { |
779 | 779 | snd_soc_update_bits(codec, WM8994_ANTIPOP_1, |
780 | - WM8994_LINEOUT_VMID_BUF_ENA | | |
781 | 780 | WM8994_LINEOUT1_DISCH | |
782 | - WM8994_LINEOUT2_DISCH, | |
783 | - WM8994_LINEOUT_VMID_BUF_ENA); | |
781 | + WM8994_LINEOUT2_DISCH, 0); | |
784 | 782 | |
785 | 783 | wm_hubs_vmid_ena(codec); |
786 | 784 | |
787 | - /* Startup bias, VMID ramp & buffer */ | |
788 | - snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | |
789 | - WM8994_BIAS_SRC | | |
790 | - WM8994_VMID_DISCH | | |
791 | - WM8994_STARTUP_BIAS_ENA | | |
792 | - WM8994_VMID_BUF_ENA | | |
793 | - WM8994_VMID_RAMP_MASK, | |
794 | - WM8994_BIAS_SRC | | |
795 | - WM8994_STARTUP_BIAS_ENA | | |
796 | - WM8994_VMID_BUF_ENA | | |
797 | - (0x2 << WM8994_VMID_RAMP_SHIFT)); | |
785 | + switch (wm8994->vmid_mode) { | |
786 | + default: | |
787 | + WARN_ON(0 == "Invalid VMID mode"); | |
788 | + case WM8994_VMID_NORMAL: | |
789 | + /* Startup bias, VMID ramp & buffer */ | |
790 | + snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | |
791 | + WM8994_BIAS_SRC | | |
792 | + WM8994_VMID_DISCH | | |
793 | + WM8994_STARTUP_BIAS_ENA | | |
794 | + WM8994_VMID_BUF_ENA | | |
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)); | |
798 | 800 | |
799 | - /* Main bias enable, VMID=2x40k */ | |
800 | - snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, | |
801 | - WM8994_BIAS_ENA | | |
802 | - WM8994_VMID_SEL_MASK, | |
803 | - WM8994_BIAS_ENA | 0x2); | |
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); | |
804 | 806 | |
805 | - msleep(50); | |
807 | + msleep(50); | |
806 | 808 | |
807 | - snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | |
808 | - WM8994_VMID_RAMP_MASK | WM8994_BIAS_SRC, | |
809 | - 0); | |
809 | + snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | |
810 | + WM8994_VMID_RAMP_MASK | | |
811 | + WM8994_BIAS_SRC, | |
812 | + 0); | |
813 | + break; | |
814 | + | |
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); | |
835 | + | |
836 | + snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | |
837 | + WM8994_VMID_RAMP_MASK | | |
838 | + WM8994_BIAS_SRC, | |
839 | + 0); | |
840 | + break; | |
841 | + } | |
810 | 842 | } |
811 | 843 | } |
812 | 844 | |
813 | 845 | |
814 | 846 | |
815 | 847 | |
816 | 848 | |
817 | 849 | |
818 | 850 | |
819 | 851 | |
820 | 852 | |
... | ... | @@ -820,41 +852,68 @@ |
820 | 852 | wm8994->vmid_refcount); |
821 | 853 | |
822 | 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 | 870 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, |
825 | 871 | WM8994_BIAS_SRC | |
826 | - WM8994_STARTUP_BIAS_ENA | | |
827 | - WM8994_VMID_BUF_ENA | | |
828 | - WM8994_VMID_RAMP_MASK, | |
872 | + WM8994_VMID_DISCH, | |
829 | 873 | WM8994_BIAS_SRC | |
830 | - WM8994_STARTUP_BIAS_ENA | | |
831 | - WM8994_VMID_BUF_ENA | | |
832 | - (1 << WM8994_VMID_RAMP_SHIFT)); | |
874 | + WM8994_VMID_DISCH); | |
833 | 875 | |
834 | - /* Disable main biases */ | |
835 | - snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, | |
836 | - WM8994_BIAS_ENA | | |
837 | - WM8994_VMID_SEL_MASK, 0); | |
876 | + switch (wm8994->vmid_mode) { | |
877 | + case WM8994_VMID_FORCE: | |
878 | + msleep(350); | |
879 | + break; | |
880 | + default: | |
881 | + break; | |
882 | + } | |
838 | 883 | |
839 | - /* Discharge VMID */ | |
840 | - snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | |
841 | - WM8994_VMID_DISCH, WM8994_VMID_DISCH); | |
884 | + snd_soc_update_bits(codec, WM8994_ADDITIONAL_CONTROL, | |
885 | + WM8994_VROI, WM8994_VROI); | |
842 | 886 | |
843 | - /* Discharge line */ | |
887 | + /* Active discharge */ | |
844 | 888 | snd_soc_update_bits(codec, WM8994_ANTIPOP_1, |
845 | 889 | WM8994_LINEOUT1_DISCH | |
846 | 890 | WM8994_LINEOUT2_DISCH, |
847 | 891 | WM8994_LINEOUT1_DISCH | |
848 | 892 | WM8994_LINEOUT2_DISCH); |
849 | 893 | |
850 | - msleep(5); | |
894 | + msleep(150); | |
851 | 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); | |
904 | + | |
852 | 905 | /* Switch off startup biases */ |
853 | 906 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, |
854 | 907 | WM8994_BIAS_SRC | |
855 | 908 | WM8994_STARTUP_BIAS_ENA | |
856 | 909 | WM8994_VMID_BUF_ENA | |
857 | 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 | 919 | pm_runtime_put(codec->dev); |
... | ... | @@ -2193,6 +2252,55 @@ |
2193 | 2252 | } |
2194 | 2253 | |
2195 | 2254 | codec->dapm.bias_level = level; |
2255 | + | |
2256 | + return 0; | |
2257 | +} | |
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 | + } | |
2196 | 2304 | |
2197 | 2305 | return 0; |
2198 | 2306 | } |
sound/soc/codecs/wm8994.h
... | ... | @@ -32,6 +32,11 @@ |
32 | 32 | #define WM8994_FLL_SRC_LRCLK 3 |
33 | 33 | #define WM8994_FLL_SRC_BCLK 4 |
34 | 34 | |
35 | +enum wm8994_vmid_mode { | |
36 | + WM8994_VMID_NORMAL, | |
37 | + WM8994_VMID_FORCE, | |
38 | +}; | |
39 | + | |
35 | 40 | typedef void (*wm8958_micdet_cb)(u16 status, void *data); |
36 | 41 | |
37 | 42 | int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, |
... | ... | @@ -39,6 +44,8 @@ |
39 | 44 | int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, |
40 | 45 | wm8958_micdet_cb cb, void *cb_data); |
41 | 46 | |
47 | +int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode); | |
48 | + | |
42 | 49 | int wm8958_aif_ev(struct snd_soc_dapm_widget *w, |
43 | 50 | struct snd_kcontrol *kcontrol, int event); |
44 | 51 | |
... | ... | @@ -75,6 +82,7 @@ |
75 | 82 | |
76 | 83 | int vmid_refcount; |
77 | 84 | int active_refcount; |
85 | + enum wm8994_vmid_mode vmid_mode; | |
78 | 86 | |
79 | 87 | int dac_rates[2]; |
80 | 88 | int lrclk_shared[2]; |