Merge branch 'for-2.6.37' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6 into topic/asoc
diff --git a/arch/arm/mach-mx3/clock-imx31.c b/arch/arm/mach-mx3/clock-imx31.c
index 9b52a67..9a9eb6d 100644
--- a/arch/arm/mach-mx3/clock-imx31.c
+++ b/arch/arm/mach-mx3/clock-imx31.c
@@ -558,8 +558,8 @@
 	_REGISTER_CLOCK("mxc_w1.0", NULL, owire_clk)
 	_REGISTER_CLOCK("mxc-mmc.0", NULL, sdhc1_clk)
 	_REGISTER_CLOCK("mxc-mmc.1", NULL, sdhc2_clk)
-	_REGISTER_CLOCK("imx-ssi-dai.0", NULL, ssi1_clk)
-	_REGISTER_CLOCK("imx-ssi-dai.1", NULL, ssi2_clk)
+	_REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
+	_REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
 	_REGISTER_CLOCK(NULL, "firi", firi_clk)
 	_REGISTER_CLOCK(NULL, "ata", ata_clk)
 	_REGISTER_CLOCK(NULL, "rtic", rtic_clk)
diff --git a/arch/arm/mach-mx3/clock-imx35.c b/arch/arm/mach-mx3/clock-imx35.c
index f29c3e9..d3af0fd 100644
--- a/arch/arm/mach-mx3/clock-imx35.c
+++ b/arch/arm/mach-mx3/clock-imx35.c
@@ -464,8 +464,8 @@
 	_REGISTER_CLOCK(NULL, "sdma", sdma_clk)
 	_REGISTER_CLOCK(NULL, "spba", spba_clk)
 	_REGISTER_CLOCK(NULL, "spdif", spdif_clk)
-	_REGISTER_CLOCK("imx-ssi-dai.0", NULL, ssi1_clk)
-	_REGISTER_CLOCK("imx-ssi-dai.1", NULL, ssi2_clk)
+	_REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
+	_REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
 	_REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk)
 	_REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk)
 	_REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
diff --git a/arch/arm/mach-mx3/devices.c b/arch/arm/mach-mx3/devices.c
index 90eccba..a4fd1a2 100644
--- a/arch/arm/mach-mx3/devices.c
+++ b/arch/arm/mach-mx3/devices.c
@@ -327,14 +327,14 @@
 };
 
 struct platform_device imx_ssi_device0 = {
-	.name = "imx-ssi-dai",
+	.name = "imx-ssi",
 	.id = 0,
 	.num_resources = ARRAY_SIZE(imx_ssi_resources0),
 	.resource = imx_ssi_resources0,
 };
 
 struct platform_device imx_ssi_device1 = {
-	.name = "imx-ssi-dai",
+	.name = "imx-ssi",
 	.id = 1,
 	.num_resources = ARRAY_SIZE(imx_ssi_resources1),
 	.resource = imx_ssi_resources1,
diff --git a/arch/arm/plat-mxc/audmux-v2.c b/arch/arm/plat-mxc/audmux-v2.c
index 910374d..f9e7cdb 100644
--- a/arch/arm/plat-mxc/audmux-v2.c
+++ b/arch/arm/plat-mxc/audmux-v2.c
@@ -45,9 +45,9 @@
 {
 	switch (port) {
 	case MX31_AUDMUX_PORT1_SSI0:
-		return "imx-ssi-dai.0";
+		return "imx-ssi.0";
 	case MX31_AUDMUX_PORT2_SSI1:
-		return "imx-ssi-dai.1";
+		return "imx-ssi.1";
 	case MX31_AUDMUX_PORT3_SSI_PINS_3:
 		return "SSI3";
 	case MX31_AUDMUX_PORT4_SSI_PINS_4:
diff --git a/include/sound/wm8962.h b/include/sound/wm8962.h
index 9722aac..2b5306c 100644
--- a/include/sound/wm8962.h
+++ b/include/sound/wm8962.h
@@ -15,6 +15,7 @@
 #define WM8962_GPIO_SET 0x10000
 
 struct wm8962_pdata {
+	int gpio_base;
 	u32 gpio_init[WM8962_MAX_GPIO];
 
 	/* Setup for microphone detection, raw value to be written to
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index ca7d9ee..2657f5c 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -390,37 +390,42 @@
 			  int source, unsigned int freq_in,
 			  unsigned int freq_out)
 {
-	int ret;
 	struct snd_soc_codec *codec;
-	struct pll_div pll_div = { 0 };
 
 	codec = dai->codec;
-	if (freq_in && freq_out) {
+	if (!freq_in || !freq_out) {
+		/* disable the PLL */
+		snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0x1);
+		return 0;
+	} else {
+		int ret;
+		struct pll_div pll_div;
+
 		ret = pll_factors(&pll_div, freq_out, freq_in);
 		if (ret)
 			return ret;
+
+		/* power down the PLL before reprogramming it */
+		snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0x1);
+
+		if (!freq_in || !freq_out)
+			return 0;
+
+		/* set PLLN and PRESCALE */
+		snd_soc_update_bits(codec, WM8804_PLL4, 0xf | 0x10,
+				    pll_div.n | (pll_div.prescale << 4));
+		/* set mclkdiv and freqmode */
+		snd_soc_update_bits(codec, WM8804_PLL5, 0x3 | 0x8,
+				    pll_div.freqmode | (pll_div.mclkdiv << 3));
+		/* set PLLK */
+		snd_soc_write(codec, WM8804_PLL1, pll_div.k & 0xff);
+		snd_soc_write(codec, WM8804_PLL2, (pll_div.k >> 8) & 0xff);
+		snd_soc_write(codec, WM8804_PLL3, pll_div.k >> 16);
+
+		/* power up the PLL */
+		snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0);
 	}
 
