* [PATCH 1/2] ASoC: Initial WM8996 headphone impedance measurement support
@ 2011-09-17 13:14 Mark Brown
2011-09-17 13:14 ` [PATCH 2/2] ASoC: Add line loads to the list of supported detections for Speyside Mark Brown
2011-09-19 9:24 ` [PATCH 1/2] ASoC: Initial WM8996 headphone impedance measurement support Girdwood, Liam
0 siblings, 2 replies; 3+ messages in thread
From: Mark Brown @ 2011-09-17 13:14 UTC (permalink / raw)
To: Liam Girdwood; +Cc: alsa-devel, patches, Mark Brown
The WM8996 can measure the impedance of accessories connected to the
headphone output. Implement initial support for this, measuring the
left channel impedance when an accessory is detected and using this
to distinguish between a line load and a headphone load.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
sound/soc/codecs/wm8996.c | 137 ++++++++++++++++++++++++++++++++++++--------
1 files changed, 112 insertions(+), 25 deletions(-)
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index 8e9d7f7..a6168c5 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -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);
@@ -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
@@ -2429,15 +2519,11 @@ 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.
@@ -2445,8 +2531,6 @@ static void wm8996_micd(struct snd_soc_codec *codec)
snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
WM8996_MICD_RATE_MASK,
7 << WM8996_MICD_RATE_SHIFT);
-
- wm8996->detecting = false;
}
}
}
@@ -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;
}
--
1.7.6.3
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 2/2] ASoC: Add line loads to the list of supported detections for Speyside
2011-09-17 13:14 [PATCH 1/2] ASoC: Initial WM8996 headphone impedance measurement support Mark Brown
@ 2011-09-17 13:14 ` Mark Brown
2011-09-19 9:24 ` [PATCH 1/2] ASoC: Initial WM8996 headphone impedance measurement support Girdwood, Liam
1 sibling, 0 replies; 3+ messages in thread
From: Mark Brown @ 2011-09-17 13:14 UTC (permalink / raw)
To: Liam Girdwood; +Cc: alsa-devel, patches, Mark Brown
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
sound/soc/samsung/speyside.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c
index 6652c3c..dfa62c9 100644
--- a/sound/soc/samsung/speyside.c
+++ b/sound/soc/samsung/speyside.c
@@ -167,7 +167,8 @@ static int speyside_wm8996_init(struct snd_soc_pcm_runtime *rtd)
gpio_direction_output(WM8996_HPSEL_GPIO, speyside_jack_polarity);
ret = snd_soc_jack_new(codec, "Headset",
- SND_JACK_HEADSET | SND_JACK_BTN_0,
+ SND_JACK_LINEOUT | SND_JACK_HEADSET |
+ SND_JACK_BTN_0,
&speyside_headset);
if (ret)
return ret;
--
1.7.6.3
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH 1/2] ASoC: Initial WM8996 headphone impedance measurement support
2011-09-17 13:14 [PATCH 1/2] ASoC: Initial WM8996 headphone impedance measurement support Mark Brown
2011-09-17 13:14 ` [PATCH 2/2] ASoC: Add line loads to the list of supported detections for Speyside Mark Brown
@ 2011-09-19 9:24 ` Girdwood, Liam
1 sibling, 0 replies; 3+ messages in thread
From: Girdwood, Liam @ 2011-09-19 9:24 UTC (permalink / raw)
To: Mark Brown; +Cc: alsa-devel, patches
On 17 September 2011 14:14, Mark Brown
<broonie@opensource.wolfsonmicro.com>wrote:
> The WM8996 can measure the impedance of accessories connected to the
> headphone output. Implement initial support for this, measuring the
> left channel impedance when an accessory is detected and using this
> to distinguish between a line load and a headphone load.
>
> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
> ---
> sound/soc/codecs/wm8996.c | 137
> ++++++++++++++++++++++++++++++++++++--------
> 1 files changed, 112 insertions(+), 25 deletions(-)
>
>
Both
Acked-by: Liam Girdwood <lrg@ti.com>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2011-09-19 9:24 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-09-17 13:14 [PATCH 1/2] ASoC: Initial WM8996 headphone impedance measurement support Mark Brown
2011-09-17 13:14 ` [PATCH 2/2] ASoC: Add line loads to the list of supported detections for Speyside Mark Brown
2011-09-19 9:24 ` [PATCH 1/2] ASoC: Initial WM8996 headphone impedance measurement support Girdwood, Liam
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).