[alsa-devel] [PATCH 13/19] ASoC: mrst_machine: add jack detection support
Lu Guanqun
guanqun.lu at intel.com
Wed May 4 15:45:59 CEST 2011
Signed-off-by: Lu Guanqun <guanqun.lu at intel.com>
---
sound/soc/mid-x86/mrst_machine.c | 142 ++++++++++++++++++++++++++++++++++++++
1 files changed, 142 insertions(+), 0 deletions(-)
diff --git a/sound/soc/mid-x86/mrst_machine.c b/sound/soc/mid-x86/mrst_machine.c
index d70b26e..96df9a1 100644
--- a/sound/soc/mid-x86/mrst_machine.c
+++ b/sound/soc/mid-x86/mrst_machine.c
@@ -31,10 +31,83 @@
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/gpio.h>
+#include <linux/list.h>
#include <linux/io.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <sound/jack.h>
+#include <../codecs/upd9976.h>
+
+/* Jack Detection */
+static struct snd_soc_jack mrst_jack;
+struct mrst_jack_context {
+ struct list_head head;
+ spinlock_t lock;
+ void __iomem *interrupt_base;
+};
+
+struct mrst_jack_node {
+ struct list_head list;
+ u8 interrupt_status;
+};
+
+static struct snd_soc_jack_pin mrst_jack_pins = {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADSET,
+};
+
+static irqreturn_t mrst_jack_intr_handler(int irq, void *dev)
+{
+ struct mrst_jack_context *context = dev;
+ u8 interrupt_status;
+ struct mrst_jack_node *node;
+ unsigned long flags;
+
+ memcpy_fromio(&interrupt_status,
+ context->interrupt_base,
+ sizeof(u8));
+
+ /* check if it's valid */
+ if (!(interrupt_status & 0xf))
+ return IRQ_NONE;
+
+ node = kmalloc(sizeof(*node), GFP_ATOMIC);
+ if (!node)
+ return IRQ_NONE;
+
+ INIT_LIST_HEAD(&node->list);
+ node->interrupt_status = interrupt_status;
+
+ spin_lock_irqsave(&context->lock, flags);
+ list_add_tail(&node->list, &context->head);
+ spin_unlock_irqrestore(&context->lock, flags);
+
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t mrst_jack_detection(int irq, void *data)
+{
+ struct mrst_jack_context *context = data;
+ u8 interrupt_status;
+ unsigned long flags;
+ struct mrst_jack_node *node;
+
+ spin_lock_irqsave(&context->lock, flags);
+ if (list_empty(&context->head)) {
+ spin_unlock_irqrestore(&context->lock, flags);
+ return IRQ_HANDLED;
+ }
+ node = list_first_entry(&context->head, struct mrst_jack_node, list);
+ interrupt_status = node->interrupt_status;
+ list_del(&node->list);
+ kfree(node);
+ spin_unlock_irqrestore(&context->lock, flags);
+
+ upd9976_jack_detection(&mrst_jack, interrupt_status);
+
+ return IRQ_HANDLED;
+}
static const struct snd_kcontrol_new mrst_snd_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone"),
@@ -116,8 +189,22 @@ static int mrst_audio_init(struct snd_soc_pcm_runtime *runtime)
snd_soc_dapm_disable_pin(dapm, "Headset MIC");
snd_soc_dapm_enable_pin(dapm, "Internal MIC");
+ snd_soc_dapm_force_enable_pin(dapm, "MIC2 Bias");
+
snd_soc_dapm_sync(dapm);
+ ret = snd_soc_jack_new(codec, "Intel(R) MID Audio Jack",
+ (SND_JACK_HEADSET |
+ SND_JACK_BTN_0 |
+ SND_JACK_BTN_1),
+ &mrst_jack);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_jack_add_pins(&mrst_jack, 1, &mrst_jack_pins);
+ if (ret)
+ return ret;
+
return 0;
}
@@ -159,6 +246,9 @@ static struct snd_soc_card snd_soc_card_mrst = {
static int __devinit snd_mrst_audio_probe(struct platform_device *pdev)
{
+ int irq;
+ struct resource *irq_mem;
+ struct mrst_jack_context *jack_context = NULL;
int ret;
if (pdev->dev.platform_data) {
@@ -168,14 +258,59 @@ static int __devinit snd_mrst_audio_probe(struct platform_device *pdev)
mrst_gpio_amp = 0;
}
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ ret = irq;
+ goto fail_get_irq;
+ }
+
+ jack_context = kzalloc(sizeof(*jack_context), GFP_KERNEL);
+ if (!jack_context) {
+ ret = -ENOMEM;
+ goto fail_get_irq;
+ }
+ spin_lock_init(&jack_context->lock);
+ INIT_LIST_HEAD(&jack_context->head);
+
+ irq_mem = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "IRQ_BASE");
+ if (!irq_mem) {
+ ret = -ENODEV;
+ goto fail_alloc_context;
+ }
+
+ jack_context->interrupt_base = ioremap_nocache(irq_mem->start,
+ resource_size(irq_mem));
+ if (!jack_context->interrupt_base) {
+ ret = -ENOMEM;
+ goto fail_alloc_context;
+ }
+
+ ret = request_threaded_irq(irq,
+ mrst_jack_intr_handler,
+ mrst_jack_detection,
+ IRQF_SHARED,
+ pdev->dev.driver->name,
+ jack_context);
+ if (ret)
+ goto fail_request_irq;
+
snd_soc_card_mrst.dev = &pdev->dev;
ret = snd_soc_register_card(&snd_soc_card_mrst);
if (ret)
goto fail_register_card;
+ platform_set_drvdata(pdev, jack_context);
+
return 0;
fail_register_card:
+ free_irq(irq, jack_context);
+fail_request_irq:
+ iounmap(jack_context->interrupt_base);
+fail_alloc_context:
+ kfree(jack_context);
+fail_get_irq:
if (mrst_gpio_amp)
gpio_free(mrst_gpio_amp);
return ret;
@@ -183,9 +318,16 @@ fail_register_card:
static int __devexit snd_mrst_audio_remove(struct platform_device *pdev)
{
+ struct mrst_jack_context *jack_context = platform_get_drvdata(pdev);
+ int irq = platform_get_irq(pdev, 0);
+
+ free_irq(irq, jack_context);
+ iounmap(jack_context->interrupt_base);
+ kfree(jack_context);
if (mrst_gpio_amp)
gpio_free(mrst_gpio_amp);
snd_soc_unregister_card(&snd_soc_card_mrst);
+
return 0;
}
More information about the Alsa-devel
mailing list