public inbox for linux-omap@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCHv2 6/7] ASoC: TWL6030: Enable audio interrupt
@ 2009-09-26  2:03 Lopez Cruz, Misael
  2009-09-28 13:34 ` Mark Brown
  0 siblings, 1 reply; 2+ messages in thread
From: Lopez Cruz, Misael @ 2009-09-26  2:03 UTC (permalink / raw)
  To: alsa-devel@alsa-project.org, linux-omap@vger.kernel.org; +Cc: Mark Brown

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 <x0052729@ti.com>
---
 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

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCHv2 6/7] ASoC: TWL6030: Enable audio interrupt
  2009-09-26  2:03 [PATCHv2 6/7] ASoC: TWL6030: Enable audio interrupt Lopez Cruz, Misael
@ 2009-09-28 13:34 ` Mark Brown
  0 siblings, 0 replies; 2+ messages in thread
From: Mark Brown @ 2009-09-28 13:34 UTC (permalink / raw)
  To: Lopez Cruz, Misael
  Cc: alsa-devel@alsa-project.org, linux-omap@vger.kernel.org

On Fri, Sep 25, 2009 at 09:03:41PM -0500, Lopez Cruz, Misael wrote:

> +/* 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;
> +}

You should use request_threaded_irq() here and have the body of the work
function in the threaded IRQ handler.  It essentially does the same
thing that you've open coded here but with less code and is a bit more
friendly to the IRQ infrastructure since it lets it know what's going
on more explicitly.

> @@ -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;
> +	}
> +

Is it worth making this optional?  I wouldn't like to rely on boards
remembering to wire up the interrupt line.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2009-09-28 13:34 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-09-26  2:03 [PATCHv2 6/7] ASoC: TWL6030: Enable audio interrupt Lopez Cruz, Misael
2009-09-28 13:34 ` Mark Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox