Merge branch 'topic/cs46xx' into for-linus
[pandora-kernel.git] / sound / soc / pxa / palm27x.c
index e6102fd..1f96e32 100644 (file)
 #include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/gpio.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
+#include <sound/jack.h>
 
 #include <asm/mach-types.h>
 #include <mach/audio.h>
 #include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 
-static int palm27x_jack_func = 1;
-static int palm27x_spk_func = 1;
-static int palm27x_ep_gpio = -1;
+static struct snd_soc_jack hs_jack;
 
-static void palm27x_ext_control(struct snd_soc_codec *codec)
-{
-       if (!palm27x_spk_func)
-               snd_soc_dapm_enable_pin(codec, "Speaker");
-       else
-               snd_soc_dapm_disable_pin(codec, "Speaker");
-
-       if (!palm27x_jack_func)
-               snd_soc_dapm_enable_pin(codec, "Headphone Jack");
-       else
-               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
-
-       snd_soc_dapm_sync(codec);
-}
-
-static int palm27x_startup(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->socdev->card->codec;
-
-       /* check the jack status at stream startup */
-       palm27x_ext_control(codec);
-       return 0;
-}
-
-static struct snd_soc_ops palm27x_ops = {
-       .startup = palm27x_startup,
+/* Headphones jack detection DAPM pins */
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+       {
+               .pin    = "Headphone Jack",
+               .mask   = SND_JACK_HEADPHONE,
+       },
 };
 
-static irqreturn_t palm27x_interrupt(int irq, void *v)
-{
-       palm27x_spk_func = gpio_get_value(palm27x_ep_gpio);
-       palm27x_jack_func = !palm27x_spk_func;
-       return IRQ_HANDLED;
-}
-
-static int palm27x_get_jack(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       ucontrol->value.integer.value[0] = palm27x_jack_func;
-       return 0;
-}
-
-static int palm27x_set_jack(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
-
-       if (palm27x_jack_func == ucontrol->value.integer.value[0])
-               return 0;
-
-       palm27x_jack_func = ucontrol->value.integer.value[0];
-       palm27x_ext_control(codec);
-       return 1;
-}
-
-static int palm27x_get_spk(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       ucontrol->value.integer.value[0] = palm27x_spk_func;
-       return 0;
-}
-
-static int palm27x_set_spk(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
-
-       if (palm27x_spk_func == ucontrol->value.integer.value[0])
-               return 0;
-
-       palm27x_spk_func = ucontrol->value.integer.value[0];
-       palm27x_ext_control(codec);
-       return 1;
-}
+/* Headphones jack detection gpios */
+static struct snd_soc_jack_gpio hs_jack_gpios[] = {
+       [0] = {
+               /* gpio is set on per-platform basis */
+               .name           = "hp-gpio",
+               .report         = SND_JACK_HEADPHONE,
+               .debounce_time  = 200,
+       },
+};
 
-/* PalmTX machine dapm widgets */
+/* Palm27x machine dapm widgets */
 static const struct snd_soc_dapm_widget palm27x_dapm_widgets[] = {
        SND_SOC_DAPM_HP("Headphone Jack", NULL),
-       SND_SOC_DAPM_SPK("Speaker", NULL),
+       SND_SOC_DAPM_SPK("Ext. Speaker", NULL),
+       SND_SOC_DAPM_MIC("Ext. Microphone", NULL),
 };
 
 /* PalmTX audio map */
@@ -126,46 +66,66 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Headphone Jack", NULL, "HPOUTR"},
 
        /* ext speaker connected to ROUT2, LOUT2 */
-       {"Speaker", NULL, "LOUT2"},
-       {"Speaker", NULL, "ROUT2"},
-};
+       {"Ext. Speaker", NULL, "LOUT2"},
+       {"Ext. Speaker", NULL, "ROUT2"},
 
-static const char *jack_function[] = {"Headphone", "Off"};
-static const char *spk_function[] = {"On", "Off"};
-static const struct soc_enum palm27x_enum[] = {
-       SOC_ENUM_SINGLE_EXT(2, jack_function),
-       SOC_ENUM_SINGLE_EXT(2, spk_function),
+       /* mic connected to MIC1 */
+       {"Ext. Microphone", NULL, "MIC1"},
 };
 
