summaryrefslogtreecommitdiff
path: root/sound/soc/imx/imx-wm8962.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/imx/imx-wm8962.c')
-rw-r--r--sound/soc/imx/imx-wm8962.c100
1 files changed, 54 insertions, 46 deletions
diff --git a/sound/soc/imx/imx-wm8962.c b/sound/soc/imx/imx-wm8962.c
index 8cf4bdd577de..50da297c50f4 100644
--- a/sound/soc/imx/imx-wm8962.c
+++ b/sound/soc/imx/imx-wm8962.c
@@ -27,6 +27,7 @@
#include <linux/fsl_devices.h>
#include <linux/slab.h>
#include <linux/clk.h>
+#include <linux/switch.h>
#include <linux/kthread.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -53,6 +54,7 @@ struct imx_priv {
int amic_irq;
int amic_status;
struct platform_device *pdev;
+ struct switch_dev sdev;
struct snd_pcm_substream *first_stream;
struct snd_pcm_substream *second_stream;
};
@@ -64,7 +66,7 @@ static struct snd_soc_codec *gcodec;
static struct snd_soc_jack imx_hp_jack;
static struct snd_soc_jack_pin imx_hp_jack_pins[] = {
{
- .pin = "Ext Spk",
+ .pin = "Headphone Jack",
.mask = SND_JACK_HEADPHONE,
},
};
@@ -260,50 +262,25 @@ static void imx_resume_event(struct work_struct *wor)
return;
}
-static int imx_event_hp(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+static int hp_jack_status_check(void)
{
struct imx_priv *priv = &card_priv;
struct platform_device *pdev = priv->pdev;
struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
char *envp[3];
char *buf;
+ int ret = 0;
if (plat->hp_gpio != -1) {
priv->hp_status = gpio_get_value(plat->hp_gpio);
- buf = kmalloc(32, GFP_ATOMIC);
- if (!buf) {
- pr_err("%s kmalloc failed\n", __func__);
- return -ENOMEM;
- }
-
+ /* if headphone is inserted, disable speaker */
if (priv->hp_status != plat->hp_active_low)
- snprintf(buf, 32, "STATE=%d", 2);
+ snd_soc_dapm_nc_pin(&gcodec->dapm, "Ext Spk");
else
- snprintf(buf, 32, "STATE=%d", 0);
-
- envp[0] = "NAME=headphone";
- envp[1] = buf;
- envp[2] = NULL;
- kobject_uevent_env(&pdev->dev.kobj, KOBJ_CHANGE, envp);
- kfree(buf);
- }
-
- return 0;
-}
-
-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;
- struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
- char *envp[3];
- char *buf;
+ snd_soc_dapm_enable_pin(&gcodec->dapm, "Ext Spk");
- if (plat->mic_gpio != -1) {
- priv->amic_status = gpio_get_value(plat->mic_gpio);
+ snd_soc_dapm_sync(&gcodec->dapm);
buf = kmalloc(32, GFP_ATOMIC);
if (!buf) {
@@ -311,32 +288,30 @@ static int imx_event_mic(struct snd_soc_dapm_widget *w,
return -ENOMEM;
}
- if (priv->amic_status == 0)
+ if (priv->hp_status != plat->hp_active_low) {
+ switch_set_state(&priv->sdev, 2);
snprintf(buf, 32, "STATE=%d", 2);
- else
+ ret = imx_hp_jack_gpio.report;
+ } else {
+ switch_set_state(&priv->sdev, 0);
snprintf(buf, 32, "STATE=%d", 0);
-
- envp[0] = "NAME=amic";
+ }
+ envp[0] = "NAME=headphone";
envp[1] = buf;
envp[2] = NULL;
kobject_uevent_env(&pdev->dev.kobj, KOBJ_CHANGE, envp);
kfree(buf);
}
- return 0;
+ return ret;
}
-
-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_SPK("Ext Spk", NULL),
SND_SOC_DAPM_MIC("AMIC", NULL),
- SND_SOC_DAPM_MIC("DMIC", imx_event_mic),
+ SND_SOC_DAPM_MIC("DMIC", NULL),
};
/* imx machine connections to the codec pins */
@@ -361,6 +336,9 @@ static ssize_t show_headphone(struct device_driver *dev, char *buf)
struct platform_device *pdev = priv->pdev;
struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
+ if (plat->hp_gpio == -1)
+ return 0;
+
/* determine whether hp is plugged in */
priv->hp_status = gpio_get_value(plat->hp_gpio);
@@ -427,12 +405,14 @@ static int imx_wm8962_init(struct snd_soc_pcm_runtime *rtd)
/* Set up imx specific audio path audio_map */
snd_soc_dapm_add_routes(&codec->dapm, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_enable_pin(&codec->dapm, "Headphone Jack");
+ snd_soc_dapm_enable_pin(&codec->dapm, "Ext Spk");
snd_soc_dapm_enable_pin(&codec->dapm, "AMIC");
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_gpio.jack_status_check = hp_jack_status_check;
+
+ snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
&imx_hp_jack);
snd_soc_jack_add_pins(&imx_hp_jack,
ARRAY_SIZE(imx_hp_jack_pins),
@@ -446,6 +426,14 @@ static int imx_wm8962_init(struct snd_soc_pcm_runtime *rtd)
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) {
@@ -470,6 +458,8 @@ static int imx_wm8962_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_sync(&codec->dapm);
+ snd_soc_dapm_sync(&codec->dapm);
+
return 0;
}
@@ -542,6 +532,20 @@ static int __devinit imx_wm8962_probe(struct platform_device *pdev)
priv->sysclk = plat->sysclk;
+ priv->sdev.name = "h2w";
+ ret = switch_dev_register(&priv->sdev);
+ if (ret < 0) {
+ ret = -EINVAL;
+ return ret;
+ }
+
+ if (plat->hp_gpio != -1) {
+ priv->hp_status = gpio_get_value(plat->hp_gpio);
+ if (priv->hp_status != plat->hp_active_low)
+ switch_set_state(&priv->sdev, 2);
+ else
+ switch_set_state(&priv->sdev, 0);
+ }
priv->first_stream = NULL;
priv->second_stream = NULL;
@@ -553,9 +557,13 @@ static int __devexit imx_wm8962_remove(struct platform_device *pdev)
struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
struct imx_priv *priv = &card_priv;
+ plat->clock_enable(0);
+
if (plat->finit)
plat->finit();
+ switch_dev_unregister(&priv->sdev);
+
if (priv->hp_irq)
free_irq(priv->hp_irq, priv);
if (priv->amic_irq)