]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00236910 wm8962: use alsa jack mechanism to handle pin detection
authorGary Zhang <b13634@freescale.com>
Tue, 18 Dec 2012 07:15:25 +0000 (15:15 +0800)
committerLothar Waßmann <LW@KARO-electronics.de>
Fri, 24 May 2013 06:35:48 +0000 (08:35 +0200)
use alsa jack mechanism to handle pin detection

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

index 9abc4a7424dd0ef1fbb4e8d71a52e3bb8fdc8b3b..e7b60df131809e280e9529bcfcccaff2b6e572e0 100644 (file)
@@ -58,10 +58,34 @@ 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 struct snd_soc_jack imx_hp_jack;
+static struct snd_soc_jack_pin imx_hp_jack_pins[] = {
+       {
+               .pin = "Ext Spk",
+               .mask = SND_JACK_HEADPHONE,
+       },
+};
+static struct snd_soc_jack_gpio imx_hp_jack_gpio = {
+       .name = "headphone detect",
+       .report = SND_JACK_HEADPHONE,
+       .debounce_time = 150,
+       .invert = 0,
+};
+
+static struct snd_soc_jack imx_mic_jack;
+static struct snd_soc_jack_pin imx_mic_jack_pins[] = {
+       {
+               .pin = "DMIC",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+static struct snd_soc_jack_gpio imx_mic_jack_gpio = {
+       .name = "micphone detect",
+       .report = SND_JACK_MICROPHONE,
+       .debounce_time = 150,
+       .invert = 0,
+};
 
 static int imx_hifi_startup(struct snd_pcm_substream *substream)
 {
@@ -150,35 +174,50 @@ static int imx_hifi_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static const struct snd_kcontrol_new controls[] = {
-       SOC_DAPM_PIN_SWITCH("Ext Spk"),
-};
+static void imx_resume_event(struct work_struct *wor)
+{
+       struct imx_priv *priv = &card_priv;
+       struct platform_device *pdev = priv->pdev;
+       struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
+       struct snd_soc_jack *jack;
+       int enable;
+       int report;
 
-/* imx card dapm widgets */
-static const struct snd_soc_dapm_widget imx_dapm_widgets[] = {
-       SND_SOC_DAPM_HP("Headphone Jack", NULL),
-       SND_SOC_DAPM_SPK("Ext Spk", NULL),
-       SND_SOC_DAPM_MIC("AMIC", NULL),
-       SND_SOC_DAPM_MIC("DMIC", NULL),
-};
+       if (plat->hp_gpio != -1) {
+               jack = imx_hp_jack_gpio.jack;
 
-/* imx machine connections to the codec pins */
-static const struct snd_soc_dapm_route audio_map[] = {
-       { "Headphone Jack", NULL, "HPOUTL" },
-       { "Headphone Jack", NULL, "HPOUTR" },
+               enable = gpio_get_value_cansleep(imx_hp_jack_gpio.gpio);
+               if (imx_hp_jack_gpio.invert)
+                       enable = !enable;
 
-       { "Ext Spk", NULL, "SPKOUTL" },
-       { "Ext Spk", NULL, "SPKOUTR" },
+               if (enable)
+                       report = imx_hp_jack_gpio.report;
+               else
+                       report = 0;
 
-       { "MICBIAS", NULL, "AMIC" },
-       { "IN3R", NULL, "MICBIAS" },
+               snd_soc_jack_report(jack, report, imx_hp_jack_gpio.report);
+       }
 
-       { "DMIC", NULL, "MICBIAS" },
-       { "DMICDAT", NULL, "DMIC" },
+       if (plat->mic_gpio != -1) {
+               jack = imx_mic_jack_gpio.jack;
 
-};
+               enable = gpio_get_value_cansleep(imx_mic_jack_gpio.gpio);
+               if (imx_mic_jack_gpio.invert)
+                       enable = !enable;
+
+               if (enable)
+                       report = imx_mic_jack_gpio.report;
+               else
+                       report = 0;
+
+               snd_soc_jack_report(jack, report, imx_mic_jack_gpio.report);
+       }
+
+       return;
+}
 
-static void headphone_detect_handler(struct work_struct *wor)
+static int imx_event_hp(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol, int event)
 {
        struct imx_priv *priv = &card_priv;
        struct platform_device *pdev = priv->pdev;
@@ -186,23 +225,12 @@ static void headphone_detect_handler(struct work_struct *wor)
        char *envp[3];
        char *buf;
 
-       /*sysfs_notify(&pdev->dev.kobj, NULL, "headphone");*/
-       priv->hp_status = gpio_get_value(plat->hp_gpio);
-
-       /* if headphone is inserted, disable speaker */
-       if (priv->hp_status != plat->hp_active_low)
-               snd_soc_dapm_nc_pin(&gcodec->dapm, "Ext Spk");
-       else
-               snd_soc_dapm_enable_pin(&gcodec->dapm, "Ext Spk");
-
-       snd_soc_dapm_sync(&gcodec->dapm);
-
-       /* setup a message for userspace headphone in */
        buf = kmalloc(32, GFP_ATOMIC);
        if (!buf) {
                pr_err("%s kmalloc failed\n", __func__);
-               return;
+               return -ENOMEM;
        }
+       priv->hp_status = gpio_get_value(plat->hp_gpio);
 
        if (priv->hp_status != plat->hp_active_low)
                snprintf(buf, 32, "STATE=%d", 2);
@@ -215,49 +243,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;
-}
-
-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;
-}
-
-static ssize_t show_headphone(struct device_driver *dev, char *buf)
-{
-       struct imx_priv *priv = &card_priv;
-       struct platform_device *pdev = priv->pdev;
-       struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
-
-       /* determine whether hp is plugged in */
-       priv->hp_status = gpio_get_value(plat->hp_gpio);
-
-       if (priv->hp_status != plat->hp_active_low)
-               strcpy(buf, "headphone\n");
-       else
-               strcpy(buf, "speaker\n");
-
-       return strlen(buf);
+       return 0;
 }
 
-static DRIVER_ATTR(headphone, S_IRUGO | S_IWUSR, show_headphone, NULL);
-
-static void amic_detect_handler(struct work_struct *work)
+static int imx_event_mic(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol, int event)
 {
        struct imx_priv *priv = &card_priv;
        struct platform_device *pdev = priv->pdev;
@@ -265,22 +255,12 @@ static void amic_detect_handler(struct work_struct *work)
        char *envp[3];
        char *buf;
 
-       /* sysfs_notify(&pdev->dev.kobj, NULL, "amic"); */
        priv->amic_status = gpio_get_value(plat->mic_gpio);
 
-       /* if amic is inserted, disable dmic */
-       if (priv->amic_status != plat->mic_active_low)
-               snd_soc_dapm_nc_pin(&gcodec->dapm, "DMIC");
-       else
-               snd_soc_dapm_enable_pin(&gcodec->dapm, "DMIC");
-
-       snd_soc_dapm_sync(&gcodec->dapm);
-
-       /* setup a message for userspace headphone in */
        buf = kmalloc(32, GFP_ATOMIC);
        if (!buf) {
                pr_err("%s kmalloc failed\n", __func__);
-               return;
+               return -ENOMEM;
        }
 
        if (priv->amic_status == 0)
@@ -294,27 +274,57 @@ 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);
+       return 0;
 }
 
-static DECLARE_DELAYED_WORK(amic_event, amic_detect_handler);
 
-static irqreturn_t imx_amic_detect_handler(int irq, void *data)
+static const struct snd_kcontrol_new controls[] = {
+       SOC_DAPM_PIN_SWITCH("Ext Spk"),
+};
+
+/* imx card dapm widgets */
+static const struct snd_soc_dapm_widget imx_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_SPK("Ext Spk", imx_event_hp),
+       SND_SOC_DAPM_MIC("AMIC", NULL),
+       SND_SOC_DAPM_MIC("DMIC", imx_event_mic),
+};
+
+/* imx machine connections to the codec pins */
+static const struct snd_soc_dapm_route audio_map[] = {
+       { "Headphone Jack", NULL, "HPOUTL" },
+       { "Headphone Jack", NULL, "HPOUTR" },
+
+       { "Ext Spk", NULL, "SPKOUTL" },
+       { "Ext Spk", NULL, "SPKOUTR" },
+
+       { "MICBIAS", NULL, "AMIC" },
+       { "IN3R", NULL, "MICBIAS" },
+
+       { "DMIC", NULL, "MICBIAS" },
+       { "DMICDAT", NULL, "DMIC" },
+
+};
+
+static ssize_t show_headphone(struct device_driver *dev, char *buf)
 {
-       if (suspend_mic_flag == 1)
-               return IRQ_HANDLED;
+       struct imx_priv *priv = &card_priv;
+       struct platform_device *pdev = priv->pdev;
+       struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
+
+       /* determine whether hp is plugged in */
+       priv->hp_status = gpio_get_value(plat->hp_gpio);
+
+       if (priv->hp_status != plat->hp_active_low)
+               strcpy(buf, "headphone\n");
+       else
+               strcpy(buf, "speaker\n");
 
-       mic_irq = 1;
-       disable_irq_nosync(irq);
-       schedule_delayed_work(&amic_event, msecs_to_jiffies(200));
-       return IRQ_HANDLED;
+       return strlen(buf);
 }
 
