NAUDINT interrupt line is provided by the TWL6030 codec to signal
externally events like headset plug/unplug, hook, power-up sequence
completion, etc.

Signed-off-by: Misael Lopez Cruz <[email protected]>
---
 sound/soc/codecs/twl6030.c |   78 +++++++++++++++++++++++++++++++++++++++++++-
 sound/soc/codecs/twl6030.h |   10 ++++++
 2 files changed, 87 insertions(+), 1 deletions(-)

diff --git a/sound/soc/codecs/twl6030.c b/sound/soc/codecs/twl6030.c
index 032619d..5cf2099 100644
--- a/sound/soc/codecs/twl6030.c
+++ b/sound/soc/codecs/twl6030.c
@@ -47,6 +47,7 @@ struct twl6030_data {
        struct snd_soc_codec codec;
        int codec_powered;
        unsigned int sysclk;
+       struct work_struct audint_work;
 };
 
 /*
@@ -329,6 +330,58 @@ static int headset_power_mode(struct snd_soc_codec *codec, 
int high_perf)
        return 0;
 }
 
+/* audio interrupt handler */
+irqreturn_t twl6030_naudint_handler(int irq, void *data)
+{
+       struct snd_soc_codec *codec = data;
+       struct twl6030_data *priv = codec->private_data;
+
+       schedule_work(&priv->audint_work);
+
+       /* disable audint irq to let workqueue to execute */
+       disable_irq_nosync(irq);
+
+       return IRQ_HANDLED;
+}
+
+void twl6030_naudint_work(struct work_struct *work)
+{
+       struct twl_codec_data *twl_codec;
+       struct snd_soc_codec *codec;
+       struct twl6030_data *priv;
+       u8 intid;
+
+       priv = container_of(work, struct twl6030_data, audint_work);
+       codec = &priv->codec;
+       twl_codec = codec->control_data;
+
+       twl_i2c_read_u8(TWL6030_MODULE_AUDIO, &intid, TWL6030_REG_INTID);
+
+       switch (intid) {
+       case TWL6030_THINT:
+               dev_alert(codec->dev, "die temp over-limit detection\n");
+               break;
+       case TWL6030_PLUGINT:
+       case TWL6030_UNPLUGINT:
+       case TWL6030_HOOKINT:
+               break;
+       case TWL6030_HFINT:
+               dev_alert(codec->dev, "hf drivers over current detection\n");
+               break;
+       case TWL6030_VIBINT:
+               dev_alert(codec->dev, "vib drivers over current detection\n");
+               break;
+       case TWL6030_READYINT:
+               dev_alert(codec->dev, "codec is ready\n");
+               break;
+       default:
+               dev_err(codec->dev, "unknown audio interrupt %d\n", intid);
+               break;
+       }
+
+       enable_irq(twl_codec->naudint_irq);
+}
+
 /*
  * MICATT volume control:
  * from -6 to 0 dB in 6 dB steps
@@ -610,6 +663,7 @@ static int twl6030_set_bias_level(struct snd_soc_codec 
*codec,
                priv->codec_powered = 0;
                break;
        }
+
        codec->bias_level = level;
 
        return 0;
@@ -954,8 +1008,15 @@ static int __devinit twl6030_codec_probe(struct 
platform_device *pdev)
        struct twl6030_data *priv;
        struct snd_soc_codec *codec;
        int audpwron_gpio = twl_codec->audpwron_gpio;
+       int naudint_irq = twl_codec->naudint_irq;
        int ret = 0;
 
+       /* prerequisites */
+       if (!naudint_irq) {
+               dev_err(&pdev->dev, "no audio interrupt irq supplied\n");
+               return -EINVAL;
+       }
+
        priv = kzalloc(sizeof(struct twl6030_data), GFP_KERNEL);
        if (priv == NULL)
                return -ENOMEM;
@@ -998,6 +1059,17 @@ static int __devinit twl6030_codec_probe(struct 
platform_device *pdev)
                priv->codec_powered = 0;
        }
 
+       /* audio interrupt */
+       INIT_WORK(&priv->audint_work, twl6030_naudint_work);
+
+       ret = request_irq(naudint_irq,
+                       twl6030_naudint_handler,
+                       IRQF_TRIGGER_LOW | IRQF_DISABLED,
+                       "twl6030-codec",
+                       codec);
+       if (ret)
+               goto gpio2_err;
+
        /* init vio registers */
        twl6030_init_vio_regs(codec);
 
@@ -1006,7 +1078,7 @@ static int __devinit twl6030_codec_probe(struct 
platform_device *pdev)
 
        ret = snd_soc_register_codec(codec);
        if (ret)
-               goto gpio2_err;
+               goto reg_err;
 
        twl6030_codec = codec;
 
@@ -1019,6 +1091,8 @@ static int __devinit twl6030_codec_probe(struct 
platform_device *pdev)
 dai_err:
        snd_soc_unregister_codec(codec);
        twl6030_codec = NULL;
+reg_err:
+       free_irq(naudint_irq, twl_codec);
 gpio2_err:
        if (gpio_is_valid(audpwron_gpio))
                gpio_free(audpwron_gpio);
@@ -1036,6 +1110,8 @@ static int __devexit twl6030_codec_remove(struct 
platform_device *pdev)
        if (gpio_is_valid(twl_codec->audpwron_gpio))
                gpio_free(twl_codec->audpwron_gpio);
 
+       free_irq(twl_codec->naudint_irq, twl6030_codec);
+
        snd_soc_unregister_dai(&twl6030_dai);
        snd_soc_unregister_codec(twl6030_codec);
 
diff --git a/sound/soc/codecs/twl6030.h b/sound/soc/codecs/twl6030.h
index 15d3e1b..8a106f2 100644
--- a/sound/soc/codecs/twl6030.h
+++ b/sound/soc/codecs/twl6030.h
@@ -67,6 +67,16 @@
 #define TWL6030_VIOREGNUM              18
 #define TWL6030_VDDREGNUM              21
 
+/* INTID (0x03) fields */
+
+#define TWL6030_THINT                  0x01
+#define TWL6030_PLUGINT                        0x02
+#define TWL6030_UNPLUGINT              0x04
+#define TWL6030_HOOKINT                        0x08
+#define TWL6030_HFINT                  0x10
+#define TWL6030_VIBINT                 0x20
+#define TWL6030_READYINT               0x40
+
 /* NCPCTL (0x05) fields */
 
 #define TWL6030_NCPENA                 0x01
-- 
1.5.4.3
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to