diff options
author | Nikesh Oswal <noswal@nvidia.com> | 2011-10-10 17:40:54 +0530 |
---|---|---|
committer | Varun Colbert <vcolbert@nvidia.com> | 2011-10-11 11:43:15 -0700 |
commit | fa4c367b3562a601d2720587def8835cd9a24160 (patch) | |
tree | bb386c84733062c860fedc4d3d4342c535e2192f /sound | |
parent | 1819a373c153beb2ee456d89550dd50dcc738789 (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.c | 89 | ||||
-rw-r--r-- | sound/soc/codecs/wm8753.h | 25 |
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 |