+static DRIVER_ATTR(headphone, S_IRUGO | S_IWUSR, show_headphone, NULL);
+
 static ssize_t show_amic(struct device_driver *dev, char *buf)
 {
        struct imx_priv *priv = &card_priv;
@@ -334,9 +344,7 @@ 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);
-
+static DECLARE_DELAYED_WORK(resume_hp_event, imx_resume_event);
 
 int imx_hifi_trigger(struct snd_pcm_substream *substream, int cmd)
 {
@@ -344,17 +352,10 @@ int imx_hifi_trigger(struct snd_pcm_substream *substream, int cmd)
        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)
+               if ((plat->hp_gpio != -1) || (plat->mic_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));
+                               msecs_to_jiffies(200));
        }
 
        return 0;
@@ -380,63 +381,43 @@ 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");
 
-       if (plat->hp_gpio != -1) {
-               priv->hp_irq = gpio_to_irq(plat->hp_gpio);
-
-               ret = request_irq(priv->hp_irq,
-                                       imx_headphone_detect_handler,
-                                       IRQ_TYPE_EDGE_BOTH, pdev->name, priv);
+       snd_soc_dapm_sync(&codec->dapm);
 
-               if (ret < 0) {
-                       ret = -EINVAL;
-                       return ret;
-               }
+       if (plat->hp_gpio != -1) {
+               imx_hp_jack_gpio.gpio = plat->hp_gpio;
+               snd_soc_jack_new(codec, "Ext Spk", SND_JACK_LINEOUT,
+                               &imx_hp_jack);
+               snd_soc_jack_add_pins(&imx_hp_jack,
+                                       ARRAY_SIZE(imx_hp_jack_pins),
+                                       imx_hp_jack_pins);
+               snd_soc_jack_add_gpios(&imx_hp_jack,
+                                       1, &imx_hp_jack_gpio);
 
                ret = driver_create_file(pdev->dev.driver,
-                                               &driver_attr_headphone);
+                                                       &driver_attr_headphone);
                if (ret < 0) {
                        ret = -EINVAL;
                        return ret;
                }
-
-               priv->hp_status = gpio_get_value(plat->hp_gpio);
-
-               /* if headphone is inserted, disable speaker */
-               if (priv->hp_status != plat->hp_active_low)
-                       snd_soc_dapm_nc_pin(&codec->dapm, "Ext Spk");
-               else
-                       snd_soc_dapm_enable_pin(&codec->dapm, "Ext Spk");
        }
 
        if (plat->mic_gpio != -1) {
-               priv->amic_irq = gpio_to_irq(plat->mic_gpio);
-
-               ret = request_irq(priv->amic_irq,
-                                       imx_amic_detect_handler,
-                                       IRQ_TYPE_EDGE_BOTH, pdev->name, priv);
+               imx_mic_jack_gpio.gpio = plat->mic_gpio;
+               snd_soc_jack_new(codec, "DMIC", SND_JACK_MICROPHONE,
+                               &imx_mic_jack);
+               snd_soc_jack_add_pins(&imx_mic_jack,
+                                       ARRAY_SIZE(imx_mic_jack_pins),
+                                       imx_mic_jack_pins);
+               snd_soc_jack_add_gpios(&imx_mic_jack,
+                                       1, &imx_mic_jack_gpio);
 
+               ret = driver_create_file(pdev->dev.driver,
+                                                       &driver_attr_amic);
                if (ret < 0) {
                        ret = -EINVAL;
                        return ret;
                }
-
-               ret = driver_create_file(pdev->dev.driver, &driver_attr_amic);
-               if (ret < 0) {
-                       ret = -EINVAL;
-                       return ret;
-               }
-
-               priv->amic_status = gpio_get_value(plat->mic_gpio);
-
-               /* if amic is inserted, disable DMIC */
-               if (priv->amic_status != plat->mic_active_low)
-                       snd_soc_dapm_nc_pin(&codec->dapm, "DMIC");
-               else
-                       snd_soc_dapm_enable_pin(&codec->dapm, "DMIC");
-       } 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;
 }