aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r--sound/soc/codecs/wm8994.c187
-rw-r--r--sound/soc/codecs/wm8994.h8
-rw-r--r--sound/soc/codecs/wm8996.c19
-rw-r--r--sound/soc/codecs/wm_hubs.c16
4 files changed, 171 insertions, 59 deletions
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 15fcb1bb7148..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)
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);
+
+ msleep(50);
- /* 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);
+ snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+ WM8994_VMID_RAMP_MASK |
+ WM8994_BIAS_SRC,
+ 0);
+ break;
- msleep(50);
+ 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);
+ 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;
@@ -2819,6 +2927,7 @@ static int wm8994_codec_resume(struct snd_soc_codec *codec)
WM1811_JACKDET_MODE_JACK);
break;
}
+ break;
case WM8958:
if (wm8994->jack_cb)
snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index 2f4d2d12a452..c724112998d8 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -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];
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index 40a124c9f15d..1fd635494045 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -1914,7 +1914,7 @@ static int wm8996_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_codec *codec = dai->codec;
struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
- int bits, i, bclk_rate;
+ int bits, i, bclk_rate, best;
int aifdata = 0;
int lrclk = 0;
int dsp = 0;
@@ -1963,14 +1963,11 @@ static int wm8996_hw_params(struct snd_pcm_substream *substream,
return bits;
aifdata |= (bits << WM8996_AIF1TX_WL_SHIFT) | bits;
+ best = 0;
for (i = 0; i < ARRAY_SIZE(dsp_divs); i++) {
- if (dsp_divs[i] == params_rate(params))
- break;
- }
- if (i == ARRAY_SIZE(dsp_divs)) {
- dev_err(codec->dev, "Unsupported sample rate %dHz\n",
- params_rate(params));
- return -EINVAL;
+ if (abs(dsp_divs[i] - params_rate(params)) <
+ abs(dsp_divs[best] - params_rate(params)))
+ best = i;
}
dsp |= i << dsp_shift;
@@ -2030,13 +2027,16 @@ static int wm8996_set_sysclk(struct snd_soc_dai *dai,
}
switch (wm8996->sysclk) {
+ case 5644800:
case 6144000:
snd_soc_update_bits(codec, WM8996_AIF_RATE,
WM8996_SYSCLK_RATE, 0);
break;
+ case 22579200:
case 24576000:
ratediv = WM8996_SYSCLK_DIV;
wm8996->sysclk /= 2;
+ case 11289600:
case 12288000:
snd_soc_update_bits(codec, WM8996_AIF_RATE,
WM8996_SYSCLK_RATE, WM8996_SYSCLK_RATE);
@@ -3060,7 +3060,8 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8996 = {
};
#define WM8996_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+ SNDRV_PCM_RATE_48000)
#define WM8996_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE |\
SNDRV_PCM_FMTBIT_S32_LE)
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index c08d1c2f346f..f13f2886339c 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -643,8 +643,6 @@ SND_SOC_DAPM_INPUT("IN2RP:VXRP"),
SND_SOC_DAPM_SUPPLY("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0, NULL, 0),
-SND_SOC_DAPM_SUPPLY("LINEOUT_VMID_BUF", WM8993_ANTIPOP1, 7, 0, NULL, 0),
-
SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0,
in1l_pga, ARRAY_SIZE(in1l_pga)),
SND_SOC_DAPM_MIXER("IN1R PGA", WM8993_POWER_MANAGEMENT_2, 4, 0,
@@ -869,11 +867,9 @@ static const struct snd_soc_dapm_route lineout1_diff_routes[] = {
};
static const struct snd_soc_dapm_route lineout1_se_routes[] = {
- { "LINEOUT1N Mixer", NULL, "LINEOUT_VMID_BUF" },
{ "LINEOUT1N Mixer", "Left Output Switch", "Left Output PGA" },
{ "LINEOUT1N Mixer", "Right Output Switch", "Right Output PGA" },
- { "LINEOUT1P Mixer", NULL, "LINEOUT_VMID_BUF" },
{ "LINEOUT1P Mixer", "Left Output Switch", "Left Output PGA" },
{ "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" },
@@ -890,11 +886,9 @@ static const struct snd_soc_dapm_route lineout2_diff_routes[] = {
};
static const struct snd_soc_dapm_route lineout2_se_routes[] = {
- { "LINEOUT2N Mixer", NULL, "LINEOUT_VMID_BUF" },
{ "LINEOUT2N Mixer", "Left Output Switch", "Left Output PGA" },
{ "LINEOUT2N Mixer", "Right Output Switch", "Right Output PGA" },
- { "LINEOUT2P Mixer", NULL, "LINEOUT_VMID_BUF" },
{ "LINEOUT2P Mixer", "Right Output Switch", "Right Output PGA" },
{ "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" },
@@ -996,6 +990,11 @@ int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec,
WM8993_LINEOUT2_MODE,
WM8993_LINEOUT2_MODE);
+ if (!lineout1_diff && !lineout2_diff)
+ snd_soc_update_bits(codec, WM8993_ANTIPOP1,
+ WM8993_LINEOUT_VMID_BUF_ENA,
+ WM8993_LINEOUT_VMID_BUF_ENA);
+
if (lineout1fb)
snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB);
@@ -1068,11 +1067,6 @@ void wm_hubs_set_bias_level(struct snd_soc_codec *codec,
WM8993_LINEOUT2P_ENA,
val);
- if (!hubs->lineout1n_ena && !hubs->lineout1p_ena &&
- !hubs->lineout2n_ena && !hubs->lineout2p_ena)
- snd_soc_update_bits(codec, WM8993_ANTIPOP1,
- WM8993_LINEOUT_VMID_BUF_ENA, 0);
-
/* Remove the input clamps */
snd_soc_update_bits(codec, WM8993_INPUTS_CLAMP_REG,
WM8993_INPUTS_CLAMP, 0);