summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorNikesh Oswal <noswal@nvidia.com>2011-10-10 17:40:54 +0530
committerVarun Colbert <vcolbert@nvidia.com>2011-10-11 11:43:15 -0700
commitfa4c367b3562a601d2720587def8835cd9a24160 (patch)
treebb386c84733062c860fedc4d3d4342c535e2192f /sound
parent1819a373c153beb2ee456d89550dd50dcc738789 (diff)
asoc: wm8753: add headphone detection code
Bug: 862023 Change-Id: I26789c9e5bc7ebd51f086a3be650186d8e541519 Signed-off-by: Nikesh Oswal <noswal@nvidia.com> Reviewed-on: http://git-master/r/57035 Reviewed-by: Sumit Bhattacharya <sumitb@nvidia.com> Reviewed-by: Scott Peterson <speterson@nvidia.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/wm8753.c89
-rw-r--r--sound/soc/codecs/wm8753.h25
2 files changed, 112 insertions, 2 deletions
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index ffa2ffe5ec11..71afc1505157 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -48,6 +48,7 @@
#include <sound/initval.h>
#include <sound/tlv.h>
#include <asm/div64.h>
+#include <sound/jack.h>
#include "wm8753.h"
@@ -94,6 +95,9 @@ struct wm8753_priv {
unsigned int hifi_fmt;
int dai_func;
+ int irq;
+ struct snd_soc_jack *headset_jack;
+ unsigned int debounce_time_hp;
};
#define wm8753_reset(c) snd_soc_write(c, WM8753_RESET, 0)
@@ -1390,13 +1394,18 @@ static void wm8753_work(struct work_struct *work)
static int wm8753_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
+ struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+
wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ disable_irq(wm8753->irq);
+
return 0;
}
static int wm8753_resume(struct snd_soc_codec *codec)
{
u16 *reg_cache = codec->reg_cache;
+ struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
int i;
/* Sync reg_cache with the hardware */
@@ -1413,6 +1422,8 @@ static int wm8753_resume(struct snd_soc_codec *codec)
wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ enable_irq(wm8753->irq);
+
/* charge wm8753 caps */
if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) {
wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
@@ -1424,6 +1435,70 @@ static int wm8753_resume(struct snd_soc_codec *codec)
return 0;
}
+static irqreturn_t wm8753_jack_handler(int irq, void *data)
+{
+ struct snd_soc_codec *codec = data;
+ struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+ unsigned int value;
+
+ /* GPIO4 interrupt disable */
+ snd_soc_update_bits(codec, WM8753_INTEN, WM8753_GPIO4IEN_MASK,
+ WM8753_GPIO4IEN_DIS);
+
+ /* sleep for debounce time */
+ msleep(wm8753->debounce_time_hp);
+
+ /* Invert GPIO4 interrupt polarity */
+ value = snd_soc_read(codec, WM8753_INTPOL);
+ if (value & WM8753_GPIO4IPOL_LOW) {
+ snd_soc_jack_report(wm8753->headset_jack, SND_JACK_HEADPHONE,
+ SND_JACK_HEADPHONE);
+ /* interupt when high i.e Headphone disconnected */
+ snd_soc_update_bits(codec, WM8753_INTPOL, WM8753_GPIO4IPOL_MASK,
+ WM8753_GPIO4IPOL_HIGH);
+ } else {
+ snd_soc_jack_report(wm8753->headset_jack, 0,
+ SND_JACK_HEADPHONE);
+ /* interupt when low i.e Headphone connected */
+ snd_soc_update_bits(codec, WM8753_INTPOL, WM8753_GPIO4IPOL_MASK,
+ WM8753_GPIO4IPOL_LOW);
+ }
+
+ /* GPIO4 interrupt enable */
+ snd_soc_update_bits(codec, WM8753_INTEN, WM8753_GPIO4IEN_MASK,
+ WM8753_GPIO4IEN_EN);
+
+ return IRQ_HANDLED;
+}
+
+int wm8753_headphone_detect(struct snd_soc_codec *codec,
+ struct snd_soc_jack *jack, enum snd_jack_types type,
+ unsigned int debounce_time_hp)
+{
+ struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+
+ wm8753->headset_jack = jack;
+ wm8753->debounce_time_hp = debounce_time_hp;
+
+ if (wm8753->irq && (type & SND_JACK_HEADPHONE)) {
+ /* Configure GPIO2 pin to generate the interrupt */
+ snd_soc_update_bits(codec, WM8753_GPIO2, WM8753_GP2M_MASK,
+ WM8753_GP2M_INT);
+ /* Active low Interrupt */
+ snd_soc_update_bits(codec, WM8753_GPIO1, WM8753_INTCON_MASK,
+ WM8753_INTCON_AL);
+ /* interupt when low i.e Headphone connected */
+ snd_soc_update_bits(codec, WM8753_INTPOL, WM8753_GPIO4IPOL_MASK,
+ WM8753_GPIO4IPOL_LOW);
+ /* GPIO4 interrupt enable */
+ snd_soc_update_bits(codec, WM8753_INTEN, WM8753_GPIO4IEN_MASK,
+ WM8753_GPIO4IEN_EN);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm8753_headphone_detect);
+
static int wm8753_probe(struct snd_soc_codec *codec)
{
struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
@@ -1443,6 +1518,19 @@ static int wm8753_probe(struct snd_soc_codec *codec)
return ret;
}
+ if (wm8753->irq) {
+ /* register an audio interrupt */
+ ret = request_threaded_irq(wm8753->irq, NULL,
+ wm8753_jack_handler,
+ IRQF_TRIGGER_FALLING,
+ "wm8753", codec);
+
+ if (ret) {
+ dev_err(codec->dev, "Failed to request IRQ: %d\n", ret);
+ return ret;
+ }
+ }
+
wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
wm8753->dai_func = 0;
@@ -1540,6 +1628,7 @@ static __devinit int wm8753_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, wm8753);
wm8753->control_type = SND_SOC_I2C;
+ wm8753->irq = i2c->irq;
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai));
diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h
index 94edac144bcb..550af291d3fb 100644
--- a/sound/soc/codecs/wm8753.h
+++ b/sound/soc/codecs/wm8753.h
@@ -112,7 +112,28 @@
#define WM8753_VXCLK_DIV_8 (3 << 6)
#define WM8753_VXCLK_DIV_16 (4 << 6)
-#define WM8753_DAI_HIFI 0
-#define WM8753_DAI_VOICE 1
+/* GPIO Control 2 */
+#define WM8753_GP2M_MASK (7 << 3)
+#define WM8753_GP2M_INT (3 << 3)
+/* GPIO Control 1 */
+#define WM8753_INTCON_MASK (3 << 7)
+#define WM8753_INTCON_AL (3 << 7)
+
+/* Interrupt Polarity*/
+#define WM8753_GPIO4IPOL_MASK (1 << 4)
+#define WM8753_GPIO4IPOL_LOW (1 << 4)
+#define WM8753_GPIO4IPOL_HIGH (0 << 4)
+
+/* Interrupt Enable*/
+#define WM8753_GPIO4IEN_MASK (1 << 4)
+#define WM8753_GPIO4IEN_EN (1 << 4)
+#define WM8753_GPIO4IEN_DIS (0 << 4)
+
+#define WM8753_DAI_HIFI 0
+#define WM8753_DAI_VOICE 1
+
+int wm8753_headphone_detect(struct snd_soc_codec *codec,
+ struct snd_soc_jack *jack, enum snd_jack_types type,
+ unsigned int debounce_time_hp);
#endif