Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 270842
b: refs/heads/master
c: ba896ed
h: refs/heads/master
v: v3
  • Loading branch information
Mark Brown committed Oct 11, 2011
1 parent b2eacd8 commit 4687863
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 3a53d827292b657afcb73495cac139371cb157e1
refs/heads/master: ba896ede9a9a54a9114ee2a4fe534328078c6b02
162 changes: 162 additions & 0 deletions trunk/sound/soc/codecs/wm5100.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/jack.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <sound/wm5100.h>
Expand Down Expand Up @@ -68,6 +69,11 @@ struct wm5100_priv {

bool out_ena[2];

struct snd_soc_jack *jack;
bool jack_detecting;
bool jack_mic;
int jack_mode;

struct wm5100_fll fll[2];

struct wm5100_pdata pdata;
Expand Down Expand Up @@ -2113,6 +2119,159 @@ static int wm5100_dig_vu[] = {
WM5100_DAC_DIGITAL_VOLUME_6R,
};

static void wm5100_set_detect_mode(struct snd_soc_codec *codec, int the_mode)
{
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
struct wm5100_jack_mode *mode = &wm5100->pdata.jack_modes[the_mode];

BUG_ON(the_mode >= ARRAY_SIZE(wm5100->pdata.jack_modes));

gpio_set_value_cansleep(wm5100->pdata.hp_pol, mode->hp_pol);
snd_soc_update_bits(codec, WM5100_ACCESSORY_DETECT_MODE_1,
WM5100_ACCDET_BIAS_SRC_MASK |
WM5100_ACCDET_SRC,
(mode->bias << WM5100_ACCDET_BIAS_SRC_SHIFT) |
mode->micd_src << WM5100_ACCDET_SRC_SHIFT);

wm5100->jack_mode = the_mode;

dev_dbg(codec->dev, "Set microphone polarity to %d\n",
wm5100->jack_mode);
}

static void wm5100_micd_irq(struct snd_soc_codec *codec)
{
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
int val;

val = snd_soc_read(codec, WM5100_MIC_DETECT_3);

dev_dbg(codec->dev, "Microphone event: %x\n", val);

if (!(val & WM5100_ACCDET_VALID)) {
dev_warn(codec->dev, "Microphone detection state invalid\n");
return;
}

/* No accessory, reset everything and report removal */
if (!(val & WM5100_ACCDET_STS)) {
dev_dbg(codec->dev, "Jack removal detected\n");
wm5100->jack_mic = false;
wm5100->jack_detecting = true;
snd_soc_jack_report(wm5100->jack, 0,
SND_JACK_LINEOUT | SND_JACK_HEADSET |
SND_JACK_BTN_0);

snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
WM5100_ACCDET_RATE_MASK,
WM5100_ACCDET_RATE_MASK);
return;
}

/* 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) {
if (wm5100->jack_detecting) {
dev_dbg(codec->dev, "Microphone detected\n");
wm5100->jack_mic = true;
snd_soc_jack_report(wm5100->jack,
SND_JACK_HEADSET,
SND_JACK_HEADSET | SND_JACK_BTN_0);

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

return;
}

/* If we detected a lower impedence during initial startup
* then we probably have the wrong polarity, flip it. Don't
* do this for the lowest impedences to speed up detection of
* plain headphones.
*/
if (wm5100->jack_detecting && (val & 0x3f8)) {
wm5100_set_detect_mode(codec, !wm5100->jack_mode);

return;
}

/* Don't distinguish between buttons, just report any low
* impedence as BTN_0.
*/
if (val & 0x3fc) {
if (wm5100->jack_mic) {
dev_dbg(codec->dev, "Mic button detected\n");
snd_soc_jack_report(wm5100->jack, SND_JACK_BTN_0,
SND_JACK_BTN_0);
} else if (wm5100->jack_detecting) {
dev_dbg(codec->dev, "Headphone detected\n");
snd_soc_jack_report(wm5100->jack, SND_JACK_HEADPHONE,
SND_JACK_HEADPHONE);

/* Increase the detection rate a bit for
* responsiveness.
*/
snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
WM5100_ACCDET_RATE_MASK,
7 << WM5100_ACCDET_RATE_SHIFT);
}
}
}

int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
{
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);

if (jack) {
wm5100->jack = jack;
wm5100->jack_detecting = true;

wm5100_set_detect_mode(codec, 0);

/* Slowest detection rate, gives debounce for initial
* detection */
snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
WM5100_ACCDET_BIAS_STARTTIME_MASK |
WM5100_ACCDET_RATE_MASK,
(7 << WM5100_ACCDET_BIAS_STARTTIME_SHIFT) |
WM5100_ACCDET_RATE_MASK);

/* We need the charge pump to power MICBIAS */
snd_soc_dapm_force_enable_pin(&codec->dapm, "CP2");
snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK");
snd_soc_dapm_sync(&codec->dapm);

/* We start off just enabling microphone detection - even a
* plain headphone will trigger detection.
*/
snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
WM5100_ACCDET_ENA, WM5100_ACCDET_ENA);

snd_soc_update_bits(codec, WM5100_INTERRUPT_STATUS_3_MASK,
WM5100_IM_ACCDET_EINT, 0);
} else {
snd_soc_update_bits(codec, WM5100_INTERRUPT_STATUS_3_MASK,
WM5100_IM_HPDET_EINT |
WM5100_IM_ACCDET_EINT,
WM5100_IM_HPDET_EINT |
WM5100_IM_ACCDET_EINT);
snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
WM5100_ACCDET_ENA, 0);
wm5100->jack = NULL;
}

return 0;
}

static irqreturn_t wm5100_irq(int irq, void *data)
{
struct snd_soc_codec *codec = data;
Expand Down Expand Up @@ -2144,6 +2303,9 @@ static irqreturn_t wm5100_irq(int irq, void *data)
complete(&wm5100->fll[1].lock);
}

if (irq_val & WM5100_ACCDET_EINT)
wm5100_micd_irq(codec);

irq_val = snd_soc_read(codec, WM5100_INTERRUPT_STATUS_4);
if (irq_val < 0) {
dev_err(codec->dev, "Failed to read IRQ status 4: %d\n",
Expand Down
2 changes: 2 additions & 0 deletions trunk/sound/soc/codecs/wm5100.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

#include <sound/soc.h>

int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack);

#define WM5100_CLK_AIF1 1
#define WM5100_CLK_AIF2 2
#define WM5100_CLK_AIF3 3
Expand Down

0 comments on commit 4687863

Please sign in to comment.