-	/* power down the PLL before reprogramming it */
-	snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0);
-
-	if (!freq_in || !freq_out)
-		return 0;
-
-	/* set PLLN and PRESCALE */
-	snd_soc_update_bits(codec, WM8804_PLL4, 0xf | 0x10,
-			    pll_div.n | (pll_div.prescale << 4));
-	/* set mclkdiv and freqmode */
-	snd_soc_update_bits(codec, WM8804_PLL5, 0x3 | 0x8,
-			    pll_div.freqmode | (pll_div.mclkdiv << 3));
-	/* set PLLK */
-	snd_soc_write(codec, WM8804_PLL1, pll_div.k & 0xff);
-	snd_soc_write(codec, WM8804_PLL2, (pll_div.k >> 8) & 0xff);
-	snd_soc_write(codec, WM8804_PLL3, pll_div.k >> 16);
-
-	/* power up the PLL */
-	snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0x1);
-
 	return 0;
 }
 
@@ -669,7 +674,7 @@
 			SNDRV_PCM_FMTBIT_S24_LE)
 
 static struct snd_soc_dai_driver wm8804_dai = {
-	.name = "wm8804-s/pdif",
+	.name = "wm8804-spdif",
 	.playback = {
 		.stream_name = "Playback",
 		.channels_min = 2,
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index be34146..6d30f34 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -17,6 +17,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/gcd.h>
+#include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/platform_device.h>
@@ -24,6 +25,7 @@
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 #include <sound/core.h>
+#include <sound/jack.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -62,6 +64,9 @@
 	int fll_fref;
 	int fll_fout;
 
+	struct delayed_work mic_work;
+	struct snd_soc_jack *jack;
+
 	struct regulator_bulk_data supplies[WM8962_NUM_SUPPLIES];
 	struct notifier_block disable_nb[WM8962_NUM_SUPPLIES];
 
@@ -70,6 +75,10 @@
 	struct work_struct beep_work;
 	int beep_rate;
 #endif
+
+#ifdef CONFIG_GPIOLIB
+	struct gpio_chip gpio_chip;
+#endif
 };
 
 /* We can't use the same notifier block for more than one supply and
@@ -911,12 +920,6 @@
 	int clocking2 = 0;
 	int aif2 = 0;
 
-	/* If the CODEC is powered on we can configure BCLK */
-	if (codec->bias_level != SND_SOC_BIAS_OFF) {
-		dev_dbg(codec->dev, "Bias is off, can't configure BCLK\n");
-		return;
-	}
-
 	if (!wm8962->bclk) {
 		dev_dbg(codec->dev, "No BCLK rate configured\n");
 		return;
@@ -1463,9 +1466,40 @@
 	.symmetric_rates = 1,
 };
 
+static void wm8962_mic_work(struct work_struct *work)
+{
+	struct wm8962_priv *wm8962 = container_of(work,
+						  struct wm8962_priv,
+						  mic_work.work);
+	struct snd_soc_codec *codec = wm8962->codec;
+	int status = 0;
+	int irq_pol = 0;
+	int reg;
+
+	reg = snd_soc_read(codec, WM8962_ADDITIONAL_CONTROL_4);
+
+	if (reg & WM8962_MICDET_STS) {
+		status |= SND_JACK_MICROPHONE;
+		irq_pol |= WM8962_MICD_IRQ_POL;
+	}
+
+	if (reg & WM8962_MICSHORT_STS) {
+		status |= SND_JACK_BTN_0;
+		irq_pol |= WM8962_MICSCD_IRQ_POL;
+	}
+
+	snd_soc_jack_report(wm8962->jack, status,
+			    SND_JACK_MICROPHONE | SND_JACK_BTN_0);
+
+	snd_soc_update_bits(codec, WM8962_MICINT_SOURCE_POL,
+			    WM8962_MICSCD_IRQ_POL |
+			    WM8962_MICD_IRQ_POL, irq_pol);
+}
+
 static irqreturn_t wm8962_irq(int irq, void *data)
 {
 	struct snd_soc_codec *codec = data;
+	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
 	int mask;
 	int active;
 
@@ -1480,12 +1514,59 @@
 	if (active & WM8962_TEMP_SHUT_EINT)
 		dev_crit(codec->dev, "Thermal shutdown\n");
 
+	if (active & (WM8962_MICSCD_EINT | WM8962_MICD_EINT)) {
+		dev_dbg(codec->dev, "Microphone event detected\n");
+
+		schedule_delayed_work(&wm8962->mic_work,
+				      msecs_to_jiffies(250));
+	}
+
 	/* Acknowledge the interrupts */
 	snd_soc_write(codec, WM8962_INTERRUPT_STATUS_2, active);
 
 	return IRQ_HANDLED;
 }
 
+/**
+ * wm8962_mic_detect - Enable microphone detection via the WM8962 IRQ
+ *
+ * @codec:  WM8962 codec
+ * @jack:   jack to report detection events on
+ *
+ * Enable microphone detection via IRQ on the WM8962.  If GPIOs are
+ * being used to bring out signals to the processor then only platform
+ * data configuration is needed for WM8962 and processor GPIOs should
+ * be configured using snd_soc_jack_add_gpios() instead.
+ *
+ * If no jack is supplied detection will be disabled.
+ */
+int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
+{
+	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+	int irq_mask, enable;
+
+	wm8962->jack = jack;
+	if (jack) {
+		irq_mask = 0;
+		enable = WM8962_MICDET_ENA;
+	} else {
+		irq_mask = WM8962_MICD_EINT | WM8962_MICSCD_EINT;
+		enable = 0;
+	}
+
+	snd_soc_update_bits(codec, WM8962_INTERRUPT_STATUS_2_MASK,
+			    WM8962_MICD_EINT | WM8962_MICSCD_EINT, irq_mask);
+	snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4,
+			    WM8962_MICDET_ENA, enable);
+
+	/* Send an initial empty report */
+	snd_soc_jack_report(wm8962->jack, 0,
+			    SND_JACK_MICROPHONE | SND_JACK_BTN_0);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm8962_mic_detect);
+
 #ifdef CONFIG_PM
 static int wm8962_resume(struct snd_soc_codec *codec)
 {
@@ -1652,6 +1733,132 @@
 }
 #endif
 
