[alsa-devel] [PATCH v3 2/3] ASoC: twl6040: Add jack support for headset and handset
From: Jorge Eduardo Candelaria jorge.candelaria@ti.com
This patch adds support for reporting twl6040 headset and handset jack events.
The machine driver retrieves and report the status through twl6040_hs_jack_detect in case of the early interrupt.
Signed-off-by: Jorge Eduardo Candelaria jorge.candelaria@ti.com Signed-off-by: Misael Lopez Cruz misael.lopez@ti.com Signed-off-by: Margarita Olaya Cabrera magi.olaya@ti.com --- sound/soc/codecs/twl6040.c | 42 ++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/twl6040.h | 12 ++++++++++++ 2 files changed, 54 insertions(+), 0 deletions(-)
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index b92f2b7..c3799d7 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -42,10 +42,16 @@ #define TWL6040_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) #define TWL6040_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
+struct twl6040_jack_data { + struct snd_soc_jack *jack; + int report; +}; + /* codec private data */ struct twl6040_data { int audpwron; int naudint; + struct twl6040_jack_data hs_jack; int codec_powered; int pll; int non_lp; @@ -386,6 +392,8 @@ static irqreturn_t twl6040_naudint_handler(int irq, void *data) { struct snd_soc_codec *codec = data; struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); + struct twl6040_jack_data *jack = &priv->hs_jack; + int report = 0; u8 intid;
twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &intid, TWL6040_REG_INTID); @@ -395,7 +403,23 @@ static irqreturn_t twl6040_naudint_handler(int irq, void *data) dev_alert(codec->dev, "die temp over-limit detection\n"); break; case TWL6040_PLUGINT: + /* Debounce */ + msleep(200); + report = jack->report; + /* + * Early interrupt, CODEC driver cannot report jack status + * since jack is not registered yet. MACHINE driver will + * register jack and report status thru twl6040_hs_jack_detect + */ + if (jack->jack) + snd_soc_jack_report(jack->jack, report, jack->report); + break; case TWL6040_UNPLUGINT: + /* Debounce */ + msleep(200); + if (jack->jack) + snd_soc_jack_report(jack->jack, report, jack->report); + break; case TWL6040_HOOKINT: break; case TWL6040_HFINT: @@ -1011,6 +1035,24 @@ static int twl6040_resume(struct snd_soc_codec *codec) #define twl6040_resume NULL #endif
+void twl6040_hs_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *jack, int report) +{ + struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); + int status; + + priv->hs_jack.jack = jack; + priv->hs_jack.report = report; + + /* Sync status */ + status = twl6040_read_reg_volatile(codec, TWL6040_REG_STATUS); + if (status & TWL6040_PLUGCOMP) + snd_soc_jack_report(jack, report, report); + else + snd_soc_jack_report(jack, 0, report); +} +EXPORT_SYMBOL_GPL(twl6040_hs_jack_detect); + static int twl6040_probe(struct snd_soc_codec *codec) { struct twl4030_codec_data *twl_codec = codec->dev->platform_data; diff --git a/sound/soc/codecs/twl6040.h b/sound/soc/codecs/twl6040.h index f7c77fa..5456c18 100644 --- a/sound/soc/codecs/twl6040.h +++ b/sound/soc/codecs/twl6040.h @@ -135,4 +135,16 @@ #define TWL6040_HPPLL_ID 1 #define TWL6040_LPPLL_ID 2
+/* STATUS (0x2E) fields */ + +#define TWL6040_PLUGCOMP 0x02 + +struct twl6040_setup_data { + void (*codec_enable)(int enable); + void *jack; +}; + +void twl6040_hs_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *jack, int report); + #endif /* End of __TWL6040_H__ */
On Wed, Dec 08, 2010 at 10:55:08AM -0600, Olaya, Margarita wrote:
case TWL6040_PLUGINT:
/* Debounce */
msleep(200);
Hrm. We're blocking the interrupt thread for an extended period, and since we don't re-read the status after the debounce period the debounce effectiveness will be substantially reduced, and may go very wrong if we also get a removal interrupt queued up in the meantime as the removal IRQ would then get processed even if the jack was actually inserted.
Scheduling a work item which checks the jack status (like hs_jack_detect below does) for both plug and unplug IRQs would deal with this - the work will get deferred each time we bounce, and the final status will be whatever it stabalises at.
report = jack->report;
/*
* Early interrupt, CODEC driver cannot report jack status
* since jack is not registered yet. MACHINE driver will
* register jack and report status thru twl6040_hs_jack_detect
*/
if (jack->jack)
snd_soc_jack_report(jack->jack, report, jack->report);
The jack API should handle null jacks happily.
+struct twl6040_setup_data {
- void (*codec_enable)(int enable);
- void *jack;
+};
The jack doesn't look to be used in this, and I guess the codec enable belongs with something else?
participants (2)
-
Mark Brown
-
Olaya, Margarita