Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 270595
b: refs/heads/master
c: 0b684cc
h: refs/heads/master
i:
  270593: df7c062
  270591: 70662e0
v: v3
  • Loading branch information
Mark Brown committed Sep 19, 2011
1 parent e13b979 commit 4a389a2
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 26 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 8259df12fd3f3429648411bfff37dfbb34a2d9b2
refs/heads/master: 0b684cc14a791accdd6d97cb68242ab5009ece3e
137 changes: 112 additions & 25 deletions trunk/sound/soc/codecs/wm8996.c
Original file line number Diff line number Diff line change
Expand Up @@ -2350,12 +2350,94 @@ int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,

/* Enable interrupts and we're off */
snd_soc_update_bits(codec, WM8996_INTERRUPT_STATUS_2_MASK,
WM8996_IM_MICD_EINT, 0);
WM8996_IM_MICD_EINT | WM8996_HP_DONE_EINT, 0);

return 0;
}
EXPORT_SYMBOL_GPL(wm8996_detect);

static void wm8996_hpdet_irq(struct snd_soc_codec *codec)
{
struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
int val, reg, report;

/* Assume headphone in error conditions; we need to report
* something or we stall our state machine.
*/
report = SND_JACK_HEADPHONE;

reg = snd_soc_read(codec, WM8996_HEADPHONE_DETECT_2);
if (reg < 0) {
dev_err(codec->dev, "Failed to read HPDET status\n");
goto out;
}

if (!(reg & WM8996_HP_DONE)) {
dev_err(codec->dev, "Got HPDET IRQ but HPDET is busy\n");
goto out;
}

val = reg & WM8996_HP_LVL_MASK;

dev_dbg(codec->dev, "HPDET measured %d ohms\n", val);

/* If we've got high enough impedence then report as line,
* otherwise assume headphone.
*/
if (val >= 126)
report = SND_JACK_LINEOUT;
else
report = SND_JACK_HEADPHONE;

out:
if (wm8996->jack_mic)
report |= SND_JACK_MICROPHONE;

snd_soc_jack_report(wm8996->jack, report,
SND_JACK_LINEOUT | SND_JACK_HEADSET);

wm8996->detecting = false;

/* If the output isn't running re-clamp it */
if (!(snd_soc_read(codec, WM8996_POWER_MANAGEMENT_1) &
(WM8996_HPOUT1L_ENA | WM8996_HPOUT1R_RMV_SHORT)))
snd_soc_update_bits(codec, WM8996_ANALOGUE_HP_1,
WM8996_HPOUT1L_RMV_SHORT |
WM8996_HPOUT1R_RMV_SHORT, 0);

/* Go back to looking at the microphone */
snd_soc_update_bits(codec, WM8996_ACCESSORY_DETECT_MODE_1,
WM8996_JD_MODE_MASK, 0);
snd_soc_update_bits(codec, WM8996_MIC_DETECT_1, WM8996_MICD_ENA,
WM8996_MICD_ENA);

snd_soc_dapm_disable_pin(&codec->dapm, "Bandgap");
snd_soc_dapm_sync(&codec->dapm);
}

static void wm8996_hpdet_start(struct snd_soc_codec *codec)
{
/* Unclamp the output, we can't measure while we're shorting it */
snd_soc_update_bits(codec, WM8996_ANALOGUE_HP_1,
WM8996_HPOUT1L_RMV_SHORT |
WM8996_HPOUT1R_RMV_SHORT,
WM8996_HPOUT1L_RMV_SHORT |
WM8996_HPOUT1R_RMV_SHORT);

/* We need bandgap for HPDET */
snd_soc_dapm_force_enable_pin(&codec->dapm, "Bandgap");
snd_soc_dapm_sync(&codec->dapm);

/* Go into headphone detect left mode */
snd_soc_update_bits(codec, WM8996_MIC_DETECT_1, WM8996_MICD_ENA, 0);
snd_soc_update_bits(codec, WM8996_ACCESSORY_DETECT_MODE_1,
WM8996_JD_MODE_MASK, 1);

/* Trigger a measurement */
snd_soc_update_bits(codec, WM8996_HEADPHONE_DETECT_1,
WM8996_HP_POLL, WM8996_HP_POLL);
}

static void wm8996_micd(struct snd_soc_codec *codec)
{
struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
Expand All @@ -2376,28 +2458,36 @@ static void wm8996_micd(struct snd_soc_codec *codec)
wm8996->jack_mic = false;
wm8996->detecting = true;
snd_soc_jack_report(wm8996->jack, 0,
SND_JACK_HEADSET | SND_JACK_BTN_0);
SND_JACK_LINEOUT | SND_JACK_HEADSET |
SND_JACK_BTN_0);

snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
WM8996_MICD_RATE_MASK,
WM8996_MICD_RATE_MASK);
return;
}

/* If the measurement is very high we've got a microphone but
* do a little debounce to account for mechanical issues.
/* If the measurement is very high we've got a microphone,
* either we just detected one or if we already reported then
* we've got a button release event.
*/
if (val & 0x400) {
dev_dbg(codec->dev, "Microphone detected\n");
snd_soc_jack_report(wm8996->jack, SND_JACK_HEADSET,
SND_JACK_HEADSET | SND_JACK_BTN_0);
wm8996->jack_mic = true;
wm8996->detecting = false;

/* Increase poll rate to give better responsiveness
* for buttons */
snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
WM8996_MICD_RATE_MASK,
5 << WM8996_MICD_RATE_SHIFT);
if (wm8996->detecting) {
dev_dbg(codec->dev, "Microphone detected\n");
wm8996->jack_mic = true;
wm8996_hpdet_start(codec);

/* Increase poll rate to give better responsiveness
* for buttons */
snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
WM8996_MICD_RATE_MASK,
5 << WM8996_MICD_RATE_SHIFT);
} else {
dev_dbg(codec->dev, "Mic button up\n");
snd_soc_jack_report(wm8996->jack, 0, SND_JACK_BTN_0);
}

return;
}

/* If we detected a lower impedence during initial startup
Expand Down Expand Up @@ -2429,24 +2519,18 @@ static void wm8996_micd(struct snd_soc_codec *codec)
if (val & 0x3fc) {
if (wm8996->jack_mic) {
dev_dbg(codec->dev, "Mic button detected\n");
snd_soc_jack_report(wm8996->jack,
SND_JACK_HEADSET | SND_JACK_BTN_0,
SND_JACK_HEADSET | SND_JACK_BTN_0);
} else {
dev_dbg(codec->dev, "Headphone detected\n");
snd_soc_jack_report(wm8996->jack,
SND_JACK_HEADPHONE,
SND_JACK_HEADSET |
snd_soc_jack_report(wm8996->jack, SND_JACK_BTN_0,
SND_JACK_BTN_0);
} else if (wm8996->detecting) {
dev_dbg(codec->dev, "Headphone detected\n");
wm8996_hpdet_start(codec);

/* Increase the detection rate a bit for
* responsiveness.
*/
snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
WM8996_MICD_RATE_MASK,
7 << WM8996_MICD_RATE_SHIFT);

wm8996->detecting = false;
}
}
}
Expand Down Expand Up @@ -2486,6 +2570,9 @@ static irqreturn_t wm8996_irq(int irq, void *data)
if (irq_val & WM8996_MICD_EINT)
wm8996_micd(codec);

if (irq_val & WM8996_HP_DONE_EINT)
wm8996_hpdet_irq(codec);

return IRQ_HANDLED;
}

Expand Down

0 comments on commit 4a389a2

Please sign in to comment.