+static void wm8962_set_gpio_mode(struct snd_soc_codec *codec, int gpio)
+{
+	int mask = 0;
+	int val = 0;
+
+	/* Some of the GPIOs are behind MFP configuration and need to
+	 * be put into GPIO mode. */
+	switch (gpio) {
+	case 2:
+		mask = WM8962_CLKOUT2_SEL_MASK;
+		val = 1 << WM8962_CLKOUT2_SEL_SHIFT;
+		break;
+	case 3:
+		mask = WM8962_CLKOUT3_SEL_MASK;
+		val = 1 << WM8962_CLKOUT3_SEL_SHIFT;
+		break;
+	default:
+		break;
+	}
+
+	if (mask)
+		snd_soc_update_bits(codec, WM8962_ANALOGUE_CLOCKING1,
+				    mask, val);
+}
+
+#ifdef CONFIG_GPIOLIB
+static inline struct wm8962_priv *gpio_to_wm8962(struct gpio_chip *chip)
+{
+	return container_of(chip, struct wm8962_priv, gpio_chip);
+}
+
+static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	struct wm8962_priv *wm8962 = gpio_to_wm8962(chip);
+	struct snd_soc_codec *codec = wm8962->codec;
+
+	/* The WM8962 GPIOs aren't linearly numbered.  For simplicity
+	 * we export linear numbers and error out if the unsupported
+	 * ones are requsted.
+	 */
+	switch (offset + 1) {
+	case 2:
+	case 3:
+	case 5:
+	case 6:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	wm8962_set_gpio_mode(codec, offset + 1);
+
+	return 0;
+}
+
+static void wm8962_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct wm8962_priv *wm8962 = gpio_to_wm8962(chip);
+	struct snd_soc_codec *codec = wm8962->codec;
+
+	snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset,
+			    WM8962_GP2_LVL, value << WM8962_GP2_LVL_SHIFT);
+}
+
+static int wm8962_gpio_direction_out(struct gpio_chip *chip,
+				     unsigned offset, int value)
+{
+	struct wm8962_priv *wm8962 = gpio_to_wm8962(chip);
+	struct snd_soc_codec *codec = wm8962->codec;
+	int val;
+
+	/* Force function 1 (logic output) */
+	val = (1 << WM8962_GP2_FN_SHIFT) | (value << WM8962_GP2_LVL_SHIFT);
+
+	return snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset,
+				   WM8962_GP2_FN_MASK | WM8962_GP2_LVL, val);
+}
+
+static struct gpio_chip wm8962_template_chip = {
+	.label			= "wm8962",
+	.owner			= THIS_MODULE,
+	.request		= wm8962_gpio_request,
+	.direction_output	= wm8962_gpio_direction_out,
+	.set			= wm8962_gpio_set,
+	.can_sleep		= 1,
+};
+
+static void wm8962_init_gpio(struct snd_soc_codec *codec)
+{
+	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+	struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
+	int ret;
+
+	wm8962->gpio_chip = wm8962_template_chip;
+	wm8962->gpio_chip.ngpio = WM8962_MAX_GPIO;
+	wm8962->gpio_chip.dev = codec->dev;
+
+	if (pdata && pdata->gpio_base)
+		wm8962->gpio_chip.base = pdata->gpio_base;
+	else
+		wm8962->gpio_chip.base = -1;
+
+	ret = gpiochip_add(&wm8962->gpio_chip);
+	if (ret != 0)
+		dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
+}
+
+static void wm8962_free_gpio(struct snd_soc_codec *codec)
+{
+	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	ret = gpiochip_remove(&wm8962->gpio_chip);
+	if (ret != 0)
+		dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
+}
+#else
+static void wm8962_init_gpio(struct snd_soc_codec *codec)
+{
+}
+
+static void wm8962_free_gpio(struct snd_soc_codec *codec)
+{
+}
+#endif
+
 static int wm8962_probe(struct snd_soc_codec *codec)
 {
 	int ret;
@@ -1662,6 +1869,7 @@
 	int i, trigger, irq_pol;
 
 	wm8962->codec = codec;
+	INIT_DELAYED_WORK(&wm8962->mic_work, wm8962_mic_work);
 
 	codec->cache_sync = 1;
 	codec->idle_bias_off = 1;
@@ -1749,9 +1957,11 @@
 	if (pdata) {
 		/* Apply static configuration for GPIOs */
 		for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++)
-			if (pdata->gpio_init[i])
+			if (pdata->gpio_init[i]) {
+				wm8962_set_gpio_mode(codec, i + 1);
 				snd_soc_write(codec, 0x200 + i,
 					      pdata->gpio_init[i] & 0xffff);
+			}
 
 		/* Put the speakers into mono mode? */
 		if (pdata->spk_mono)
@@ -1784,6 +1994,7 @@
 	wm8962_add_widgets(codec);
 
 	wm8962_init_beep(codec);
+	wm8962_init_gpio(codec);
 
 	if (i2c->irq) {
 		if (pdata && pdata->irq_active_low) {
@@ -1834,6 +2045,9 @@
 	if (i2c->irq)
 		free_irq(i2c->irq, codec);
 
+	cancel_delayed_work_sync(&wm8962->mic_work);
+
+	wm8962_free_gpio(codec);
 	wm8962_free_beep(codec);
 	for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++)
 		regulator_unregister_notifier(wm8962->supplies[i].consumer,
diff --git a/sound/soc/codecs/wm8962.h b/sound/soc/codecs/wm8962.h
index 6145399..2af6c93 100644
--- a/sound/soc/codecs/wm8962.h
+++ b/sound/soc/codecs/wm8962.h
@@ -14,6 +14,7 @@
 #define _WM8962_H
 
 #include <asm/types.h>
+#include <sound/soc.h>
 
 #define WM8962_SYSCLK_MCLK 1
 #define WM8962_SYSCLK_FLL  2
@@ -181,6 +182,7 @@
 #define WM8962_EQ39                             0x175
 #define WM8962_EQ40                             0x176
 #define WM8962_EQ41                             0x177
+#define WM8962_GPIO_BASE			0x200
 #define WM8962_GPIO_2                           0x201
 #define WM8962_GPIO_3                           0x202
 #define WM8962_GPIO_5                           0x204
@@ -3784,4 +3786,6 @@
 extern
 const struct wm8962_reg_access wm8962_reg_access[WM8962_MAX_REGISTER + 1];
 
+int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
+
 #endif
diff --git a/sound/soc/imx/eukrea-tlv320.c b/sound/soc/imx/eukrea-tlv320.c
index 807f736..b596752 100644
--- a/sound/soc/imx/eukrea-tlv320.c
+++ b/sound/soc/imx/eukrea-tlv320.c
@@ -82,7 +82,7 @@
 	.codec_dai	= "tlv320aic23-hifi",
 	.platform_name	= "imx-pcm-audio.0",
 	.codec_name	= "tlv320aic23-codec.0-001a",
-	.cpu_dai = "imx-ssi-dai.0",
+	.cpu_dai = "imx-ssi.0",
 	.ops		= &eukrea_tlv320_snd_ops,
 };
 
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
index 26716e9..d4bd345 100644
--- a/sound/soc/imx/imx-ssi.c
+++ b/sound/soc/imx/imx-ssi.c
@@ -734,7 +734,7 @@
 	.remove = __devexit_p(imx_ssi_remove),
 
 	.driver = {
-		.name = "imx-ssi-dai",
+		.name = "imx-ssi",
 		.owner = THIS_MODULE,
 	},
 };
diff --git a/sound/soc/imx/phycore-ac97.c b/sound/soc/imx/phycore-ac97.c
index 65f0f99..6a65dd7 100644
--- a/sound/soc/imx/phycore-ac97.c
+++ b/sound/soc/imx/phycore-ac97.c
@@ -34,7 +34,7 @@
 		.stream_name	= "HiFi",
 		.codec_dai_name		= "wm9712-hifi",
 		.codec_name	= "wm9712-codec",
-		.cpu_dai_name	= "imx-ssi-dai.0",
+		.cpu_dai_name	= "imx-ssi.0",
 		.platform_name	= "imx-fiq-pcm-audio.0",
 		.ops		= &imx_phycore_hifi_ops,
 	},
diff --git a/sound/soc/imx/wm1133-ev1.c b/sound/soc/imx/wm1133-ev1.c
index 7406863..30fdb15 100644
--- a/sound/soc/imx/wm1133-ev1.c
+++ b/sound/soc/imx/wm1133-ev1.c
@@ -243,7 +243,7 @@
 static struct snd_soc_dai_link wm1133_ev1_dai = {
 	.name = "WM1133-EV1",
 	.stream_name = "Audio",
-	.cpu_dai_name = "imx-ssi-dai.0",
+	.cpu_dai_name = "imx-ssi.0",
 	.codec_dai_name = "wm8350-hifi",
 	.platform_name = "imx-fiq-pcm-audio.0",
 	.codec_name = "wm8350-codec.0-0x1a",