ASoC: wm8994: Bring WM8994 accessory detection up to date

Make the mechanism used for WM8994 more like that for WM1811 and WM8958:
provide the logic to distinguish between headphone and headset and hard
code the reporting of sensible SND_JACK values. Should integration with
other detection mechanisms be required we can add appropriate callbacks
(though some integrations should be able to use the subsystem ones).

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
This commit is contained in:
Mark Brown 2012-02-06 18:50:39 +00:00
parent 27060b3c64
commit 87092e3ca4
2 changed files with 63 additions and 24 deletions

View File

@ -2946,8 +2946,6 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
* @codec: WM8994 codec * @codec: WM8994 codec
* @jack: jack to report detection events on * @jack: jack to report detection events on
* @micbias: microphone bias to detect on * @micbias: microphone bias to detect on
* @det: value to report for presence detection
* @shrt: value to report for short detection
* *
* Enable microphone detection via IRQ on the WM8994. If GPIOs are * Enable microphone detection via IRQ on the WM8994. If GPIOs are
* being used to bring out signals to the processor then only platform * being used to bring out signals to the processor then only platform
@ -2958,43 +2956,63 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
* and micbias2_lvl platform data members. * and micbias2_lvl platform data members.
*/ */
int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
int micbias, int det, int shrt) int micbias)
{ {
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994_micdet *micdet; struct wm8994_micdet *micdet;
struct wm8994 *control = wm8994->wm8994; struct wm8994 *control = wm8994->wm8994;
int reg; int reg, ret;
if (control->type != WM8994) if (control->type != WM8994) {
dev_warn(codec->dev, "Not a WM8994\n");
return -EINVAL; return -EINVAL;
}
switch (micbias) { switch (micbias) {
case 1: case 1:
micdet = &wm8994->micdet[0]; micdet = &wm8994->micdet[0];
if (jack)
ret = snd_soc_dapm_force_enable_pin(&codec->dapm,
"MICBIAS1");
else
ret = snd_soc_dapm_disable_pin(&codec->dapm,
"MICBIAS1");
break; break;
case 2: case 2:
micdet = &wm8994->micdet[1]; micdet = &wm8994->micdet[1];
if (jack)
ret = snd_soc_dapm_force_enable_pin(&codec->dapm,
"MICBIAS1");
else
ret = snd_soc_dapm_disable_pin(&codec->dapm,
"MICBIAS1");
break; break;
default: default:
dev_warn(codec->dev, "Invalid MICBIAS %d\n", micbias);
return -EINVAL; return -EINVAL;
} }
dev_dbg(codec->dev, "Configuring microphone detection on %d: %x %x\n", if (ret != 0)
micbias, det, shrt); dev_warn(codec->dev, "Failed to configure MICBIAS%d: %d\n",
micbias, ret);
dev_dbg(codec->dev, "Configuring microphone detection on %d %p\n",
micbias, jack);
/* Store the configuration */ /* Store the configuration */
micdet->jack = jack; micdet->jack = jack;
micdet->det = det; micdet->detecting = true;
micdet->shrt = shrt;
/* If either of the jacks is set up then enable detection */ /* If either of the jacks is set up then enable detection */
if (wm8994->micdet[0].jack || wm8994->micdet[1].jack) if (wm8994->micdet[0].jack || wm8994->micdet[1].jack)
reg = WM8994_MICD_ENA; reg = WM8994_MICD_ENA;
else else
reg = 0; reg = 0;
snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, reg); snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, reg);
snd_soc_dapm_sync(&codec->dapm);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(wm8994_mic_detect); EXPORT_SYMBOL_GPL(wm8994_mic_detect);
@ -3020,20 +3038,42 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data)
dev_dbg(codec->dev, "Microphone status: %x\n", reg); dev_dbg(codec->dev, "Microphone status: %x\n", reg);
report = 0; report = 0;
if (reg & WM8994_MIC1_DET_STS) if (reg & WM8994_MIC1_DET_STS) {
report |= priv->micdet[0].det; if (priv->micdet[0].detecting)
if (reg & WM8994_MIC1_SHRT_STS) report = SND_JACK_HEADSET;
report |= priv->micdet[0].shrt; }
if (reg & WM8994_MIC1_SHRT_STS) {
if (priv->micdet[0].detecting)
report = SND_JACK_HEADPHONE;
else
report |= SND_JACK_BTN_0;
}
if (report)
priv->micdet[0].detecting = false;
else
priv->micdet[0].detecting = true;
snd_soc_jack_report(priv->micdet[0].jack, report, snd_soc_jack_report(priv->micdet[0].jack, report,
priv->micdet[0].det | priv->micdet[0].shrt); SND_JACK_HEADSET | SND_JACK_BTN_0);
report = 0; report = 0;
if (reg & WM8994_MIC2_DET_STS) if (reg & WM8994_MIC2_DET_STS) {
report |= priv->micdet[1].det; if (priv->micdet[1].detecting)
if (reg & WM8994_MIC2_SHRT_STS) report = SND_JACK_HEADSET;
report |= priv->micdet[1].shrt; }
if (reg & WM8994_MIC2_SHRT_STS) {
if (priv->micdet[1].detecting)
report = SND_JACK_HEADPHONE;
else
report |= SND_JACK_BTN_0;
}
if (report)
priv->micdet[1].detecting = false;
else
priv->micdet[1].detecting = true;
snd_soc_jack_report(priv->micdet[1].jack, report, snd_soc_jack_report(priv->micdet[1].jack, report,
priv->micdet[1].det | priv->micdet[1].shrt); SND_JACK_HEADSET | SND_JACK_BTN_0);
return IRQ_HANDLED; return IRQ_HANDLED;
} }

View File

@ -35,7 +35,7 @@
typedef void (*wm8958_micdet_cb)(u16 status, void *data); typedef void (*wm8958_micdet_cb)(u16 status, void *data);
int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
int micbias, int det, int shrt); int micbias);
int wm8958_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); wm8958_micdet_cb cb, void *cb_data);
@ -46,8 +46,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec);
struct wm8994_micdet { struct wm8994_micdet {
struct snd_soc_jack *jack; struct snd_soc_jack *jack;
int det; bool detecting;
int shrt;
}; };
/* codec private data */ /* codec private data */