summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorGary Zhang <b13634@freescale.com>2012-12-18 15:15:25 +0800
committerGary Zhang <b13634@freescale.com>2012-12-19 14:01:42 +0800
commit29d76238e17ac1b46327529375bbdf8e5903d702 (patch)
tree757a87089652b2d6a7867009ff018d0c76eeb425 /sound
parent592eb9e19b04e44e47064fed2428b71874ac4ccb (diff)
downloadlinux-29d76238e17ac1b46327529375bbdf8e5903d702.tar.gz
ENGR00236910 wm8962: use alsa jack mechanism to handle pin detection
use alsa jack mechanism to handle pin detection Signed-off-by: Gary Zhang <b13634@freescale.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/imx/imx-wm8962.c299
1 files changed, 140 insertions, 159 deletions
diff --git a/sound/soc/imx/imx-wm8962.c b/sound/soc/imx/imx-wm8962.c
index 9abc4a7424dd..e7b60df13180 100644
--- a/sound/soc/imx/imx-wm8962.c
+++ b/sound/soc/imx/imx-wm8962.c
@@ -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;
}