Commit 22f8d055350066b4a87de4adea8c5213cac54534

Authored by Mark Brown
1 parent 6f8270cc9a

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];