summaryrefslogtreecommitdiff
path: root/sound/soc/codecs
diff options
context:
space:
mode:
authorNikesh Oswal <noswal@nvidia.com>2011-09-30 17:27:08 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:49:19 -0800
commit7510bbfe31a983590f61c381d2a3be13b4a30d49 (patch)
tree7785a1ed19b412dff7d06c220ebd061f28ff29fd /sound/soc/codecs
parent4762c4d4a011fe734d39be9b2a83596ee1ee1553 (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> Rebase-Id: Rf725fad369dbbe4d5f6eaa7b667170a127fa0a08
Diffstat (limited to 'sound/soc/codecs')
-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 ac65a2d36408..e7e5bfe10fa0 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] = {
@@ -1908,6 +1911,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");
@@ -1933,6 +1937,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
@@ -1954,6 +1978,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);
@@ -1990,6 +2076,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",
@@ -2068,6 +2166,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 be89a4f4aab8..cf4b04d2d07a 100644
--- a/sound/soc/codecs/max98088.h
+++ b/sound/soc/codecs/max98088.h
@@ -194,6 +194,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
@@ -203,4 +222,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