diff options
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/codecs/max98088.c | 99 | ||||
-rw-r--r-- | sound/soc/codecs/max98088.h | 22 |
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 |