summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorNikesh Oswal <noswal@nvidia.com>2011-09-30 17:27:08 +0530
committerVarun Colbert <vcolbert@nvidia.com>2011-10-12 13:45:35 -0700
commit1a404786317bc06e6bd6cef5852fde235ef657b0 (patch)
tree4fff25dbb3f956104067b2703f5486913da3729b /sound
parent24597f69a28aef0cfdae0d3c0acb980c9dff2a26 (diff)
asoc: max98088: add headset/headphone detection code
Bug: 862023 Change-Id: Ieb9247cef5feecf3e241d8980f9c4376cadf2965 Signed-off-by: Nikesh Oswal <noswal@nvidia.com> Reviewed-on: http://git-master/r/55465 Reviewed-by: Sumit Bhattacharya <sumitb@nvidia.com> Reviewed-by: Scott Peterson <speterson@nvidia.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/max98088.c99
-rw-r--r--sound/soc/codecs/max98088.h22
2 files changed, 121 insertions, 0 deletions
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index bd0517cb7980..93fca9076931 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -25,6 +25,7 @@
#include <linux/slab.h>
#include <asm/div64.h>
#include <sound/max98088.h>
+#include <sound/jack.h>
#include "max98088.h"
enum max98088_type {
@@ -54,6 +55,8 @@ struct max98088_priv {
unsigned int mic1pre;
unsigned int mic2pre;
unsigned int extmic_mode;
+ int irq;
+ struct snd_soc_jack *headset_jack;
};
static const u8 max98088_reg[M98088_REG_CNT] = {
@@ -1898,6 +1901,7 @@ static void max98088_handle_pdata(struct snd_soc_codec *codec)
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
struct max98088_pdata *pdata = max98088->pdata;
u8 regval = 0;
+ unsigned int debounce_time;
if (!pdata) {
dev_dbg(codec->dev, "No platform data\n");
@@ -1923,6 +1927,26 @@ static void max98088_handle_pdata(struct snd_soc_codec *codec)
/* Configure equalizers */
if (pdata->eq_cfgcnt)
max98088_handle_eq_pdata(codec);
+
+ /* Configure the debounce time */
+ if (max98088->irq) {
+ switch (pdata->debounce_time_ms) {
+ case 25:
+ debounce_time = M98088_JDEB_25;
+ break;
+ case 50:
+ debounce_time = M98088_JDEB_50;
+ break;
+ case 100:
+ debounce_time = M98088_JDEB_100;
+ break;
+ case 200:
+ default:
+ debounce_time = M98088_JDEB_200;
+ }
+ snd_soc_update_bits(codec, M98088_REG_4B_CFG_JACKDET,
+ M98088_JDEB, debounce_time);
+ }
}
#ifdef CONFIG_PM
@@ -1944,6 +1968,68 @@ static int max98088_resume(struct snd_soc_codec *codec)
#define max98088_resume NULL
#endif
+int max98088_report_jack(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ unsigned int value;
+ int jack_report = 0;
+
+ /* Read the Jack Status Register*/
+ value = snd_soc_read(codec, M98088_REG_02_JACK_STAUS);
+
+ if ((value & M98088_JKSNS_7) == 0)
+ jack_report |= SND_JACK_HEADPHONE;
+ if (value & M98088_JKSNS_6)
+ jack_report |= SND_JACK_MICROPHONE;
+
+ snd_soc_jack_report(max98088->headset_jack,
+ jack_report, SND_JACK_HEADSET);
+
+ return 0;
+}
+
+static irqreturn_t max98088_jack_handler(int irq, void *data)
+{
+ struct snd_soc_codec *codec = data;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+
+ /*clear the interrupt by reading the status register */
+ snd_soc_read(codec, M98088_REG_00_IRQ_STATUS);
+ max98088_report_jack(codec);
+
+ return IRQ_HANDLED;
+}
+
+int max98088_headset_detect(struct snd_soc_codec *codec,
+ struct snd_soc_jack *jack, enum snd_jack_types type)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ max98088->headset_jack = jack;
+
+ max98088_report_jack(codec);
+
+ if (max98088->irq) {
+ if (type & SND_JACK_HEADSET) {
+ /* headphone + microphone detection */
+ snd_soc_update_bits(codec, M98088_REG_4E_BIAS_CNTL,
+ M98088_JDWK, 0);
+ } else {
+ /* headphone detection only*/
+ snd_soc_update_bits(codec, M98088_REG_4E_BIAS_CNTL,
+ M98088_JDWK, 1);
+ }
+ /* Enable the Jack Detection Circuitry */
+ snd_soc_update_bits(codec, M98088_REG_4B_CFG_JACKDET,
+ M98088_JDETEN, M98088_JDETEN);
+ /*Enable the jack detection interrupt*/
+ snd_soc_update_bits(codec, M98088_REG_0F_IRQ_ENABLE,
+ M98088_IJDET, M98088_IJDET);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(max98088_headset_detect);
+
static int max98088_probe(struct snd_soc_codec *codec)
{
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
@@ -1980,6 +2066,18 @@ static int max98088_probe(struct snd_soc_codec *codec)
max98088->mic1pre = 0;
max98088->mic2pre = 0;
+ if (max98088->irq) {
+ /* register an audio interrupt */
+ ret = request_threaded_irq(max98088->irq, NULL,
+ max98088_jack_handler,
+ IRQF_TRIGGER_FALLING,
+ "max98088", codec);
+ if (ret) {
+ dev_err(codec->dev, "Failed to request IRQ: %d\n", ret);
+ goto err_access;
+ }
+ }
+
ret = snd_soc_read(codec, M98088_REG_FF_REV_ID);
if (ret < 0) {
dev_err(codec->dev, "Failed to read device revision: %d\n",
@@ -2053,6 +2151,7 @@ static int max98088_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, max98088);
max98088->control_data = i2c;
max98088->pdata = i2c->dev.platform_data;
+ max98088->irq = i2c->irq;
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_max98088, &max98088_dai[0], 2);
diff --git a/sound/soc/codecs/max98088.h b/sound/soc/codecs/max98088.h
index 56554c797fef..3ac3fe3a5fb8 100644
--- a/sound/soc/codecs/max98088.h
+++ b/sound/soc/codecs/max98088.h
@@ -181,6 +181,25 @@
#define M98088_PWRSV8K (1<<1)
#define M98088_PWRSV (1<<0)
+/* M98088_REG_4E_BIAS_CNTL */
+ #define M98088_JDWK (1<<1)
+
+/* M98088_REG_4B_CFG_JACKDET */
+ #define M98088_JDETEN (1<<7)
+ #define M98088_JDEB (3<<0)
+ #define M98088_JDEB_25 (0<<0)
+ #define M98088_JDEB_50 (1<<0)
+ #define M98088_JDEB_100 (2<<0)
+ #define M98088_JDEB_200 (3<<0)
+
+
+/* M98088_REG_0F_IRQ_ENABLE */
+ #define M98088_IJDET (1<<1)
+
+/* M98088_REG_02_JACK_STAUS */
+ #define M98088_JKSNS_7 (1<<7)
+ #define M98088_JKSNS_6 (1<<6)
+
/* Line inputs */
#define LINE_INA 0
#define LINE_INB 1
@@ -190,4 +209,7 @@
#define M98088_BYTE1(w) ((w >> 8) & 0xff)
#define M98088_BYTE0(w) (w & 0xff)
+int max98088_headset_detect(struct snd_soc_codec *codec,
+ struct snd_soc_jack *jack, enum snd_jack_types type);
+
#endif