forked from Minki/linux
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>
This commit is contained in:
parent
6f8270cc9a
commit
22f8d05535
@ -777,36 +777,68 @@ static void vmid_reference(struct snd_soc_codec *codec)
|
||||
|
||||
if (wm8994->vmid_refcount == 1) {
|
||||
snd_soc_update_bits(codec, WM8994_ANTIPOP_1,
|
||||
WM8994_LINEOUT_VMID_BUF_ENA |
|
||||
WM8994_LINEOUT1_DISCH |
|
||||
WM8994_LINEOUT2_DISCH,
|
||||
WM8994_LINEOUT_VMID_BUF_ENA);
|
||||
WM8994_LINEOUT2_DISCH, 0);
|
||||
|
||||
wm_hubs_vmid_ena(codec);
|
||||
|
||||
/* Startup bias, VMID ramp & buffer */
|
||||
snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
|
||||
WM8994_BIAS_SRC |
|
||||
WM8994_VMID_DISCH |
|
||||
WM8994_STARTUP_BIAS_ENA |
|
||||
WM8994_VMID_BUF_ENA |
|
||||
WM8994_VMID_RAMP_MASK,
|
||||
WM8994_BIAS_SRC |
|
||||
WM8994_STARTUP_BIAS_ENA |
|
||||
WM8994_VMID_BUF_ENA |
|
||||
(0x2 << WM8994_VMID_RAMP_SHIFT));
|
||||
switch (wm8994->vmid_mode) {
|
||||
default:
|
||||
WARN_ON(0 == "Invalid VMID mode");
|
||||
case WM8994_VMID_NORMAL:
|
||||
/* Startup bias, VMID ramp & buffer */
|
||||
snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
|
||||
WM8994_BIAS_SRC |
|
||||
WM8994_VMID_DISCH |
|
||||
WM8994_STARTUP_BIAS_ENA |
|
||||
WM8994_VMID_BUF_ENA |
|
||||
WM8994_VMID_RAMP_MASK,
|
||||
WM8994_BIAS_SRC |
|
||||
WM8994_STARTUP_BIAS_ENA |
|
||||
WM8994_VMID_BUF_ENA |
|
||||
(0x3 << WM8994_VMID_RAMP_SHIFT));
|
||||
|
||||
/* Main bias enable, VMID=2x40k */
|
||||
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
|
||||
WM8994_BIAS_ENA |
|
||||
WM8994_VMID_SEL_MASK,
|
||||
WM8994_BIAS_ENA | 0x2);
|
||||
/* Main bias enable, VMID=2x40k */
|
||||
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
|
||||
WM8994_BIAS_ENA |
|
||||
WM8994_VMID_SEL_MASK,
|
||||
WM8994_BIAS_ENA | 0x2);
|
||||
|
||||
msleep(50);
|
||||
msleep(50);
|
||||
|
||||
snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
|
||||
WM8994_VMID_RAMP_MASK | WM8994_BIAS_SRC,
|
||||
0);
|
||||
snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
|
||||
WM8994_VMID_RAMP_MASK |
|
||||
WM8994_BIAS_SRC,
|
||||
0);
|
||||
break;
|
||||
|
||||
case WM8994_VMID_FORCE:
|
||||
/* Startup bias, slow VMID ramp & buffer */
|
||||
snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
|
||||
WM8994_BIAS_SRC |
|
||||
WM8994_VMID_DISCH |
|
||||
WM8994_STARTUP_BIAS_ENA |
|
||||
WM8994_VMID_BUF_ENA |
|
||||
WM8994_VMID_RAMP_MASK,
|
||||
WM8994_BIAS_SRC |
|
||||
WM8994_STARTUP_BIAS_ENA |
|
||||
WM8994_VMID_BUF_ENA |
|
||||
(0x2 << WM8994_VMID_RAMP_SHIFT));
|
||||
|
||||
/* Main bias enable, VMID=2x40k */
|
||||
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
|
||||
WM8994_BIAS_ENA |
|
||||
WM8994_VMID_SEL_MASK,
|
||||
WM8994_BIAS_ENA | 0x2);
|
||||
|
||||
msleep(400);
|
||||
|
||||
snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
|
||||
WM8994_VMID_RAMP_MASK |
|
||||
WM8994_BIAS_SRC,
|
||||
0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -820,34 +852,55 @@ static void vmid_dereference(struct snd_soc_codec *codec)
|
||||
wm8994->vmid_refcount);
|
||||
|
||||
if (wm8994->vmid_refcount == 0) {
|
||||
/* Switch over to startup biases */
|
||||
if (wm8994->hubs.lineout1_se)
|
||||
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_3,
|
||||
WM8994_LINEOUT1N_ENA |
|
||||
WM8994_LINEOUT1P_ENA,
|
||||
WM8994_LINEOUT1N_ENA |
|
||||
WM8994_LINEOUT1P_ENA);
|
||||
|
||||
if (wm8994->hubs.lineout2_se)
|
||||
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_3,
|
||||
WM8994_LINEOUT2N_ENA |
|
||||
WM8994_LINEOUT2P_ENA,
|
||||
WM8994_LINEOUT2N_ENA |
|
||||
WM8994_LINEOUT2P_ENA);
|
||||
|
||||
/* Start discharging VMID */
|
||||
snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
|
||||
WM8994_BIAS_SRC |
|
||||
WM8994_STARTUP_BIAS_ENA |
|
||||
WM8994_VMID_BUF_ENA |
|
||||
WM8994_VMID_RAMP_MASK,
|
||||
WM8994_VMID_DISCH,
|
||||
WM8994_BIAS_SRC |
|
||||
WM8994_STARTUP_BIAS_ENA |
|
||||
WM8994_VMID_BUF_ENA |
|
||||
(1 << WM8994_VMID_RAMP_SHIFT));
|
||||
WM8994_VMID_DISCH);
|
||||
|
||||
/* Disable main biases */
|
||||
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
|
||||
WM8994_BIAS_ENA |
|
||||
WM8994_VMID_SEL_MASK, 0);
|
||||
switch (wm8994->vmid_mode) {
|
||||
case WM8994_VMID_FORCE:
|
||||
msleep(350);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Discharge VMID */
|
||||
snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
|
||||
WM8994_VMID_DISCH, WM8994_VMID_DISCH);
|
||||
snd_soc_update_bits(codec, WM8994_ADDITIONAL_CONTROL,
|
||||
WM8994_VROI, WM8994_VROI);
|
||||
|
||||
/* Discharge line */
|
||||
/* Active discharge */
|
||||
snd_soc_update_bits(codec, WM8994_ANTIPOP_1,
|
||||
WM8994_LINEOUT1_DISCH |
|
||||
WM8994_LINEOUT2_DISCH,
|
||||
WM8994_LINEOUT1_DISCH |
|
||||
WM8994_LINEOUT2_DISCH);
|
||||
|
||||
msleep(5);
|
||||
msleep(150);
|
||||
|
||||
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_3,
|
||||
WM8994_LINEOUT1N_ENA |
|
||||
WM8994_LINEOUT1P_ENA |
|
||||
WM8994_LINEOUT2N_ENA |
|
||||
WM8994_LINEOUT2P_ENA, 0);
|
||||
|
||||
snd_soc_update_bits(codec, WM8994_ADDITIONAL_CONTROL,
|
||||
WM8994_VROI, 0);
|
||||
|
||||
/* Switch off startup biases */
|
||||
snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
|
||||
@ -855,6 +908,12 @@ static void vmid_dereference(struct snd_soc_codec *codec)
|
||||
WM8994_STARTUP_BIAS_ENA |
|
||||
WM8994_VMID_BUF_ENA |
|
||||
WM8994_VMID_RAMP_MASK, 0);
|
||||
|
||||
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
|
||||
WM8994_BIAS_ENA | WM8994_VMID_SEL_MASK, 0);
|
||||
|
||||
snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
|
||||
WM8994_VMID_RAMP_MASK, 0);
|
||||
}
|
||||
|
||||
pm_runtime_put(codec->dev);
|
||||
@ -2197,6 +2256,55 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode)
|
||||
{
|
||||
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (mode) {
|
||||
case WM8994_VMID_NORMAL:
|
||||
if (wm8994->hubs.lineout1_se) {
|
||||
snd_soc_dapm_disable_pin(&codec->dapm,
|
||||
"LINEOUT1N Driver");
|
||||
snd_soc_dapm_disable_pin(&codec->dapm,
|
||||
"LINEOUT1P Driver");
|
||||
}
|
||||
if (wm8994->hubs.lineout2_se) {
|
||||
snd_soc_dapm_disable_pin(&codec->dapm,
|
||||
"LINEOUT2N Driver");
|
||||
snd_soc_dapm_disable_pin(&codec->dapm,
|
||||
"LINEOUT2P Driver");
|
||||
}
|
||||
|
||||
/* Do the sync with the old mode to allow it to clean up */
|
||||
snd_soc_dapm_sync(&codec->dapm);
|
||||
wm8994->vmid_mode = mode;
|
||||
break;
|
||||
|
||||
case WM8994_VMID_FORCE:
|
||||
if (wm8994->hubs.lineout1_se) {
|
||||
snd_soc_dapm_force_enable_pin(&codec->dapm,
|
||||
"LINEOUT1N Driver");
|
||||
snd_soc_dapm_force_enable_pin(&codec->dapm,
|
||||
"LINEOUT1P Driver");
|
||||
}
|
||||
if (wm8994->hubs.lineout2_se) {
|
||||
snd_soc_dapm_force_enable_pin(&codec->dapm,
|
||||
"LINEOUT2N Driver");
|
||||
snd_soc_dapm_force_enable_pin(&codec->dapm,
|
||||
"LINEOUT2P Driver");
|
||||
}
|
||||
|
||||
wm8994->vmid_mode = mode;
|
||||
snd_soc_dapm_sync(&codec->dapm);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
|
@ -32,6 +32,11 @@
|
||||
#define WM8994_FLL_SRC_LRCLK 3
|
||||
#define WM8994_FLL_SRC_BCLK 4
|
||||
|
||||
enum wm8994_vmid_mode {
|
||||
WM8994_VMID_NORMAL,
|
||||
WM8994_VMID_FORCE,
|
||||
};
|
||||
|
||||
typedef void (*wm8958_micdet_cb)(u16 status, void *data);
|
||||
|
||||
int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
|
||||
@ -39,6 +44,8 @@ int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
|
||||
int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
|
||||
wm8958_micdet_cb cb, void *cb_data);
|
||||
|
||||
int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode);
|
||||
|
||||
int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event);
|
||||
|
||||
@ -75,6 +82,7 @@ struct wm8994_priv {
|
||||
|
||||
int vmid_refcount;
|
||||
int active_refcount;
|
||||
enum wm8994_vmid_mode vmid_mode;
|
||||
|
||||
int dac_rates[2];
|
||||
int lrclk_shared[2];
|
||||
|
Loading…
Reference in New Issue
Block a user