aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8994.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/wm8994.c')
-rw-r--r--sound/soc/codecs/wm8994.c320
1 files changed, 126 insertions, 194 deletions
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index e4b9440..7e7f4a2 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -60,8 +60,6 @@ static int wm8994_retune_mobile_base[] = {
WM8994_AIF2_EQ_GAINS_1,
};
-static void wm8958_default_micdet(u16 status, void *data);
-
static const struct wm8958_micd_rate micdet_rates[] = {
{ 32768, true, 1, 4 },
{ 32768, false, 1, 1 },
@@ -84,10 +82,6 @@ static void wm8958_micd_set_rate(struct snd_soc_codec *codec)
const struct wm8958_micd_rate *rates;
int num_rates;
- if (!(wm8994->pdata && wm8994->pdata->micd_rates) &&
- wm8994->jack_cb != wm8958_default_micdet)
- return;
-
idle = !wm8994->jack_mic;
sysclk = snd_soc_read(codec, WM8994_CLOCKING_1);
@@ -564,7 +558,7 @@ static int wm8994_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
return 0;
}
-#if defined(CONFIG_MACH_C1_KOR_LGT)
+#if defined(CONFIG_MACH_C1_KOR_LGT) || defined(CONFIG_MACH_BAFFIN_KOR_LGT)
static const char *fm_control[] = {
"OFF", "RCV", "EAR", "SPK", "SPK",
};
@@ -813,7 +807,7 @@ SOC_ENUM("AIF2DAC Noise Gate Hold Time", wm8958_aif2dac_ng_hold),
SOC_SINGLE_TLV("AIF2DAC Noise Gate Threshold Volume",
WM8958_AIF2_DAC_NOISE_GATE, WM8958_AIF2DAC_NG_THR_SHIFT,
7, 1, ng_tlv),
-#if defined(CONFIG_MACH_C1_KOR_LGT)
+#if defined(CONFIG_MACH_C1_KOR_LGT) || defined(CONFIG_MACH_BAFFIN_KOR_LGT)
SOC_ENUM_EXT("FM Control", fm_control_enum,
wm8994_get_fm_control, wm8994_put_fm_control),
#endif
@@ -832,11 +826,8 @@ SOC_SINGLE_TLV("MIXINL IN1RP Boost Volume", WM8994_INPUT_MIXER_1, 8, 1, 0,
static void wm1811_jackdet_set_mode(struct snd_soc_codec *codec, u16 mode)
{
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-#ifdef CONFIG_USE_ADC_DET
+
if (!wm8994->jackdet || !wm8994->micdet[0].jack)
-#else
- if (!wm8994->jackdet || !wm8994->jack_cb)
-#endif
return;
if (wm8994->active_refcount)
@@ -1269,9 +1260,11 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w,
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5,
WM8994_AIF2DACL_ENA |
WM8994_AIF2DACR_ENA, 0);
+ #if !defined(CONFIG_MACH_BAFFIN)
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_4,
WM8994_AIF2ADCL_ENA |
WM8994_AIF2ADCR_ENA, 0);
+ #endif
val = snd_soc_read(codec, WM8994_CLOCKING_1);
if (val & WM8994_AIF1DSPCLK_ENA)
@@ -2402,6 +2395,33 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
configure_clock(codec);
+ /*
+ * If SYSCLK will be less than 50kHz adjust AIFnCLK dividers
+ * for detection.
+ */
+ if ((max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) && (!wm8994->aifdiv[0])) {
+ dev_dbg(codec->dev, "Configuring AIFs for 128fs\n");
+ wm8994->aifdiv[0] = snd_soc_read(codec, WM8994_AIF1_RATE)
+ & WM8994_AIF1CLK_RATE_MASK;
+ wm8994->aifdiv[1] = snd_soc_read(codec, WM8994_AIF2_RATE)
+ & WM8994_AIF1CLK_RATE_MASK;
+
+ snd_soc_update_bits(codec, WM8994_AIF1_RATE,
+ WM8994_AIF1CLK_RATE_MASK, 0x1);
+ snd_soc_update_bits(codec, WM8994_AIF2_RATE,
+ WM8994_AIF2CLK_RATE_MASK, 0x1);
+ } else if ((max(wm8994->aifclk[0], wm8994->aifclk[1]) >= 50000) && wm8994->aifdiv[0]) {
+ snd_soc_update_bits(codec, WM8994_AIF1_RATE,
+ WM8994_AIF1CLK_RATE_MASK,
+ wm8994->aifdiv[0]);
+ snd_soc_update_bits(codec, WM8994_AIF2_RATE,
+ WM8994_AIF2CLK_RATE_MASK,
+ wm8994->aifdiv[1]);
+
+ wm8994->aifdiv[0] = 0;
+ wm8994->aifdiv[1] = 0;
+ }
+
return 0;
}
@@ -2470,13 +2490,11 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
break;
case WM1811:
- if (wm8994->revision < 4) {
- snd_soc_write(codec, 0x102, 0x3);
- snd_soc_write(codec, 0x56, 0x7);
- snd_soc_write(codec, 0x5d, 0x7e);
- snd_soc_write(codec, 0x5e, 0x0);
- snd_soc_write(codec, 0x102, 0x0);
- }
+ snd_soc_write(codec, 0x102, 0x3);
+ snd_soc_write(codec, 0x56, 0xc07);
+ snd_soc_write(codec, 0x5d, 0x7e);
+ snd_soc_write(codec, 0x5e, 0x0);
+ snd_soc_write(codec, 0x102, 0x0);
break;
}
@@ -3127,6 +3145,9 @@ static int wm8994_codec_resume(struct snd_soc_codec *codec)
/* force a HW read */
val = wm8994_reg_read(codec->control_data,
WM8994_POWER_MANAGEMENT_5);
+ if (val < 0)
+ dev_err(codec->dev, "[%s]Failed to read PM5 ret[%d]\n",
+ __func__, val);
/* modify the cache only */
codec->cache_only = 1;
@@ -3158,28 +3179,6 @@ static int wm8994_codec_resume(struct snd_soc_codec *codec)
i + 1, ret);
}
- switch (control->type) {
- case WM8994:
- if (wm8994->micdet[0].jack || wm8994->micdet[1].jack)
- snd_soc_update_bits(codec, WM8994_MICBIAS,
- WM8994_MICD_ENA, WM8994_MICD_ENA);
- break;
- case WM1811:
- if (wm8994->jackdet && wm8994->jack_cb) {
- /* Restart from idle */
- snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
- WM1811_JACKDET_MODE_MASK,
- WM1811_JACKDET_MODE_JACK);
- break;
- }
- break;
- case WM8958:
- if (wm8994->jack_cb)
- snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
- WM8958_MICD_ENA, WM8958_MICD_ENA);
- break;
- }
-
return 0;
}
#else
@@ -3425,36 +3424,79 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data)
return IRQ_HANDLED;
}
-/* Default microphone detection handler for WM8958 - the user can
- * override this if they wish.
- */
-static void wm8958_default_micdet(u16 status, void *data)
+static void wm1811_micd_stop(struct snd_soc_codec *codec)
+{
+ struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+ if (!wm8994->jackdet)
+ return;
+
+ mutex_lock(&wm8994->accdet_lock);
+
+ snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, WM8958_MICD_ENA, 0);
+
+ wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_JACK);
+
+ mutex_unlock(&wm8994->accdet_lock);
+
+ if (wm8994->pdata->jd_ext_cap)
+ snd_soc_dapm_disable_pin(&codec->dapm,
+ "MICBIAS2");
+}
+
+static void wm8958_button_det(struct snd_soc_codec *codec, u16 status)
{
- struct snd_soc_codec *codec = data;
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
int report;
+ report = 0;
+ if (status & 0x4)
+ report |= SND_JACK_BTN_0;
+
+ if (status & 0x8)
+ report |= SND_JACK_BTN_1;
+
+ if (status & 0x10)
+ report |= SND_JACK_BTN_2;
+
+ if (status & 0x20)
+ report |= SND_JACK_BTN_3;
+
+ if (status & 0x40)
+ report |= SND_JACK_BTN_4;
+
+ if (status & 0x80)
+ report |= SND_JACK_BTN_5;
+
+ snd_soc_jack_report(wm8994->micdet[0].jack, report,
+ wm8994->btn_mask);
+}
+
+static void wm8958_mic_id(void *data, u16 status)
+{
+ struct snd_soc_codec *codec = data;
+ struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
/* Either nothing present or just starting detection */
if (!(status & WM8958_MICD_STS)) {
- if (!wm8994->jackdet) {
/* If nothing present then clear our statuses */
dev_dbg(codec->dev, "Detected open circuit\n");
wm8994->jack_mic = false;
wm8994->mic_detecting = true;
+ wm1811_micd_stop(codec);
+
wm8958_micd_set_rate(codec);
snd_soc_jack_report(wm8994->micdet[0].jack, 0,
wm8994->btn_mask |
SND_JACK_HEADSET);
- }
return;
}
-
/* If the measurement is showing a high impedence we've got a
* microphone.
*/
- if (wm8994->mic_detecting && (status & 0x600)) {
+ if (status & 0x600) {
dev_dbg(codec->dev, "Detected microphone\n");
wm8994->mic_detecting = false;
@@ -3467,7 +3509,7 @@ static void wm8958_default_micdet(u16 status, void *data)
}
- if (wm8994->mic_detecting && status & 0x4) {
+ if (status & 0x4) {
dev_dbg(codec->dev, "Detected headphone\n");
wm8994->mic_detecting = false;
@@ -3477,50 +3519,10 @@ static void wm8958_default_micdet(u16 status, void *data)
SND_JACK_HEADSET);
/* If we have jackdet that will detect removal */
- if (wm8994->jackdet) {
- mutex_lock(&wm8994->accdet_lock);
-
- snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
- WM8958_MICD_ENA, 0);
-
- wm1811_jackdet_set_mode(codec,
- WM1811_JACKDET_MODE_JACK);
-
- mutex_unlock(&wm8994->accdet_lock);
-
- if (wm8994->pdata->jd_ext_cap) {
- mutex_lock(&codec->mutex);
- snd_soc_dapm_disable_pin(&codec->dapm,
- "MICBIAS2");
- snd_soc_dapm_sync(&codec->dapm);
- mutex_unlock(&codec->mutex);
- }
- }
- }
-
- /* Report short circuit as a button */
- if (wm8994->jack_mic) {
- report = 0;
- if (status & 0x4)
- report |= SND_JACK_BTN_0;
-
- if (status & 0x8)
- report |= SND_JACK_BTN_1;
-
- if (status & 0x10)
- report |= SND_JACK_BTN_2;
-
- if (status & 0x20)
- report |= SND_JACK_BTN_3;
-
- if (status & 0x40)
- report |= SND_JACK_BTN_4;
+ wm1811_micd_stop(codec);
- if (status & 0x80)
- report |= SND_JACK_BTN_5;
-
- snd_soc_jack_report(wm8994->micdet[0].jack, report,
- wm8994->btn_mask);
+ snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADPHONE,
+ SND_JACK_HEADSET);
}
}
@@ -3556,15 +3558,18 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
snd_soc_update_bits(codec, WM1811_JACKDET_CTRL,
WM1811_JACKDET_DB, 0);
+ /* If there's a callback it'll be called out of the lock */
+ if (!wm8994->micd_cb) {
/*
- * Start off measument of microphone impedence to find
- * out what's actually there.
+ * Start off measument of microphone impedence to find out
+ * what's actually there.
*/
wm8994->mic_detecting = true;
wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_MIC);
snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
WM8958_MICD_ENA, WM8958_MICD_ENA);
+ }
} else {
dev_dbg(codec->dev, "Jack not detected\n");
@@ -3606,6 +3611,10 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
SND_JACK_MECHANICAL | SND_JACK_HEADSET |
wm8994->btn_mask);
+ /* Custom callbacks may reasonably wish to take the same locks */
+ if (present && wm8994->micd_cb)
+ wm8994->micd_cb(wm8994->micd_cb_data);
+
return IRQ_HANDLED;
}
@@ -3625,7 +3634,6 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
* flexiblity a callback is provided which allows a completely custom
* detection algorithm.
*/
-#ifdef CONFIG_USE_ADC_DET
int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
wm1811_micdet_cb det_cb, void *det_cb_data,
wm1811_mic_id_cb id_cb, void *id_cb_data)
@@ -3652,8 +3660,8 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
wm8994->micd_cb = det_cb;
wm8994->micd_cb_data = det_cb_data;
} else {
- wm8994->mic_detecting = true;
- wm8994->jack_mic = false;
+ wm8994->mic_detecting = true;
+ wm8994->jack_mic = false;
}
if (id_cb) {
@@ -3708,91 +3716,13 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
return 0;
}
-#else
-int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
- wm8958_micdet_cb cb, void *cb_data)
-{
- struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
- struct wm8994 *control = codec->control_data;
- u16 micd_lvl_sel;
-
- switch (control->type) {
- case WM1811:
- case WM8958:
- break;
- default:
- return -EINVAL;
- }
-
- if (jack) {
- if (!cb) {
- dev_dbg(codec->dev, "Using default micdet callback\n");
- cb = wm8958_default_micdet;
- cb_data = codec;
- }
-
- snd_soc_dapm_force_enable_pin(&codec->dapm, "CLK_SYS");
- snd_soc_dapm_sync(&codec->dapm);
-
- wm8994->micdet[0].jack = jack;
- wm8994->jack_cb = cb;
- wm8994->jack_cb_data = cb_data;
-
- wm8994->mic_detecting = true;
- wm8994->jack_mic = false;
-
- wm8958_micd_set_rate(codec);
-
- /* Detect microphones and short circuits by default */
- if (wm8994->pdata->micd_lvl_sel)
- micd_lvl_sel = wm8994->pdata->micd_lvl_sel;
- else
- micd_lvl_sel = 0x41;
-
- wm8994->btn_mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3 |
- SND_JACK_BTN_4 | SND_JACK_BTN_5;
-
- snd_soc_update_bits(codec, WM8958_MIC_DETECT_2,
- WM8958_MICD_LVL_SEL_MASK, micd_lvl_sel);
-
- WARN_ON(codec->dapm.bias_level > SND_SOC_BIAS_STANDBY);
-
- /*
- * If we can use jack detection start off with that,
- * otherwise jump straight to microphone detection.
- */
- if (wm8994->jackdet) {
- snd_soc_update_bits(codec, WM8958_MICBIAS2,
- WM8958_MICB2_DISCH,
- WM8958_MICB2_DISCH);
- snd_soc_update_bits(codec, WM8994_LDO_1,
- WM8994_LDO1_DISCH, 0);
- wm1811_jackdet_set_mode(codec,
- WM1811_JACKDET_MODE_JACK);
- } else {
- snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
- WM8958_MICD_ENA, WM8958_MICD_ENA);
- }
-
- } else {
- snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
- WM8958_MICD_ENA, 0);
- wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_NONE);
- snd_soc_dapm_disable_pin(&codec->dapm, "CLK_SYS");
- snd_soc_dapm_sync(&codec->dapm);
- }
-
- return 0;
-}
-#endif
EXPORT_SYMBOL_GPL(wm8958_mic_detect);
static irqreturn_t wm8958_mic_irq(int irq, void *data)
{
struct wm8994_priv *wm8994 = data;
struct snd_soc_codec *codec = wm8994->codec;
- int reg, count;
+ int reg, count, ret;
/*
* Jack detection may have detected a removal simulataneously
@@ -3833,10 +3763,22 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
trace_snd_soc_jack_irq(dev_name(codec->dev));
#endif
- if (wm8994->jack_cb)
- wm8994->jack_cb(reg, wm8994->jack_cb_data);
+ /* Avoid a transient report when the accessory is being removed */
+ if (wm8994->jackdet) {
+ ret = snd_soc_read(codec, WM1811_JACKDET_CTRL);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to read jack status: %d\n",
+ ret);
+ } else if (!(ret & WM1811_JACKDET_LVL)) {
+ dev_dbg(codec->dev, "Ignoring removed jack\n");
+ return IRQ_HANDLED;
+ }
+ }
+
+ if (wm8994->mic_detecting)
+ wm8994->mic_id_cb(wm8994->mic_id_cb_data, reg);
else
- dev_warn(codec->dev, "Accessory detection with no callback\n");
+ wm8958_button_det(codec, reg);
out:
return IRQ_HANDLED;
@@ -3968,18 +3910,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
wm8994->hubs.hp_startup_mode = 1;
wm8994->hubs.no_cache_dac_hp_direct = true;
wm8994->fll_byp = true;
-
- switch (wm8994->revision) {
- case 0:
- case 1:
- case 2:
- case 3:
- wm8994->hubs.dcs_codes_l = -9;
- wm8994->hubs.dcs_codes_r = -7;
- break;
- default:
- break;
- }
+ wm8994->hubs.dcs_codes_l = -11;
+ wm8994->hubs.dcs_codes_r = -9;
snd_soc_update_bits(codec, WM8994_ANALOGUE_HP_1,
WM1811_HPOUT1_ATTN, WM1811_HPOUT1_ATTN);
@@ -4433,7 +4365,7 @@ static int wm8994_resume(struct device *dev)
{
struct wm8994_priv *wm8994 = dev_get_drvdata(dev);
- if (wm8994->jackdet && wm8994->jack_cb) {
+ if (wm8994->jackdet && wm8994->jackdet_mode) {
snd_soc_update_bits(wm8994->codec, WM8994_ANTIPOP_2,
WM1811_JACKDET_MODE_MASK,
WM1811_JACKDET_MODE_AUDIO);