#include <sound/soc.h>
 #include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <linux/gpio.h>
 
 #include "../codecs/wm8915.h"
 #include "../codecs/wm9081.h"
 
+#define WM8915_HPSEL_GPIO 214
+
 static int speyside_set_bias_level(struct snd_soc_card *card,
                                   enum snd_soc_bias_level level)
 {
        .hw_params = speyside_hw_params,
 };
 
+static struct snd_soc_jack speyside_headset;
+
+/* Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin speyside_headset_pins[] = {
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+       {
+               .pin = "Headphone",
+               .mask = SND_JACK_HEADPHONE,
+       },
+};
+
+/* Default the headphone selection to active high */
+static int speyside_jack_polarity;
+
+static int speyside_get_micbias(struct snd_soc_dapm_widget *source,
+                               struct snd_soc_dapm_widget *sink)
+{
+       if (speyside_jack_polarity && (strcmp(source->name, "MICB1") == 0))
+               return 1;
+       if (!speyside_jack_polarity && (strcmp(source->name, "MICB2") == 0))
+               return 1;
+
+       return 0;
+}
+
+static void speyside_set_polarity(struct snd_soc_codec *codec,
+                                 int polarity)
+{
+       speyside_jack_polarity = !polarity;
+       gpio_direction_output(WM8915_HPSEL_GPIO, speyside_jack_polarity);
+
+       /* Re-run DAPM to make sure we're using the correct mic bias */
+       snd_soc_dapm_sync(&codec->dapm);
+}
+
 static int speyside_wm8915_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_dai *dai = rtd->codec_dai;
+       struct snd_soc_codec *codec = rtd->codec;
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(dai, WM8915_SYSCLK_MCLK1, 32768, 0);
+       if (ret < 0)
+               return ret;
+
+       ret = gpio_request(WM8915_HPSEL_GPIO, "HP_SEL");
+       if (ret != 0)
+               pr_err("Failed to request HP_SEL GPIO: %d\n", ret);
+       gpio_direction_output(WM8915_HPSEL_GPIO, speyside_jack_polarity);
 
-       return snd_soc_dai_set_sysclk(dai, WM8915_SYSCLK_MCLK1, 32768, 0);
+       ret = snd_soc_jack_new(codec, "Headset",
+                              SND_JACK_HEADSET | SND_JACK_BTN_0,
+                              &speyside_headset);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_jack_add_pins(&speyside_headset,
+                                   ARRAY_SIZE(speyside_headset_pins),
+                                   speyside_headset_pins);
+       if (ret)
+               return ret;
+
+       wm8915_detect(codec, &speyside_headset, speyside_set_polarity);
+
+       return 0;
 }
 
 static struct snd_soc_dai_link speyside_dai[] = {
 
 static struct snd_soc_dapm_widget widgets[] = {
        SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
 
        SND_SOC_DAPM_SPK("Main Speaker", NULL),
 
 };
 
 static struct snd_soc_dapm_route audio_paths[] = {
+       { "IN1RN", NULL, "MICB1" },
+       { "IN1RP", NULL, "MICB1" },
+       { "IN1RN", NULL, "MICB2" },
+       { "IN1RP", NULL, "MICB2" },
+       { "MICB1", NULL, "Headset Mic", speyside_get_micbias },
+       { "MICB2", NULL, "Headset Mic", speyside_get_micbias },
+
        { "IN1LP", NULL, "MICB2" },
+       { "IN1RN", NULL, "MICB1" },
        { "MICB2", NULL, "Main AMIC" },
 
        { "DMIC1DAT", NULL, "MICB1" },