]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00236020-2 wm8962: hp/speaker switching afer resume
authorGary Zhang <b13634@freescale.com>
Tue, 11 Dec 2012 05:48:05 +0000 (13:48 +0800)
committerLothar Waßmann <LW@KARO-electronics.de>
Fri, 24 May 2013 06:35:47 +0000 (08:35 +0200)
implement headphone and speaker automatically switch
even if headphone is plugin/out during suspend

Signed-off-by: Gary Zhang <b13634@freescale.com>
sound/soc/imx/imx-wm8962.c

index a224518e305a5f6b97de87f779dfda0bdb509c73..9abc4a7424dd0ef1fbb4e8d71a52e3bb8fdc8b3b 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/fsl_devices.h>
 #include <linux/slab.h>
 #include <linux/clk.h>
+#include <linux/kthread.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -57,6 +58,10 @@ unsigned int sample_format = SNDRV_PCM_FMTBIT_S16_LE;
 static struct imx_priv card_priv;
 static struct snd_soc_card snd_soc_card_imx;
 static struct snd_soc_codec *gcodec;
+static int suspend_hp_flag;
+static int suspend_mic_flag;
+static int hp_irq;
+static int mic_irq;
 
 static int imx_hifi_startup(struct snd_pcm_substream *substream)
 {
@@ -210,6 +215,11 @@ static void headphone_detect_handler(struct work_struct *wor)
        kobject_uevent_env(&pdev->dev.kobj, KOBJ_CHANGE, envp);
        kfree(buf);
 
+       if ((suspend_hp_flag == 1) && (hp_irq == 0)) {
+               suspend_hp_flag = 0;
+               return;
+       }
+       hp_irq = 0;
        enable_irq(priv->hp_irq);
 
        return;
@@ -219,6 +229,10 @@ static DECLARE_DELAYED_WORK(hp_event, headphone_detect_handler);
 
 static irqreturn_t imx_headphone_detect_handler(int irq, void *data)
 {
+       if (suspend_hp_flag == 1)
+               return IRQ_HANDLED;
+
+       hp_irq = 1;
        disable_irq_nosync(irq);
        schedule_delayed_work(&hp_event, msecs_to_jiffies(200));
        return IRQ_HANDLED;
@@ -280,6 +294,11 @@ static void amic_detect_handler(struct work_struct *work)
        kobject_uevent_env(&pdev->dev.kobj, KOBJ_CHANGE, envp);
        kfree(buf);
 
+       if ((suspend_mic_flag == 1) && (mic_irq == 0)) {
+               suspend_mic_flag = 0;
+               return;
+       }
+       mic_irq = 0;
        enable_irq(priv->amic_irq);
 }
 
@@ -287,6 +306,10 @@ static DECLARE_DELAYED_WORK(amic_event, amic_detect_handler);
 
 static irqreturn_t imx_amic_detect_handler(int irq, void *data)
 {
+       if (suspend_mic_flag == 1)
+               return IRQ_HANDLED;
+
+       mic_irq = 1;
        disable_irq_nosync(irq);
        schedule_delayed_work(&amic_event, msecs_to_jiffies(200));
        return IRQ_HANDLED;
@@ -311,6 +334,32 @@ static ssize_t show_amic(struct device_driver *dev, char *buf)
 
 static DRIVER_ATTR(amic, S_IRUGO | S_IWUSR, show_amic, NULL);
 
+static DECLARE_DELAYED_WORK(resume_hp_event, headphone_detect_handler);
+static DECLARE_DELAYED_WORK(resume_mic_event, amic_detect_handler);
+
+
+int imx_hifi_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct imx_priv *priv = &card_priv;
+       struct platform_device *pdev = priv->pdev;
+       struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
+
+       if (SNDRV_PCM_TRIGGER_SUSPEND == cmd) {
+               suspend_hp_flag = 1;
+               suspend_mic_flag = 1;
+       }
+       if (SNDRV_PCM_TRIGGER_RESUME == cmd) {
+               if (plat->hp_gpio != -1)
+                       schedule_delayed_work(&resume_hp_event,
+                                                       msecs_to_jiffies(200));
+               if (plat->mic_gpio != -1)
+                       schedule_delayed_work(&resume_mic_event,
+                                                       msecs_to_jiffies(200));
+       }
+
+       return 0;
+}
+
 static int imx_wm8962_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
@@ -331,8 +380,6 @@ static int imx_wm8962_init(struct snd_soc_pcm_runtime *rtd)
        snd_soc_dapm_enable_pin(&codec->dapm, "Headphone Jack");
        snd_soc_dapm_enable_pin(&codec->dapm, "AMIC");
 
-       snd_soc_dapm_sync(&codec->dapm);
-
        if (plat->hp_gpio != -1) {
                priv->hp_irq = gpio_to_irq(plat->hp_gpio);
 
@@ -389,6 +436,8 @@ static int imx_wm8962_init(struct snd_soc_pcm_runtime *rtd)
        } else if (!snd_soc_dapm_get_pin_status(&codec->dapm, "DMICDAT"))
                snd_soc_dapm_nc_pin(&codec->dapm, "DMIC");
 
+       snd_soc_dapm_sync(&codec->dapm);
+
        return 0;
 }
 
@@ -396,6 +445,7 @@ static struct snd_soc_ops imx_hifi_ops = {
        .startup = imx_hifi_startup,
        .shutdown = imx_hifi_shutdown,
        .hw_params = imx_hifi_hw_params,
+       .trigger = imx_hifi_trigger,
 };
 
 static struct snd_soc_dai_link imx_dai[] = {