-static const struct snd_kcontrol_new palm27x_controls[] = {
-       SOC_ENUM_EXT("Jack Function", palm27x_enum[0], palm27x_get_jack,
-               palm27x_set_jack),
-       SOC_ENUM_EXT("Speaker Function", palm27x_enum[1], palm27x_get_spk,
-               palm27x_set_spk),
-};
+static struct snd_soc_card palm27x_asoc;
 
 static int palm27x_ac97_init(struct snd_soc_codec *codec)
 {
        int err;
 
+       /* add palm27x specific widgets */
+       err = snd_soc_dapm_new_controls(codec, palm27x_dapm_widgets,
+                               ARRAY_SIZE(palm27x_dapm_widgets));
+       if (err)
+               return err;
+
+       /* set up palm27x specific audio path audio_map */
+       err = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       if (err)
+               return err;
+
+       /* connected pins */
+       if (machine_is_palmld())
+               snd_soc_dapm_enable_pin(codec, "MIC1");
+       snd_soc_dapm_enable_pin(codec, "HPOUTL");
+       snd_soc_dapm_enable_pin(codec, "HPOUTR");
+       snd_soc_dapm_enable_pin(codec, "LOUT2");
+       snd_soc_dapm_enable_pin(codec, "ROUT2");
+
+       /* not connected pins */
        snd_soc_dapm_nc_pin(codec, "OUT3");
        snd_soc_dapm_nc_pin(codec, "MONOOUT");
+       snd_soc_dapm_nc_pin(codec, "LINEINL");
+       snd_soc_dapm_nc_pin(codec, "LINEINR");
+       snd_soc_dapm_nc_pin(codec, "PCBEEP");
+       snd_soc_dapm_nc_pin(codec, "PHONE");
+       snd_soc_dapm_nc_pin(codec, "MIC2");
+
+       err = snd_soc_dapm_sync(codec);
+       if (err)
+               return err;
 
-       /* add palm27x specific controls */
-       err = snd_soc_add_controls(codec, palm27x_controls,
-                               ARRAY_SIZE(palm27x_controls));
-       if (err < 0)
+       /* Jack detection API stuff */
+       err = snd_soc_jack_new(&palm27x_asoc, "Headphone Jack",
+                               SND_JACK_HEADPHONE, &hs_jack);
+       if (err)
                return err;
 
-       /* add palm27x specific widgets */
-       snd_soc_dapm_new_controls(codec, palm27x_dapm_widgets,
-                               ARRAY_SIZE(palm27x_dapm_widgets));
+       err = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
+                               hs_jack_pins);
+       if (err)
+               return err;
 
-       /* set up palm27x specific audio path audio_map */
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       err = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios),
+                               hs_jack_gpios);
 
-       snd_soc_dapm_sync(codec);
-       return 0;
+       return err;
 }
 
 static struct snd_soc_dai_link palm27x_dai[] = {
@@ -175,14 +135,12 @@ static struct snd_soc_dai_link palm27x_dai[] = {
        .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
        .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
        .init = palm27x_ac97_init,
-       .ops = &palm27x_ops,
 },
 {
        .name = "AC97 Aux",
        .stream_name = "AC97 Aux",
        .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
        .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
-       .ops = &palm27x_ops,
 },
 };
 
@@ -208,27 +166,17 @@ static int palm27x_asoc_probe(struct platform_device *pdev)
                machine_is_palmld() || machine_is_palmte2()))
                return -ENODEV;
 
-       if (pdev->dev.platform_data)
-               palm27x_ep_gpio = ((struct palm27x_asoc_info *)
-                       (pdev->dev.platform_data))->jack_gpio;
-
-       ret = gpio_request(palm27x_ep_gpio, "Headphone Jack");
-       if (ret)
-               return ret;
-       ret = gpio_direction_input(palm27x_ep_gpio);
-       if (ret)
-               goto err_alloc;
+       if (!pdev->dev.platform_data) {
+               dev_err(&pdev->dev, "please supply platform_data\n");
+               return -ENODEV;
+       }
 
-       if (request_irq(gpio_to_irq(palm27x_ep_gpio), palm27x_interrupt,
-                       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-                       "Headphone jack", NULL))
-               goto err_alloc;
+       hs_jack_gpios[0].gpio = ((struct palm27x_asoc_info *)
+                       (pdev->dev.platform_data))->jack_gpio;
 
        palm27x_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!palm27x_snd_device) {
-               ret = -ENOMEM;
-               goto err_dev;
-       }
+       if (!palm27x_snd_device)
+               return -ENOMEM;
 
        platform_set_drvdata(palm27x_snd_device, &palm27x_snd_devdata);
        palm27x_snd_devdata.dev = &palm27x_snd_device->dev;
@@ -241,18 +189,12 @@ static int palm27x_asoc_probe(struct platform_device *pdev)
 
 put_device:
        platform_device_put(palm27x_snd_device);
-err_dev:
-       free_irq(gpio_to_irq(palm27x_ep_gpio), NULL);
-err_alloc:
-       gpio_free(palm27x_ep_gpio);
 
        return ret;
 }
 
 static int __devexit palm27x_asoc_remove(struct platform_device *pdev)
 {
-       free_irq(gpio_to_irq(palm27x_ep_gpio), NULL);
-       gpio_free(palm27x_ep_gpio);
        platform_device_unregister(palm27x_snd_device);
        return 0;
 }