summary refs log tree commit diff
path: root/sound
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-10-13 10:06:58 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2008-10-13 10:06:58 -0700
commitbe3bfbba8f7f6c8f32e8444ef895433701a3f801 (patch)
treedfd00be7d15dbf8353f188f2505426411cb18d06 /sound
parent20272c8994cf1e1f8ed745a2ea161dd9ad3889f2 (diff)
parent7dc85076f83253fcffae99e6d5e6ce77840f8841 (diff)
downloadlinux-be3bfbba8f7f6c8f32e8444ef895433701a3f801.tar.gz
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (33 commits)
  ALSA: ASoC codec: remove unused #include <version.h>
  ALSA: ASoC: update email address for Liam Girdwood
  ALSA: hda: corrected invalid mixer values
  ALSA: hda: add mixers for analog mixer on 92hd75xx codecs
  ALSA: ASoC: Add destination and source port for DMA on OMAP1
  ALSA: ASoC: Drop device registration from GTA01 lm4857 driver
  ALSA: ASoC: Fix build of GTA01 audio driver
  ALSA: ASoC: Add widgets before setting endpoints on GTA01
  ALSA: ASoC: Fix inverted input PGA mute bits in WM8903
  ALSA: ASoC: OMAP: Set DMA stream name at runtime in McBSP DAI driver
  ALSA: ASoC: OMAP: Add support for OMAP2430 and OMAP34xx in McBSP DAI driver
  ALSA: ASoC: OMAP: Add multilink support to McBSP DAI driver
  ALSA: ASoC: Make TLV320AIC26 user-visible
  ALSA: ASoC - clean up Kconfig for TLV320AIC2
  ALSA: ASoC: Make WM8510 microphone input a DAPM mixer
  ALSA: ASoC: Implement WM8510 bias level control
  ALSA: ASoC: Remove unused AUDIO_NAME define from codec drivers
  ALSA: ASoC: tlv320aic3x: Use uniform tlv320aic naming
  ALSA: ASoC: Add WM8510 SPI support
  ALSA: ASoC: Add WM8753 SPI support
  ...
Diffstat (limited to 'sound')
-rw-r--r--sound/oss/ac97_codec.c2
-rw-r--r--sound/pci/ac97/ac97_patch.c2
-rw-r--r--sound/pci/hda/patch_sigmatel.c50
-rw-r--r--sound/soc/at91/Kconfig17
-rw-r--r--sound/soc/at91/Makefile5
-rw-r--r--sound/soc/at91/at91-ssc.c2
-rw-r--r--sound/soc/at91/eti_b1_wm8731.c349
-rw-r--r--sound/soc/blackfin/Kconfig16
-rw-r--r--sound/soc/blackfin/Makefile3
-rw-r--r--sound/soc/blackfin/bf5xx-ac97-pcm.c42
-rw-r--r--sound/soc/blackfin/bf5xx-ac97.c1
-rw-r--r--sound/soc/blackfin/bf5xx-ad73311.c240
-rw-r--r--sound/soc/blackfin/bf5xx-i2s.c47
-rw-r--r--sound/soc/blackfin/bf5xx-sport.h2
-rw-r--r--sound/soc/codecs/Kconfig11
-rw-r--r--sound/soc/codecs/Makefile4
-rw-r--r--sound/soc/codecs/ac97.c3
-rw-r--r--sound/soc/codecs/ad1980.c1
-rw-r--r--sound/soc/codecs/ad73311.c107
-rw-r--r--sound/soc/codecs/ad73311.h90
-rw-r--r--sound/soc/codecs/ak4535.c1
-rw-r--r--sound/soc/codecs/ssm2602.c1
-rw-r--r--sound/soc/codecs/tlv320aic23.c714
-rw-r--r--sound/soc/codecs/tlv320aic23.h122
-rw-r--r--sound/soc/codecs/tlv320aic3x.c5
-rw-r--r--sound/soc/codecs/uda1380.c1
-rw-r--r--sound/soc/codecs/wm8510.c111
-rw-r--r--sound/soc/codecs/wm8510.h1
-rw-r--r--sound/soc/codecs/wm8580.c2
-rw-r--r--sound/soc/codecs/wm8731.c1
-rw-r--r--sound/soc/codecs/wm8750.c1
-rw-r--r--sound/soc/codecs/wm8753.c75
-rw-r--r--sound/soc/codecs/wm8753.h4
-rw-r--r--sound/soc/codecs/wm8900.c1
-rw-r--r--sound/soc/codecs/wm8903.c4
-rw-r--r--sound/soc/codecs/wm8971.c1
-rw-r--r--sound/soc/codecs/wm8990.c1
-rw-r--r--sound/soc/codecs/wm9712.c3
-rw-r--r--sound/soc/codecs/wm9713.c3
-rw-r--r--sound/soc/omap/Kconfig8
-rw-r--r--sound/soc/omap/Makefile2
-rw-r--r--sound/soc/omap/n810.c6
-rw-r--r--sound/soc/omap/omap-mcbsp.c181
-rw-r--r--sound/soc/omap/omap-mcbsp.h16
-rw-r--r--sound/soc/omap/omap-pcm.c4
-rw-r--r--sound/soc/omap/osk5912.c232
-rw-r--r--sound/soc/pxa/corgi.c6
-rw-r--r--sound/soc/pxa/em-x270.c2
-rw-r--r--sound/soc/pxa/poodle.c6
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.c4
-rw-r--r--sound/soc/pxa/spitz.c16
-rw-r--r--sound/soc/pxa/tosa.c6
-rw-r--r--sound/soc/s3c24xx/neo1973_wm8753.c72
-rw-r--r--sound/soc/soc-core.c5
-rw-r--r--sound/soc/soc-dapm.c25
55 files changed, 2036 insertions, 601 deletions
diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c
index b63839e8f9bd..456a1b4d7832 100644
--- a/sound/oss/ac97_codec.c
+++ b/sound/oss/ac97_codec.c
@@ -30,7 +30,7 @@
  **************************************************************************
  *
  * History
- * May 02, 2003 Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * May 02, 2003 Liam Girdwood <lrg@slimlogic.co.uk>
  *	Removed non existant WM9700
  *	Added support for WM9705, WM9708, WM9709, WM9710, WM9711
  *	WM9712 and WM9717
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index 6ce3cbe98a6a..6e831aff1bd0 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -476,7 +476,7 @@ static int patch_yamaha_ymf753(struct snd_ac97 * ac97)
 }
 
 /*
- * May 2, 2003 Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * May 2, 2003 Liam Girdwood <lrg@slimlogic.co.uk>
  *  removed broken wolfson00 patch.
  *  added support for WM9705,WM9708,WM9709,WM9710,WM9711,WM9712 and WM9717.
  */
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index c461baa83c2a..c59065513118 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -322,8 +322,8 @@ static hda_nid_t stac92hd71bxx_mux_nids[2] = {
 	0x1a, 0x1b
 };
 
-static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
-	0x1c,
+static hda_nid_t stac92hd71bxx_dmux_nids[2] = {
+	0x1c, 0x1d,
 };
 
 static hda_nid_t stac92hd71bxx_smux_nids[2] = {
@@ -861,20 +861,18 @@ static struct hda_verb stac92hd71bxx_core_init[] = {
 	{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	/* connect headphone jack to dac1 */
 	{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
-	{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
 	/* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
 	{ 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{ 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 };
 
-#define HD_DISABLE_PORTF 3
+#define HD_DISABLE_PORTF 2
 static struct hda_verb stac92hd71bxx_analog_core_init[] = {
 	/* start of config #1 */
 
 	/* connect port 0f to audio mixer */
 	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
-	{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
 	/* unmute right and left channels for node 0x0f */
 	{ 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	/* start of config #2 */
@@ -883,10 +881,6 @@ static struct hda_verb stac92hd71bxx_analog_core_init[] = {
 	{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	/* connect headphone jack to dac1 */
 	{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
-	/* connect port 0d to audio mixer */
-	{ 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
-	/* unmute dac0 input in audio mixer */
-	{ 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
 	/* unmute right and left channels for nodes 0x0a, 0xd */
 	{ 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -1107,6 +1101,7 @@ static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
 
 static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
 	STAC_INPUT_SOURCE(2),
+	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
 
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
@@ -1119,8 +1114,17 @@ static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
 	HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
 	*/
 
-	HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
-	HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
+	HDA_CODEC_MUTE("Import0 Mux Capture Switch", 0x17, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Import0 Mux Capture Volume", 0x17, 0x0, HDA_INPUT),
+
+	HDA_CODEC_MUTE("Import1 Mux Capture Switch", 0x17, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Import1 Mux Capture Volume", 0x17, 0x1, HDA_INPUT),
+
+	HDA_CODEC_MUTE("DAC0 Capture Switch", 0x17, 0x3, HDA_INPUT),
+	HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x17, 0x3, HDA_INPUT),
+
+	HDA_CODEC_MUTE("DAC1 Capture Switch", 0x17, 0x4, HDA_INPUT),
+	HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x17, 0x4, HDA_INPUT),
 	{ } /* end */
 };
 
@@ -1649,7 +1653,7 @@ static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
 
 static unsigned int ref92hd71bxx_pin_configs[11] = {
 	0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
-	0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
+	0x0181302e, 0x01014010, 0x01019020, 0x90a000f0,
 	0x90a000f0, 0x01452050, 0x01452050,
 };
 
@@ -3000,7 +3004,7 @@ static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
 
 /* labels for amp mux outputs */
 static const char *stac92xx_amp_labels[3] = {
-	"Front Microphone", "Microphone", "Line In"
+	"Front Microphone", "Microphone", "Line In",
 };
 
 /* create amp out controls mux on capable codecs */
@@ -4327,6 +4331,16 @@ static struct hda_codec_ops stac92hd71bxx_patch_ops = {
 #endif
 };
 
+static struct hda_input_mux stac92hd71bxx_dmux = {
+	.num_items = 4,
+	.items = {
+		{ "Analog Inputs", 0x00 },
+		{ "Mixer", 0x01 },
+		{ "Digital Mic 1", 0x02 },
+		{ "Digital Mic 2", 0x03 },
+	}
+};
+
 static int patch_stac92hd71bxx(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec;
@@ -4341,6 +4355,8 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
 	spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
 	spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
 	spec->pin_nids = stac92hd71bxx_pin_nids;
+	memcpy(&spec->private_dimux, &stac92hd71bxx_dmux,
+			sizeof(stac92hd71bxx_dmux));
 	spec->board_config = snd_hda_check_board_config(codec,
 							STAC_92HD71BXX_MODELS,
 							stac92hd71bxx_models,
@@ -4392,6 +4408,7 @@ again:
 		/* no output amps */
 		spec->num_pwrs = 0;
 		spec->mixer = stac92hd71bxx_analog_mixer;
+		spec->dinput_mux = &spec->private_dimux;
 
 		/* disable VSW */
 		spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
@@ -4409,12 +4426,13 @@ again:
 		spec->num_pwrs = 0;
 		/* fallthru */
 	default:
+		spec->dinput_mux = &spec->private_dimux;
 		spec->mixer = stac92hd71bxx_analog_mixer;
 		spec->init = stac92hd71bxx_analog_core_init;
 		codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
 	}
 
-	spec->aloopback_mask = 0x20;
+	spec->aloopback_mask = 0x50;
 	spec->aloopback_shift = 0;
 
 	if (spec->board_config > STAC_92HD71BXX_REF) {
@@ -4456,6 +4474,10 @@ again:
 	spec->multiout.num_dacs = 1;
 	spec->multiout.hp_nid = 0x11;
 	spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
+	if (spec->dinput_mux)
+		spec->private_dimux.num_items +=
+			spec->num_dmics -
+				(ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1);
 
 	err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
 	if (!err) {
diff --git a/sound/soc/at91/Kconfig b/sound/soc/at91/Kconfig
index 905186502e00..85a883299c2e 100644
--- a/sound/soc/at91/Kconfig
+++ b/sound/soc/at91/Kconfig
@@ -8,20 +8,3 @@ config SND_AT91_SOC
 
 config SND_AT91_SOC_SSC
 	tristate
-
-config SND_AT91_SOC_ETI_B1_WM8731
-	tristate "SoC Audio support for WM8731-based Endrelia ETI-B1 boards"
-	depends on SND_AT91_SOC && (MACH_ETI_B1 || MACH_ETI_C1)
-	select SND_AT91_SOC_SSC
-	select SND_SOC_WM8731
-	help
-	  Say Y if you want to add support for SoC audio on WM8731-based
-	  Endrelia Technologies Inc ETI-B1 or ETI-C1 boards.
-
-config SND_AT91_SOC_ETI_SLAVE
-	bool "Run codec in slave Mode on Endrelia boards"
-	depends on SND_AT91_SOC_ETI_B1_WM8731
-	default n
-	help
-	  Say Y if you want to run with the AT91 SSC generating the BCLK
-	  and LRC signals on Endrelia boards.
diff --git a/sound/soc/at91/Makefile b/sound/soc/at91/Makefile
index f23da17cc328..b817f11df286 100644
--- a/sound/soc/at91/Makefile
+++ b/sound/soc/at91/Makefile
@@ -4,8 +4,3 @@ snd-soc-at91-ssc-objs := at91-ssc.o
 
 obj-$(CONFIG_SND_AT91_SOC) += snd-soc-at91.o
 obj-$(CONFIG_SND_AT91_SOC_SSC) += snd-soc-at91-ssc.o
-
-# AT91 Machine Support
-snd-soc-eti-b1-wm8731-objs := eti_b1_wm8731.o
-
-obj-$(CONFIG_SND_AT91_SOC_ETI_B1_WM8731) += snd-soc-eti-b1-wm8731.o
diff --git a/sound/soc/at91/at91-ssc.c b/sound/soc/at91/at91-ssc.c
index a5b1a79ebffb..1b61cc461261 100644
--- a/sound/soc/at91/at91-ssc.c
+++ b/sound/soc/at91/at91-ssc.c
@@ -5,7 +5,7 @@
  *         Endrelia Technologies Inc.
  *
  * Based on pxa2xx Platform drivers by
- * Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
diff --git a/sound/soc/at91/eti_b1_wm8731.c b/sound/soc/at91/eti_b1_wm8731.c
deleted file mode 100644
index 684781e4088b..000000000000
--- a/sound/soc/at91/eti_b1_wm8731.c
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * eti_b1_wm8731  --  SoC audio for AT91RM9200-based Endrelia ETI_B1 board.
- *
- * Author:	Frank Mandarino <fmandarino@endrelia.com>
- *		Endrelia Technologies Inc.
- * Created:	Mar 29, 2006
- *
- * Based on corgi.c by:
- *
- * Copyright 2005 Wolfson Microelectronics PLC.
- * Copyright 2005 Openedhand Ltd.
- *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
- *          Richard Purdie <richard@openedhand.com>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/clk.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-
-#include "../codecs/wm8731.h"
-#include "at91-pcm.h"
-#include "at91-ssc.h"
-
-#if 0
-#define	DBG(x...)	printk(KERN_INFO "eti_b1_wm8731: " x)
-#else
-#define	DBG(x...)
-#endif
-
-static struct clk *pck1_clk;
-static struct clk *pllb_clk;
-
-
-static int eti_b1_startup(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-	int ret;
-
-	/* cpu clock is the AT91 master clock sent to the SSC */
-	ret = snd_soc_dai_set_sysclk(cpu_dai, AT91_SYSCLK_MCK,
-		60000000, SND_SOC_CLOCK_IN);
-	if (ret < 0)
-		return ret;
-
-	/* codec system clock is supplied by PCK1, set to 12MHz */
-	ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
-		12000000, SND_SOC_CLOCK_IN);
-	if (ret < 0)
-		return ret;
-
-	/* Start PCK1 clock. */
-	clk_enable(pck1_clk);
-	DBG("pck1 started\n");
-
-	return 0;
-}
-
-static void eti_b1_shutdown(struct snd_pcm_substream *substream)
-{
-	/* Stop PCK1 clock. */
-	clk_disable(pck1_clk);
-	DBG("pck1 stopped\n");
-}
-
-static int eti_b1_hw_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-	int ret;
-
-#ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE
-	unsigned int rate;
-	int cmr_div, period;
-
-	/* set codec DAI configuration */
-	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-	if (ret < 0)
-		return ret;
-
-	/* set cpu DAI configuration */
-	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-	if (ret < 0)
-		return ret;
-
-	/*
-	 * The SSC clock dividers depend on the sample rate.  The CMR.DIV
-	 * field divides the system master clock MCK to drive the SSC TK
-	 * signal which provides the codec BCLK.  The TCMR.PERIOD and
-	 * RCMR.PERIOD fields further divide the BCLK signal to drive
-	 * the SSC TF and RF signals which provide the codec DACLRC and
-	 * ADCLRC clocks.
-	 *
-	 * The dividers were determined through trial and error, where a
-	 * CMR.DIV value is chosen such that the resulting BCLK value is
-	 * divisible, or almost divisible, by (2 * sample rate), and then
-	 * the TCMR.PERIOD or RCMR.PERIOD is BCLK / (2 * sample rate) - 1.
-	 */
-	rate = params_rate(params);
-
-	switch (rate) {
-	case 8000:
-		cmr_div = 25;	/* BCLK = 60MHz/(2*25) = 1.2MHz */
-		period = 74;	/* LRC = BCLK/(2*(74+1)) = 8000Hz */
-		break;
-	case 32000:
-		cmr_div = 7;	/* BCLK = 60MHz/(2*7) ~= 4.28571428MHz */
-		period = 66;	/* LRC = BCLK/(2*(66+1)) = 31982.942Hz */
-		break;
-	case 48000:
-		cmr_div = 13;	/* BCLK = 60MHz/(2*13) ~= 2.3076923MHz */
-		period = 23;	/* LRC = BCLK/(2*(23+1)) = 48076.923Hz */
-		break;
-	default:
-		printk(KERN_WARNING "unsupported rate %d on ETI-B1 board\n", rate);
-		return -EINVAL;
-	}
-
-	/* set the MCK divider for BCLK */
-	ret = snd_soc_dai_set_clkdiv(cpu_dai, AT91SSC_CMR_DIV, cmr_div);
-	if (ret < 0)
-		return ret;
-
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		/* set the BCLK divider for DACLRC */
-		ret = snd_soc_dai_set_clkdiv(cpu_dai,
-						AT91SSC_TCMR_PERIOD, period);
-	} else {
-		/* set the BCLK divider for ADCLRC */
-		ret = snd_soc_dai_set_clkdiv(cpu_dai,
-						AT91SSC_RCMR_PERIOD, period);
-	}
-	if (ret < 0)
-		return ret;
-
-#else /* CONFIG_SND_AT91_SOC_ETI_SLAVE */
-	/*
-	 * Codec in Master Mode.
-	 */
-
-	/* set codec DAI configuration */
-	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-	if (ret < 0)
-		return ret;
-
-	/* set cpu DAI configuration */
-	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-	if (ret < 0)
-		return ret;
-
-#endif /* CONFIG_SND_AT91_SOC_ETI_SLAVE */
-
-	return 0;
-}
-
-static struct snd_soc_ops eti_b1_ops = {
-	.startup = eti_b1_startup,
-	.hw_params = eti_b1_hw_params,
-	.shutdown = eti_b1_shutdown,
-};
-
-
-static const struct snd_soc_dapm_widget eti_b1_dapm_widgets[] = {
-	SND_SOC_DAPM_MIC("Int Mic", NULL),
-	SND_SOC_DAPM_SPK("Ext Spk", NULL),
-};
-
-static const struct snd_soc_dapm_route intercon[] = {
-
-	/* speaker connected to LHPOUT */
-	{"Ext Spk", NULL, "LHPOUT"},
-
-	/* mic is connected to Mic Jack, with WM8731 Mic Bias */
-	{"MICIN", NULL, "Mic Bias"},
-	{"Mic Bias", NULL, "Int Mic"},
-};
-
-/*
- * Logic for a wm8731 as connected on a Endrelia ETI-B1 board.
- */
-static int eti_b1_wm8731_init(struct snd_soc_codec *codec)
-{
-	DBG("eti_b1_wm8731_init() called\n");
-
-	/* Add specific widgets */
-	snd_soc_dapm_new_controls(codec, eti_b1_dapm_widgets,
-				  ARRAY_SIZE(eti_b1_dapm_widgets));
-
-	/* Set up specific audio path interconnects */
-	snd_soc_dapm_add_route(codec, intercon, ARRAY_SIZE(intercon));
-
-	/* not connected */
-	snd_soc_dapm_disable_pin(codec, "RLINEIN");
-	snd_soc_dapm_disable_pin(codec, "LLINEIN");
-
-	/* always connected */
-	snd_soc_dapm_enable_pin(codec, "Int Mic");
-	snd_soc_dapm_enable_pin(codec, "Ext Spk");
-
-	snd_soc_dapm_sync(codec);
-
-	return 0;
-}
-
-static struct snd_soc_dai_link eti_b1_dai = {
-	.name = "WM8731",
-	.stream_name = "WM8731 PCM",
-	.cpu_dai = &at91_ssc_dai[1],
-	.codec_dai = &wm8731_dai,
-	.init = eti_b1_wm8731_init,
-	.ops = &eti_b1_ops,
-};
-
-static struct snd_soc_machine snd_soc_machine_eti_b1 = {
-	.name = "ETI_B1_WM8731",
-	.dai_link = &eti_b1_dai,
-	.num_links = 1,
-};
-
-static struct wm8731_setup_data eti_b1_wm8731_setup = {
-	.i2c_bus = 0,
-	.i2c_address = 0x1a,
-};
-
-static struct snd_soc_device eti_b1_snd_devdata = {
-	.machine = &snd_soc_machine_eti_b1,
-	.platform = &at91_soc_platform,
-	.codec_dev = &soc_codec_dev_wm8731,
-	.codec_data = &eti_b1_wm8731_setup,
-};
-
-static struct platform_device *eti_b1_snd_device;
-
-static int __init eti_b1_init(void)
-{
-	int ret;
-	struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data;
-
-	if (!request_mem_region(AT91RM9200_BASE_SSC1, SZ_16K, "soc-audio")) {
-		DBG("SSC1 memory region is busy\n");
-		return -EBUSY;
-	}
-
-	ssc->base = ioremap(AT91RM9200_BASE_SSC1, SZ_16K);
-	if (!ssc->base) {
-		DBG("SSC1 memory ioremap failed\n");
-		ret = -ENOMEM;
-		goto fail_release_mem;
-	}
-
-	ssc->pid = AT91RM9200_ID_SSC1;
-
-	eti_b1_snd_device = platform_device_alloc("soc-audio", -1);
-	if (!eti_b1_snd_device) {
-		DBG("platform device allocation failed\n");
-		ret = -ENOMEM;
-		goto fail_io_unmap;
-	}
-
-	platform_set_drvdata(eti_b1_snd_device, &eti_b1_snd_devdata);
-	eti_b1_snd_devdata.dev = &eti_b1_snd_device->dev;
-
-	ret = platform_device_add(eti_b1_snd_device);
-	if (ret) {
-		DBG("platform device add failed\n");
-		platform_device_put(eti_b1_snd_device);
-		goto fail_io_unmap;
-	}
-
-	at91_set_A_periph(AT91_PIN_PB6, 0);	/* TF1 */
-	at91_set_A_periph(AT91_PIN_PB7, 0);	/* TK1 */
-	at91_set_A_periph(AT91_PIN_PB8, 0);	/* TD1 */
-	at91_set_A_periph(AT91_PIN_PB9, 0);	/* RD1 */
-/*	at91_set_A_periph(AT91_PIN_PB10, 0);*/	/* RK1 */
-	at91_set_A_periph(AT91_PIN_PB11, 0);	/* RF1 */
-
-	/*
-	 * Set PCK1 parent to PLLB and its rate to 12 Mhz.
-	 */
-	pllb_clk = clk_get(NULL, "pllb");
-	pck1_clk = clk_get(NULL, "pck1");
-
-	clk_set_parent(pck1_clk, pllb_clk);
-	clk_set_rate(pck1_clk, 12000000);
-
-	DBG("MCLK rate %luHz\n", clk_get_rate(pck1_clk));
-
-	/* assign the GPIO pin to PCK1 */
-	at91_set_B_periph(AT91_PIN_PA24, 0);
-
-#ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE
-	printk(KERN_INFO "eti_b1_wm8731: Codec in Slave Mode\n");
-#else
-	printk(KERN_INFO "eti_b1_wm8731: Codec in Master Mode\n");
-#endif
-	return ret;
-
-fail_io_unmap:
-	iounmap(ssc->base);
-fail_release_mem:
-	release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K);
-	return ret;
-}
-
-static void __exit eti_b1_exit(void)
-{
-	struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data;
-
-	clk_put(pck1_clk);
-	clk_put(pllb_clk);
-
-	platform_device_unregister(eti_b1_snd_device);
-
-	iounmap(ssc->base);
-	release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K);
-}
-
-module_init(eti_b1_init);
-module_exit(eti_b1_exit);
-
-/* Module information */
-MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>");
-MODULE_DESCRIPTION("ALSA SoC ETI-B1-WM8731");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig
index f98331d099e7..dc006206f622 100644
--- a/sound/soc/blackfin/Kconfig
+++ b/sound/soc/blackfin/Kconfig
@@ -17,6 +17,22 @@ config SND_BF5XX_SOC_SSM2602
 	help
 	  Say Y if you want to add support for SoC audio on BF527-EZKIT.
 
+config SND_BF5XX_SOC_AD73311
+	tristate "SoC AD73311 Audio support for Blackfin"
+	depends on SND_BF5XX_I2S
+	select SND_BF5XX_SOC_I2S
+	select SND_SOC_AD73311
+	help
+	  Say Y if you want to add support for AD73311 codec on Blackfin.
+
+config SND_BFIN_AD73311_SE
+	int "PF pin for AD73311L Chip Select"
+	depends on SND_BF5XX_SOC_AD73311
+	default 4
+	help
+	  Enter the GPIO used to control AD73311's SE pin. Acceptable
+	  values are 0 to 7
+
 config SND_BF5XX_AC97
 	tristate "SoC AC97 Audio for the ADI BF5xx chip"
 	depends on BLACKFIN && SND_SOC
diff --git a/sound/soc/blackfin/Makefile b/sound/soc/blackfin/Makefile
index 9ea8bd9e0ba3..97bb37a6359c 100644
--- a/sound/soc/blackfin/Makefile
+++ b/sound/soc/blackfin/Makefile
@@ -14,7 +14,8 @@ obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o
 # Blackfin Machine Support
 snd-ad1980-objs := bf5xx-ad1980.o
 snd-ssm2602-objs := bf5xx-ssm2602.o
-
+snd-ad73311-objs := bf5xx-ad73311.o
 
 obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o
 obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o
+obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c
index 51f4907c4831..25e50d2ea1ec 100644
--- a/sound/soc/blackfin/bf5xx-ac97-pcm.c
+++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c
@@ -56,6 +56,7 @@ static void bf5xx_mmap_copy(struct snd_pcm_substream *substream,
 		sport->tx_pos += runtime->period_size;
 		if (sport->tx_pos >= runtime->buffer_size)
 			sport->tx_pos %= runtime->buffer_size;
+		sport->tx_delay_pos = sport->tx_pos;
 	} else {
 		bf5xx_ac97_to_pcm(
 			(struct ac97_frame *)sport->rx_dma_buf + sport->rx_pos,
@@ -72,7 +73,15 @@ static void bf5xx_dma_irq(void *data)
 	struct snd_pcm_substream *pcm = data;
 #if defined(CONFIG_SND_MMAP_SUPPORT)
 	struct snd_pcm_runtime *runtime = pcm->runtime;
+	struct sport_device *sport = runtime->private_data;
 	bf5xx_mmap_copy(pcm, runtime->period_size);
+	if (pcm->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (sport->once == 0) {
+			snd_pcm_period_elapsed(pcm);
+			bf5xx_mmap_copy(pcm, runtime->period_size);
+			sport->once = 1;
+		}
+	}
 #endif
 	snd_pcm_period_elapsed(pcm);
 }
@@ -114,6 +123,10 @@ static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
 
 static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
 {
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+	memset(runtime->dma_area, 0, runtime->buffer_size);
 	snd_pcm_lib_free_pages(substream);
 	return 0;
 }
@@ -127,16 +140,11 @@ static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
 	 * SPORT working in TMD mode(include AC97).
 	 */
 #if defined(CONFIG_SND_MMAP_SUPPORT)
-	size_t size = bf5xx_pcm_hardware.buffer_bytes_max
-			* sizeof(struct ac97_frame) / 4;
-	/*clean up intermediate buffer*/
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		memset(sport->tx_dma_buf, 0, size);
 		sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
 		sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods,
 			runtime->period_size * sizeof(struct ac97_frame));
 	} else {
-		memset(sport->rx_dma_buf, 0, size);
 		sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
 		sport_config_rx_dma(sport, sport->rx_dma_buf, runtime->periods,
 			runtime->period_size * sizeof(struct ac97_frame));
@@ -164,8 +172,12 @@ static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 	pr_debug("%s enter\n", __func__);
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			bf5xx_mmap_copy(substream, runtime->period_size);
+			snd_pcm_period_elapsed(substream);
+			sport->tx_delay_pos = 0;
 			sport_tx_start(sport);
+		}
 		else
 			sport_rx_start(sport);
 		break;
@@ -198,7 +210,7 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
 
 #if defined(CONFIG_SND_MMAP_SUPPORT)
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		curr = sport->tx_pos;
+		curr = sport->tx_delay_pos;
 	else
 		curr = sport->rx_pos;
 #else
@@ -237,6 +249,21 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 	return ret;
 }
 
+static int bf5xx_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct sport_device *sport = runtime->private_data;
+
+	pr_debug("%s enter\n", __func__);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		sport->once = 0;
+		memset(sport->tx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame));
+	} else
+		memset(sport->rx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame));
+
+	return 0;
+}
+
 #ifdef CONFIG_SND_MMAP_SUPPORT
 static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream,
 	struct vm_area_struct *vma)
@@ -272,6 +299,7 @@ static	int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
 
 struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
 	.open		= bf5xx_pcm_open,
+	.close		= bf5xx_pcm_close,
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= bf5xx_pcm_hw_params,
 	.hw_free	= bf5xx_pcm_hw_free,
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c
index c782e311fd56..5e5aafb6485f 100644
--- a/sound/soc/blackfin/bf5xx-ac97.c
+++ b/sound/soc/blackfin/bf5xx-ac97.c
@@ -129,7 +129,6 @@ static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
 	struct ac97_frame *nextwrite;
 
 	sport_incfrag(sport, &nextfrag, 1);
-	sport_incfrag(sport, &nextfrag, 1);
 
 	nextwrite = (struct ac97_frame *)(sport->tx_buf + \
 			nextfrag * sport->tx_fragsize);
diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c
new file mode 100644
index 000000000000..622c9b909532
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-ad73311.c
@@ -0,0 +1,240 @@
+/*
+ * File:         sound/soc/blackfin/bf5xx-ad73311.c
+ * Author:       Cliff Cai <Cliff.Cai@analog.com>
+ *
+ * Created:      Thur Sep 25 2008
+ * Description:  Board driver for ad73311 sound chip
+ *
+ * Modified:
+ *               Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm_params.h>
+
+#include <asm/blackfin.h>
+#include <asm/cacheflush.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+
+#include "../codecs/ad73311.h"
+#include "bf5xx-sport.h"
+#include "bf5xx-i2s-pcm.h"
+#include "bf5xx-i2s.h"
+
+#if CONFIG_SND_BF5XX_SPORT_NUM == 0
+#define bfin_write_SPORT_TCR1	bfin_write_SPORT0_TCR1
+#define bfin_read_SPORT_TCR1	bfin_read_SPORT0_TCR1
+#define bfin_write_SPORT_TCR2	bfin_write_SPORT0_TCR2
+#define bfin_write_SPORT_TX16	bfin_write_SPORT0_TX16
+#define bfin_read_SPORT_STAT	bfin_read_SPORT0_STAT
+#else
+#define bfin_write_SPORT_TCR1	bfin_write_SPORT1_TCR1
+#define bfin_read_SPORT_TCR1	bfin_read_SPORT1_TCR1
+#define bfin_write_SPORT_TCR2	bfin_write_SPORT1_TCR2
+#define bfin_write_SPORT_TX16	bfin_write_SPORT1_TX16
+#define bfin_read_SPORT_STAT	bfin_read_SPORT1_STAT
+#endif
+
+#define GPIO_SE CONFIG_SND_BFIN_AD73311_SE
+
+static struct snd_soc_machine bf5xx_ad73311;
+
+static int snd_ad73311_startup(void)
+{
+	pr_debug("%s enter\n", __func__);
+
+	/* Pull up SE pin on AD73311L */
+	gpio_set_value(GPIO_SE, 1);
+	return 0;
+}
+
+static int snd_ad73311_configure(void)
+{
+	unsigned short ctrl_regs[6];
+	unsigned short status = 0;
+	int count = 0;
+
+	/* DMCLK = MCLK = 16.384 MHz
+	 * SCLK = DMCLK/8 = 2.048 MHz
+	 * Sample Rate = DMCLK/2048  = 8 KHz
+	 */
+	ctrl_regs[0] = AD_CONTROL | AD_WRITE | CTRL_REG_B | REGB_MCDIV(0) | \
+			REGB_SCDIV(0) | REGB_DIRATE(0);
+	ctrl_regs[1] = AD_CONTROL | AD_WRITE | CTRL_REG_C | REGC_PUDEV | \
+			REGC_PUADC | REGC_PUDAC | REGC_PUREF | REGC_REFUSE ;
+	ctrl_regs[2] = AD_CONTROL | AD_WRITE | CTRL_REG_D | REGD_OGS(2) | \
+			REGD_IGS(2);
+	ctrl_regs[3] = AD_CONTROL | AD_WRITE | CTRL_REG_E | REGE_DA(0x1f);
+	ctrl_regs[4] = AD_CONTROL | AD_WRITE | CTRL_REG_F | REGF_SEEN ;
+	ctrl_regs[5] = AD_CONTROL | AD_WRITE | CTRL_REG_A | REGA_MODE_DATA;
+
+	local_irq_disable();
+	snd_ad73311_startup();
+	udelay(1);
+
+	bfin_write_SPORT_TCR1(TFSR);
+	bfin_write_SPORT_TCR2(0xF);
+	SSYNC();
+
+	/* SPORT Tx Register is a 8 x 16 FIFO, all the data can be put to
+	 * FIFO before enable SPORT to transfer the data
+	 */
+	for (count = 0; count < 6; count++)
+		bfin_write_SPORT_TX16(ctrl_regs[count]);
+	SSYNC();
+	bfin_write_SPORT_TCR1(bfin_read_SPORT_TCR1() | TSPEN);
+	SSYNC();
+
+	/* When TUVF is set, the data is already send out */
+	while (!(status & TUVF) && count++ < 10000) {
+		udelay(1);
+		status = bfin_read_SPORT_STAT();
+		SSYNC();
+	}
+	bfin_write_SPORT_TCR1(bfin_read_SPORT_TCR1() & ~TSPEN);
+	SSYNC();
+	local_irq_enable();
+
+	if (count == 10000) {
+		printk(KERN_ERR "ad73311: failed to configure codec\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int bf5xx_probe(struct platform_device *pdev)
+{
+	int err;
+	if (gpio_request(GPIO_SE, "AD73311_SE")) {
+		printk(KERN_ERR "%s: Failed ro request GPIO_%d\n", __func__, GPIO_SE);
+		return -EBUSY;
+	}
+
+	gpio_direction_output(GPIO_SE, 0);
+
+	err = snd_ad73311_configure();
+	if (err < 0)
+		return -EFAULT;
+
+	return 0;
+}
+
+static int bf5xx_ad73311_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+
+	pr_debug("%s enter\n", __func__);
+	cpu_dai->private_data = sport_handle;
+	return 0;
+}
+
+static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	int ret = 0;
+
+	pr_debug("%s rate %d format %x\n", __func__, params_rate(params),
+		params_format(params));
+
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+
+static struct snd_soc_ops bf5xx_ad73311_ops = {
+	.startup = bf5xx_ad73311_startup,
+	.hw_params = bf5xx_ad73311_hw_params,
+};
+
+static struct snd_soc_dai_link bf5xx_ad73311_dai = {
+	.name = "ad73311",
+	.stream_name = "AD73311",
+	.cpu_dai = &bf5xx_i2s_dai,
+	.codec_dai = &ad73311_dai,
+	.ops = &bf5xx_ad73311_ops,
+};
+
+static struct snd_soc_machine bf5xx_ad73311 = {
+	.name = "bf5xx_ad73311",
+	.probe = bf5xx_probe,
+	.dai_link = &bf5xx_ad73311_dai,
+	.num_links = 1,
+};
+
+static struct snd_soc_device bf5xx_ad73311_snd_devdata = {
+	.machine = &bf5xx_ad73311,
+	.platform = &bf5xx_i2s_soc_platform,
+	.codec_dev = &soc_codec_dev_ad73311,
+};
+
+static struct platform_device *bf52x_ad73311_snd_device;
+
+static int __init bf5xx_ad73311_init(void)
+{
+	int ret;
+
+	pr_debug("%s enter\n", __func__);
+	bf52x_ad73311_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!bf52x_ad73311_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(bf52x_ad73311_snd_device, &bf5xx_ad73311_snd_devdata);
+	bf5xx_ad73311_snd_devdata.dev = &bf52x_ad73311_snd_device->dev;
+	ret = platform_device_add(bf52x_ad73311_snd_device);
+
+	if (ret)
+		platform_device_put(bf52x_ad73311_snd_device);
+
+	return ret;
+}
+
+static void __exit bf5xx_ad73311_exit(void)
+{
+	pr_debug("%s enter\n", __func__);
+	platform_device_unregister(bf52x_ad73311_snd_device);
+}
+
+module_init(bf5xx_ad73311_init);
+module_exit(bf5xx_ad73311_exit);
+
+/* Module information */
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("ALSA SoC AD73311 Blackfin");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c
index 43a4092eeb89..827587f08180 100644
--- a/sound/soc/blackfin/bf5xx-i2s.c
+++ b/sound/soc/blackfin/bf5xx-i2s.c
@@ -70,6 +70,13 @@ static struct sport_param sport_params[2] = {
 	}
 };
 
+static u16 sport_req[][7] = {
+		{ P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+		  P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0},
+		{ P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+		  P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0},
+};
+
 static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 		unsigned int fmt)
 {
@@ -78,6 +85,14 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 	/* interface format:support I2S,slave mode */
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
+		bf5xx_i2s.tcr1 |= TFSR | TCKFE;
+		bf5xx_i2s.rcr1 |= RFSR | RCKFE;
+		bf5xx_i2s.tcr2 |= TSFSE;
+		bf5xx_i2s.rcr2 |= RSFSE;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		bf5xx_i2s.tcr1 |= TFSR;
+		bf5xx_i2s.rcr1 |= RFSR;
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
 		ret = -EINVAL;
@@ -127,14 +142,17 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_FORMAT_S16_LE:
 		bf5xx_i2s.tcr2 |= 15;
 		bf5xx_i2s.rcr2 |= 15;
+		sport_handle->wdsize = 2;
 		break;
 	case SNDRV_PCM_FORMAT_S24_LE:
 		bf5xx_i2s.tcr2 |= 23;
 		bf5xx_i2s.rcr2 |= 23;
+		sport_handle->wdsize = 3;
 		break;
 	case SNDRV_PCM_FORMAT_S32_LE:
 		bf5xx_i2s.tcr2 |= 31;
 		bf5xx_i2s.rcr2 |= 31;
+		sport_handle->wdsize = 4;
 		break;
 	}
 
@@ -145,17 +163,17 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
 		 * need to configure both of them at the time when the first
 		 * stream is opened.
 		 *
-		 * CPU DAI format:I2S, slave mode.
+		 * CPU DAI:slave mode.
 		 */
-		ret = sport_config_rx(sport_handle, RFSR | RCKFE,
-				      RSFSE|bf5xx_i2s.rcr2, 0, 0);
+		ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1,
+				      bf5xx_i2s.rcr2, 0, 0);
 		if (ret) {
 			pr_err("SPORT is busy!\n");
 			return -EBUSY;
 		}
 
-		ret = sport_config_tx(sport_handle, TFSR | TCKFE,
-				      TSFSE|bf5xx_i2s.tcr2, 0, 0);
+		ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1,
+				      bf5xx_i2s.tcr2, 0, 0);
 		if (ret) {
 			pr_err("SPORT is busy!\n");
 			return -EBUSY;
@@ -174,13 +192,6 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream)
 static int bf5xx_i2s_probe(struct platform_device *pdev,
 			   struct snd_soc_dai *dai)
 {
-	u16 sport_req[][7] = {
-		{ P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
-		  P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0},
-		{ P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
-		  P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0},
-	};
-
 	pr_debug("%s enter\n", __func__);
 	if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
 		pr_err("Requesting Peripherals failed\n");
@@ -198,6 +209,13 @@ static int bf5xx_i2s_probe(struct platform_device *pdev,
 	return 0;
 }
 
+static void bf5xx_i2s_remove(struct platform_device *pdev,
+			   struct snd_soc_dai *dai)
+{
+	pr_debug("%s enter\n", __func__);
+	peripheral_free_list(&sport_req[sport_num][0]);
+}
+
 #ifdef CONFIG_PM
 static int bf5xx_i2s_suspend(struct platform_device *dev,
 			     struct snd_soc_dai *dai)
@@ -263,15 +281,16 @@ struct snd_soc_dai bf5xx_i2s_dai = {
 	.id = 0,
 	.type = SND_SOC_DAI_I2S,
 	.probe = bf5xx_i2s_probe,
+	.remove = bf5xx_i2s_remove,
 	.suspend = bf5xx_i2s_suspend,
 	.resume = bf5xx_i2s_resume,
 	.playback = {
-		.channels_min = 2,
+		.channels_min = 1,
 		.channels_max = 2,
 		.rates = BF5XX_I2S_RATES,
 		.formats = BF5XX_I2S_FORMATS,},
 	.capture = {
-		.channels_min = 2,
+		.channels_min = 1,
 		.channels_max = 2,
 		.rates = BF5XX_I2S_RATES,
 		.formats = BF5XX_I2S_FORMATS,},
diff --git a/sound/soc/blackfin/bf5xx-sport.h b/sound/soc/blackfin/bf5xx-sport.h
index 4c163454bbf8..fcadcc081f7f 100644
--- a/sound/soc/blackfin/bf5xx-sport.h
+++ b/sound/soc/blackfin/bf5xx-sport.h
@@ -123,6 +123,8 @@ struct sport_device {
 	int rx_pos;
 	unsigned int tx_buffer_size;
 	unsigned int rx_buffer_size;
+	int tx_delay_pos;
+	int once;
 #endif
 	void *private_data;
 };
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index e0b9869df0f1..4975d8573e4f 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -3,9 +3,11 @@ config SND_SOC_ALL_CODECS
 	depends on I2C
 	select SPI
 	select SPI_MASTER
+	select SND_SOC_AD73311
 	select SND_SOC_AK4535
 	select SND_SOC_CS4270
 	select SND_SOC_SSM2602
+	select SND_SOC_TLV320AIC23
 	select SND_SOC_TLV320AIC26
 	select SND_SOC_TLV320AIC3X
 	select SND_SOC_UDA1380
@@ -34,6 +36,9 @@ config SND_SOC_AC97_CODEC
 config SND_SOC_AD1980
 	tristate
 
+config SND_SOC_AD73311
+	tristate
+
 config SND_SOC_AK4535
 	tristate
 
@@ -58,9 +63,13 @@ config SND_SOC_CS4270_VD33_ERRATA
 config SND_SOC_SSM2602
 	tristate
 
+config SND_SOC_TLV320AIC23
+	tristate
+	depends on I2C
+
 config SND_SOC_TLV320AIC26
 	tristate "TI TLV320AIC26 Codec support"
-	depends on SND_SOC && SPI
+	depends on SPI
 
 config SND_SOC_TLV320AIC3X
 	tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index f977978a3409..90f0a585fc70 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -1,8 +1,10 @@
 snd-soc-ac97-objs := ac97.o
 snd-soc-ad1980-objs := ad1980.o
+snd-soc-ad73311-objs := ad73311.o
 snd-soc-ak4535-objs := ak4535.o
 snd-soc-cs4270-objs := cs4270.o
 snd-soc-ssm2602-objs := ssm2602.o
+snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 snd-soc-uda1380-objs := uda1380.o
@@ -20,9 +22,11 @@ snd-soc-wm9713-objs := wm9713.o
 
 obj-$(CONFIG_SND_SOC_AC97_CODEC)	+= snd-soc-ac97.o
 obj-$(CONFIG_SND_SOC_AD1980)	+= snd-soc-ad1980.o
+obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
 obj-$(CONFIG_SND_SOC_AK4535)	+= snd-soc-ak4535.o
 obj-$(CONFIG_SND_SOC_CS4270)	+= snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_SSM2602)	+= snd-soc-ssm2602.o
+obj-$(CONFIG_SND_SOC_TLV320AIC23)	+= snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC26)	+= snd-soc-tlv320aic26.o
 obj-$(CONFIG_SND_SOC_TLV320AIC3X)	+= snd-soc-tlv320aic3x.o
 obj-$(CONFIG_SND_SOC_UDA1380)	+= snd-soc-uda1380.o
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index 61fd96ca7bc7..bd1ebdc6c86c 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -2,8 +2,7 @@
  * ac97.c  --  ALSA Soc AC97 codec support
  *
  * Copyright 2005 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index 4e09c1f2c063..1397b8e06c0b 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -13,7 +13,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/device.h>
 #include <sound/core.h>
diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c
new file mode 100644
index 000000000000..37af8607b00a
--- /dev/null
+++ b/sound/soc/codecs/ad73311.c
@@ -0,0 +1,107 @@
+/*
+ * ad73311.c  --  ALSA Soc AD73311 codec support
+ *
+ * Copyright:	Analog Device Inc.
+ * Author:	Cliff Cai <cliff.cai@analog.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    25th Sep 2008   Initial version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "ad73311.h"
+
+struct snd_soc_dai ad73311_dai = {
+	.name = "AD73311",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
+};
+EXPORT_SYMBOL_GPL(ad73311_dai);
+
+static int ad73311_soc_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	int ret = 0;
+
+	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (codec == NULL)
+		return -ENOMEM;
+	mutex_init(&codec->mutex);
+	codec->name = "AD73311";
+	codec->owner = THIS_MODULE;
+	codec->dai = &ad73311_dai;
+	codec->num_dai = 1;
+	socdev->codec = codec;
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		printk(KERN_ERR "ad73311: failed to create pcms\n");
+		goto pcm_err;
+	}
+
+	ret = snd_soc_register_card(socdev);
+	if (ret < 0) {
+		printk(KERN_ERR "ad73311: failed to register card\n");
+		goto register_err;
+	}
+
+	return ret;
+
+register_err:
+	snd_soc_free_pcms(socdev);
+pcm_err:
+	kfree(socdev->codec);
+	socdev->codec = NULL;
+	return ret;
+}
+
+static int ad73311_soc_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	if (codec == NULL)
+		return 0;
+	snd_soc_free_pcms(socdev);
+	kfree(codec);
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_ad73311 = {
+	.probe = 	ad73311_soc_probe,
+	.remove = 	ad73311_soc_remove,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_ad73311);
+
+MODULE_DESCRIPTION("ASoC ad73311 driver");
+MODULE_AUTHOR("Cliff Cai ");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ad73311.h b/sound/soc/codecs/ad73311.h
new file mode 100644
index 000000000000..507ce0c30edf
--- /dev/null
+++ b/sound/soc/codecs/ad73311.h
@@ -0,0 +1,90 @@
+/*
+ * File:         sound/soc/codec/ad73311.h
+ * Based on:
+ * Author:       Cliff Cai <cliff.cai@analog.com>
+ *
+ * Created:      Thur Sep 25, 2008
+ * Description:  definitions for AD73311 registers
+ *
+ *
+ * Modified:
+ *               Copyright 2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __AD73311_H__
+#define __AD73311_H__
+
+#define AD_CONTROL	0x8000
+#define AD_DATA		0x0000
+#define AD_READ		0x4000
+#define AD_WRITE	0x0000
+
+/* Control register A */
+#define CTRL_REG_A	(0 << 8)
+
+#define REGA_MODE_PRO	0x00
+#define REGA_MODE_DATA	0x01
+#define REGA_MODE_MIXED	0x03
+#define REGA_DLB		0x04
+#define REGA_SLB		0x08
+#define REGA_DEVC(x)		((x & 0x7) << 4)
+#define REGA_RESET		0x80
+
+/* Control register B */
+#define CTRL_REG_B	(1 << 8)
+
+#define REGB_DIRATE(x)	(x & 0x3)
+#define REGB_SCDIV(x)	((x & 0x3) << 2)
+#define REGB_MCDIV(x)	((x & 0x7) << 4)
+#define REGB_CEE		(1 << 7)
+
+/* Control register C */
+#define CTRL_REG_C	(2 << 8)
+
+#define REGC_PUDEV		(1 << 0)
+#define REGC_PUADC		(1 << 3)
+#define REGC_PUDAC		(1 << 4)
+#define REGC_PUREF		(1 << 5)
+#define REGC_REFUSE		(1 << 6)
+
+/* Control register D */
+#define CTRL_REG_D	(3 << 8)
+
+#define REGD_IGS(x)		(x & 0x7)
+#define REGD_RMOD		(1 << 3)
+#define REGD_OGS(x)		((x & 0x7) << 4)
+#define REGD_MUTE		(x << 7)
+
+/* Control register E */
+#define CTRL_REG_E	(4 << 8)
+
+#define REGE_DA(x)		(x & 0x1f)
+#define REGE_IBYP		(1 << 5)
+
+/* Control register F */
+#define CTRL_REG_F	(5 << 8)
+
+#define REGF_SEEN		(1 << 5)
+#define REGF_INV		(1 << 6)
+#define REGF_ALB		(1 << 7)
+
+extern struct snd_soc_dai ad73311_dai;
+extern struct snd_soc_codec_device soc_codec_dev_ad73311;
+#endif
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index 088cf9927720..2a89b5888e11 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -28,7 +28,6 @@
 
 #include "ak4535.h"
 
-#define AUDIO_NAME "ak4535"
 #define AK4535_VERSION "0.3"
 
 struct snd_soc_codec_device soc_codec_dev_ak4535;
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 940ce1c3522e..44ef0dacd564 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -42,7 +42,6 @@
 
 #include "ssm2602.h"
 
-#define AUDIO_NAME "ssm2602"
 #define SSM2602_VERSION "0.1"
 
 struct snd_soc_codec_device soc_codec_dev_ssm2602;
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
new file mode 100644
index 000000000000..bac7815e00fb
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -0,0 +1,714 @@
+/*
+ * ALSA SoC TLV320AIC23 codec driver
+ *
+ * Author:      Arun KS, <arunks@mistralsolutions.com>
+ * Copyright:   (C) 2008 Mistral Solutions Pvt Ltd.,
+ *
+ * Based on sound/soc/codecs/wm8731.c by Richard Purdie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Notes:
+ *  The AIC23 is a driver for a low power stereo audio
+ *  codec tlv320aic23
+ *
+ *  The machine layer should disable unsupported inputs/outputs by
+ *  snd_soc_dapm_disable_pin(codec, "LHPOUT"), etc.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+
+#include "tlv320aic23.h"
+
+#define AIC23_VERSION "0.1"
+
+struct tlv320aic23_srate_reg_info {
+	u32 sample_rate;
+	u8 control;		/* SR3, SR2, SR1, SR0 and BOSR */
+	u8 divider;		/* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */
+};
+
+/*
+ * AIC23 register cache
+ */
+static const u16 tlv320aic23_reg[] = {
+	0x0097, 0x0097, 0x00F9, 0x00F9,	/* 0 */
+	0x001A, 0x0004, 0x0007, 0x0001,	/* 4 */
+	0x0020, 0x0000, 0x0000, 0x0000,	/* 8 */
+	0x0000, 0x0000, 0x0000, 0x0000,	/* 12 */
+};
+
+/*
+ * read tlv320aic23 register cache
+ */
+static inline unsigned int tlv320aic23_read_reg_cache(struct snd_soc_codec
+						      *codec, unsigned int reg)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg >= ARRAY_SIZE(tlv320aic23_reg))
+		return -1;
+	return cache[reg];
+}
+
+/*
+ * write tlv320aic23 register cache
+ */
+static inline void tlv320aic23_write_reg_cache(struct snd_soc_codec *codec,
+					       u8 reg, u16 value)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg >= ARRAY_SIZE(tlv320aic23_reg))
+		return;
+	cache[reg] = value;
+}
+
+/*
+ * write to the tlv320aic23 register space
+ */
+static int tlv320aic23_write(struct snd_soc_codec *codec, unsigned int reg,
+			     unsigned int value)
+{
+
+	u8 data;
+
+	/* TLV320AIC23 has 7 bit address and 9 bits of data
+	 * so we need to switch one data bit into reg and rest
+	 * of data into val
+	 */
+
+	if ((reg < 0 || reg > 9) && (reg != 15)) {
+		printk(KERN_WARNING "%s Invalid register R%d\n", __func__, reg);
+		return -1;
+	}
+
+	data = (reg << 1) | (value >> 8 & 0x01);
+
+	tlv320aic23_write_reg_cache(codec, reg, value);
+
+	if (codec->hw_write(codec->control_data, data,
+			    (value & 0xff)) == 0)
+		return 0;
+
+	printk(KERN_ERR "%s cannot write %03x to register R%d\n", __func__,
+	       value, reg);
+
+	return -EIO;
+}
+
+static const char *rec_src_text[] = { "Line", "Mic" };
+static const char *deemph_text[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+
+static const struct soc_enum rec_src_enum =
+	SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text);
+
+static const struct snd_kcontrol_new tlv320aic23_rec_src_mux_controls =
+SOC_DAPM_ENUM("Input Select", rec_src_enum);
+
+static const struct soc_enum tlv320aic23_rec_src =
+	SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text);
+static const struct soc_enum tlv320aic23_deemph =
+	SOC_ENUM_SINGLE(TLV320AIC23_DIGT, 1, 4, deemph_text);
+
+static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -12100, 100, 0);
+static const DECLARE_TLV_DB_SCALE(input_gain_tlv, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(sidetone_vol_tlv, -1800, 300, 0);
+
+static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	u16 val, reg;
+
+	val = (ucontrol->value.integer.value[0] & 0x07);
+
+	/* linear conversion to userspace
+	* 000	=	-6db
+	* 001	=	-9db
+	* 010	=	-12db
+	* 011	=	-18db (Min)
+	* 100	=	0db (Max)
+	*/
+	val = (val >= 4) ? 4  : (3 - val);
+
+	reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG) & (~0x1C0);
+	tlv320aic23_write(codec, TLV320AIC23_ANLG, reg | (val << 6));
+
+	return 0;
+}
+
+static int snd_soc_tlv320aic23_get_volsw(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	u16 val;
+
+	val = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG) & (0x1C0);
+	val = val >> 6;
+	val = (val >= 4) ? 4  : (3 -  val);
+	ucontrol->value.integer.value[0] = val;
+	return 0;
+
+}
+
+#define SOC_TLV320AIC23_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+		 SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+	.tlv.p = (tlv_array), \
+	.info = snd_soc_info_volsw, .get = snd_soc_tlv320aic23_get_volsw,\
+	.put = snd_soc_tlv320aic23_put_volsw, \
+	.private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+
+static const struct snd_kcontrol_new tlv320aic23_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("Digital Playback Volume", TLV320AIC23_LCHNVOL,
+			 TLV320AIC23_RCHNVOL, 0, 127, 0, out_gain_tlv),
+	SOC_SINGLE("Digital Playback Switch", TLV320AIC23_DIGT, 3, 1, 1),
+	SOC_DOUBLE_R("Line Input Switch", TLV320AIC23_LINVOL,
+		     TLV320AIC23_RINVOL, 7, 1, 0),
+	SOC_DOUBLE_R_TLV("Line Input Volume", TLV320AIC23_LINVOL,
+			 TLV320AIC23_RINVOL, 0, 31, 0, input_gain_tlv),
+	SOC_SINGLE("Mic Input Switch", TLV320AIC23_ANLG, 1, 1, 1),
+	SOC_SINGLE("Mic Booster Switch", TLV320AIC23_ANLG, 0, 1, 0),
+	SOC_TLV320AIC23_SINGLE_TLV("Sidetone Volume", TLV320AIC23_ANLG,
+				  6, 4, 0, sidetone_vol_tlv),
+	SOC_ENUM("Playback De-emphasis", tlv320aic23_deemph),
+};
+
+/* add non dapm controls */
+static int tlv320aic23_add_controls(struct snd_soc_codec *codec)
+{
+
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(tlv320aic23_snd_controls); i++) {
+		err = snd_ctl_add(codec->card,
+				  snd_soc_cnew(&tlv320aic23_snd_controls[i],
+					       codec, NULL));
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+
+}
+
+/* PGA Mixer controls for Line and Mic switch */
+static const struct snd_kcontrol_new tlv320aic23_output_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Line Bypass Switch", TLV320AIC23_ANLG, 3, 1, 0),
+	SOC_DAPM_SINGLE("Mic Sidetone Switch", TLV320AIC23_ANLG, 5, 1, 0),
+	SOC_DAPM_SINGLE("Playback Switch", TLV320AIC23_ANLG, 4, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC", "Playback", TLV320AIC23_PWR, 3, 1),
+	SND_SOC_DAPM_ADC("ADC", "Capture", TLV320AIC23_PWR, 2, 1),
+	SND_SOC_DAPM_MUX("Capture Source", SND_SOC_NOPM, 0, 0,
+			 &tlv320aic23_rec_src_mux_controls),
+	SND_SOC_DAPM_MIXER("Output Mixer", TLV320AIC23_PWR, 4, 1,
+			   &tlv320aic23_output_mixer_controls[0],
+			   ARRAY_SIZE(tlv320aic23_output_mixer_controls)),
+	SND_SOC_DAPM_PGA("Line Input", TLV320AIC23_PWR, 0, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("Mic Input", TLV320AIC23_PWR, 1, 1, NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("LHPOUT"),
+	SND_SOC_DAPM_OUTPUT("RHPOUT"),
+	SND_SOC_DAPM_OUTPUT("LOUT"),
+	SND_SOC_DAPM_OUTPUT("ROUT"),
+
+	SND_SOC_DAPM_INPUT("LLINEIN"),
+	SND_SOC_DAPM_INPUT("RLINEIN"),
+
+	SND_SOC_DAPM_INPUT("MICIN"),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+	/* Output Mixer */
+	{"Output Mixer", "Line Bypass Switch", "Line Input"},
+	{"Output Mixer", "Playback Switch", "DAC"},
+	{"Output Mixer", "Mic Sidetone Switch", "Mic Input"},
+
+	/* Outputs */
+	{"RHPOUT", NULL, "Output Mixer"},
+	{"LHPOUT", NULL, "Output Mixer"},
+	{"LOUT", NULL, "Output Mixer"},
+	{"ROUT", NULL, "Output Mixer"},
+
+	/* Inputs */
+	{"Line Input", "NULL", "LLINEIN"},
+	{"Line Input", "NULL", "RLINEIN"},
+
+	{"Mic Input", "NULL", "MICIN"},
+
+	/* input mux */
+	{"Capture Source", "Line", "Line Input"},
+	{"Capture Source", "Mic", "Mic Input"},
+	{"ADC", NULL, "Capture Source"},
+
+};
+
+/* tlv320aic23 related */
+static const struct tlv320aic23_srate_reg_info srate_reg_info[] = {
+	{4000, 0x06, 1},	/*  4000 */
+	{8000, 0x06, 0},	/*  8000 */
+	{16000, 0x0C, 1},	/* 16000 */
+	{22050, 0x11, 1},	/* 22050 */
+	{24000, 0x00, 1},	/* 24000 */
+	{32000, 0x0C, 0},	/* 32000 */
+	{44100, 0x11, 0},	/* 44100 */
+	{48000, 0x00, 0},	/* 48000 */
+	{88200, 0x1F, 0},	/* 88200 */
+	{96000, 0x0E, 0},	/* 96000 */
+};
+
+static int tlv320aic23_add_widgets(struct snd_soc_codec *codec)
+{
+	snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
+				  ARRAY_SIZE(tlv320aic23_dapm_widgets));
+
+	/* set up audio path interconnects */
+	snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+
+	snd_soc_dapm_new_widgets(codec);
+	return 0;
+}
+
+static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	u16 iface_reg, data;
+	u8 count = 0;
+
+	iface_reg =
+	    tlv320aic23_read_reg_cache(codec,
+				       TLV320AIC23_DIGT_FMT) & ~(0x03 << 2);
+
+	/* Search for the right sample rate */
+	/* Verify what happens if the rate is not supported
+	 * now it goes to 96Khz */
+	while ((srate_reg_info[count].sample_rate != params_rate(params)) &&
+	       (count < ARRAY_SIZE(srate_reg_info))) {
+		count++;
+	}
+
+	data =  (srate_reg_info[count].divider << TLV320AIC23_CLKIN_SHIFT) |
+		(srate_reg_info[count]. control << TLV320AIC23_BOSR_SHIFT) |
+		TLV320AIC23_USB_CLK_ON;
+
+	tlv320aic23_write(codec, TLV320AIC23_SRATE, data);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		iface_reg |= (0x01 << 2);
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		iface_reg |= (0x02 << 2);
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		iface_reg |= (0x03 << 2);
+		break;
+	}
+	tlv320aic23_write(codec, TLV320AIC23_DIGT_FMT, iface_reg);
+
+	return 0;
+}
+
+static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+
+	/* set active */
+	tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001);
+
+	return 0;
+}
+
+static void tlv320aic23_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+
+	/* deactivate */
+	if (!codec->active) {
+		udelay(50);
+		tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
+	}
+}
+
+static int tlv320aic23_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u16 reg;
+
+	reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT);
+	if (mute)
+		reg |= TLV320AIC23_DACM_MUTE;
+
+	else
+		reg &= ~TLV320AIC23_DACM_MUTE;
+
+	tlv320aic23_write(codec, TLV320AIC23_DIGT, reg);
+
+	return 0;
+}
+
+static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
+				   unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 iface_reg;
+
+	iface_reg =
+	    tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT_FMT) & (~0x03);
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface_reg |= TLV320AIC23_MS_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface_reg |= TLV320AIC23_FOR_I2S;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface_reg |= TLV320AIC23_FOR_DSP;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface_reg |= TLV320AIC23_FOR_LJUST;
+		break;
+	default:
+		return -EINVAL;
+
+	}
+
+	tlv320aic23_write(codec, TLV320AIC23_DIGT_FMT, iface_reg);
+
+	return 0;
+}
+
+static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				      int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+
+	switch (freq) {
+	case 12000000:
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec,
+				      enum snd_soc_bias_level level)
+{
+	u16 reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_PWR) & 0xff7f;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* vref/mid, osc on, dac unmute */
+		tlv320aic23_write(codec, TLV320AIC23_PWR, reg);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		/* everything off except vref/vmid, */
+		tlv320aic23_write(codec, TLV320AIC23_PWR, reg | 0x0040);
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* everything off, dac mute, inactive */
+		tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
+		tlv320aic23_write(codec, TLV320AIC23_PWR, 0xffff);
+		break;
+	}
+	codec->bias_level = level;
+	return 0;
+}
+
+#define AIC23_RATES	SNDRV_PCM_RATE_8000_96000
+#define AIC23_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+struct snd_soc_dai tlv320aic23_dai = {
+	.name = "tlv320aic23",
+	.playback = {
+		     .stream_name = "Playback",
+		     .channels_min = 2,
+		     .channels_max = 2,
+		     .rates = AIC23_RATES,
+		     .formats = AIC23_FORMATS,},
+	.capture = {
+		    .stream_name = "Capture",
+		    .channels_min = 2,
+		    .channels_max = 2,
+		    .rates = AIC23_RATES,
+		    .formats = AIC23_FORMATS,},
+	.ops = {
+		.prepare = tlv320aic23_pcm_prepare,
+		.hw_params = tlv320aic23_hw_params,
+		.shutdown = tlv320aic23_shutdown,
+		},
+	.dai_ops = {
+		    .digital_mute = tlv320aic23_mute,
+		    .set_fmt = tlv320aic23_set_dai_fmt,
+		    .set_sysclk = tlv320aic23_set_dai_sysclk,
+		    }
+};
+EXPORT_SYMBOL_GPL(tlv320aic23_dai);
+
+static int tlv320aic23_suspend(struct platform_device *pdev,
+			       pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
+	tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static int tlv320aic23_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+	int i;
+	u16 reg;
+
+	/* Sync reg_cache with the hardware */
+	for (reg = 0; reg < ARRAY_SIZE(tlv320aic23_reg); i++) {
+		u16 val = tlv320aic23_read_reg_cache(codec, reg);
+		tlv320aic23_write(codec, reg, val);
+	}
+
+	tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	tlv320aic23_set_bias_level(codec, codec->suspend_bias_level);
+
+	return 0;
+}
+
+/*
+ * initialise the AIC23 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int tlv320aic23_init(struct snd_soc_device *socdev)
+{
+	struct snd_soc_codec *codec = socdev->codec;
+	int ret = 0;
+	u16 reg;
+
+	codec->name = "tlv320aic23";
+	codec->owner = THIS_MODULE;
+	codec->read = tlv320aic23_read_reg_cache;
+	codec->write = tlv320aic23_write;
+	codec->set_bias_level = tlv320aic23_set_bias_level;
+	codec->dai = &tlv320aic23_dai;
+	codec->num_dai = 1;
+	codec->reg_cache_size = ARRAY_SIZE(tlv320aic23_reg);
+	codec->reg_cache =
+	    kmemdup(tlv320aic23_reg, sizeof(tlv320aic23_reg), GFP_KERNEL);
+	if (codec->reg_cache == NULL)
+		return -ENOMEM;
+
+	/* Reset codec */
+	tlv320aic23_write(codec, TLV320AIC23_RESET, 0);
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		printk(KERN_ERR "tlv320aic23: failed to create pcms\n");
+		goto pcm_err;
+	}
+
+	/* power on device */
+	tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	tlv320aic23_write(codec, TLV320AIC23_DIGT, TLV320AIC23_DEEMP_44K);
+
+	/* Unmute input */
+	reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_LINVOL);
+	tlv320aic23_write(codec, TLV320AIC23_LINVOL,
+			  (reg & (~TLV320AIC23_LIM_MUTED)) |
+			  (TLV320AIC23_LRS_ENABLED));
+
+	reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_RINVOL);
+	tlv320aic23_write(codec, TLV320AIC23_RINVOL,
+			  (reg & (~TLV320AIC23_LIM_MUTED)) |
+			  TLV320AIC23_LRS_ENABLED);
+
+	reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG);
+	tlv320aic23_write(codec, TLV320AIC23_ANLG,
+			 (reg) & (~TLV320AIC23_BYPASS_ON) &
+			 (~TLV320AIC23_MICM_MUTED));
+
+	/* Default output volume */
+	tlv320aic23_write(codec, TLV320AIC23_LCHNVOL,
+			  TLV320AIC23_DEFAULT_OUT_VOL &
+			  TLV320AIC23_OUT_VOL_MASK);
+	tlv320aic23_write(codec, TLV320AIC23_RCHNVOL,
+			  TLV320AIC23_DEFAULT_OUT_VOL &
+			  TLV320AIC23_OUT_VOL_MASK);
+
+	tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x1);
+
+	tlv320aic23_add_controls(codec);
+	tlv320aic23_add_widgets(codec);
+	ret = snd_soc_register_card(socdev);
+	if (ret < 0) {
+		printk(KERN_ERR "tlv320aic23: failed to register card\n");
+		goto card_err;
+	}
+
+	return ret;
+
+card_err:
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+pcm_err:
+	kfree(codec->reg_cache);
+	return ret;
+}
+static struct snd_soc_device *tlv320aic23_socdev;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+/*
+ * If the i2c layer weren't so broken, we could pass this kind of data
+ * around
+ */
+static int tlv320aic23_codec_probe(struct i2c_client *i2c,
+				   const struct i2c_device_id *i2c_id)
+{
+	struct snd_soc_device *socdev = tlv320aic23_socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	int ret;
+
+	if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EINVAL;
+
+	i2c_set_clientdata(i2c, codec);
+	codec->control_data = i2c;
+
+	ret = tlv320aic23_init(socdev);
+	if (ret < 0) {
+		printk(KERN_ERR "tlv320aic23: failed to initialise AIC23\n");
+		goto err;
+	}
+	return ret;
+
+err:
+	kfree(codec);
+	kfree(i2c);
+	return ret;
+}
+static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c)
+{
+	put_device(&i2c->dev);
+	return 0;
+}
+
+static const struct i2c_device_id tlv320aic23_id[] = {
+	{"tlv320aic23", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, tlv320aic23_id);
+
+static struct i2c_driver tlv320aic23_i2c_driver = {
+	.driver = {
+		   .name = "tlv320aic23",
+		   },
+	.probe = tlv320aic23_codec_probe,
+	.remove = __exit_p(tlv320aic23_i2c_remove),
+	.id_table = tlv320aic23_id,
+};
+
+#endif
+
+static int tlv320aic23_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	int ret = 0;
+
+	printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
+
+	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (codec == NULL)
+		return -ENOMEM;
+
+	socdev->codec = codec;
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	tlv320aic23_socdev = socdev;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	codec->hw_write = (hw_write_t) i2c_smbus_write_byte_data;
+	codec->hw_read = NULL;
+	ret = i2c_add_driver(&tlv320aic23_i2c_driver);
+	if (ret != 0)
+		printk(KERN_ERR "can't add i2c driver");
+#endif
+	return ret;
+}
+
+static int tlv320aic23_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	if (codec->control_data)
+		tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_del_driver(&tlv320aic23_i2c_driver);
+#endif
+	kfree(codec->reg_cache);
+	kfree(codec);
+
+	return 0;
+}
+struct snd_soc_codec_device soc_codec_dev_tlv320aic23 = {
+	.probe = tlv320aic23_probe,
+	.remove = tlv320aic23_remove,
+	.suspend = tlv320aic23_suspend,
+	.resume = tlv320aic23_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320aic23);
+
+MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver");
+MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic23.h b/sound/soc/codecs/tlv320aic23.h
new file mode 100644
index 000000000000..79d1faf8e570
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic23.h
@@ -0,0 +1,122 @@
+/*
+ * ALSA SoC TLV320AIC23 codec driver
+ *
+ * Author:      Arun KS, <arunks@mistralsolutions.com>
+ * Copyright:   (C) 2008 Mistral Solutions Pvt Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _TLV320AIC23_H
+#define _TLV320AIC23_H
+
+/* Codec TLV320AIC23 */
+#define TLV320AIC23_LINVOL		0x00
+#define TLV320AIC23_RINVOL		0x01
+#define TLV320AIC23_LCHNVOL		0x02
+#define TLV320AIC23_RCHNVOL		0x03
+#define TLV320AIC23_ANLG		0x04
+#define TLV320AIC23_DIGT		0x05
+#define TLV320AIC23_PWR			0x06
+#define TLV320AIC23_DIGT_FMT		0x07
+#define TLV320AIC23_SRATE		0x08
+#define TLV320AIC23_ACTIVE		0x09
+#define TLV320AIC23_RESET		0x0F
+
+/* Left (right) line input volume control register */
+#define TLV320AIC23_LRS_ENABLED		0x0100
+#define TLV320AIC23_LIM_MUTED		0x0080
+#define TLV320AIC23_LIV_DEFAULT		0x0017
+#define TLV320AIC23_LIV_MAX		0x001f
+#define TLV320AIC23_LIV_MIN		0x0000
+
+/* Left (right) channel headphone volume control register */
+#define TLV320AIC23_LZC_ON		0x0080
+#define TLV320AIC23_LHV_DEFAULT		0x0079
+#define TLV320AIC23_LHV_MAX		0x007f
+#define TLV320AIC23_LHV_MIN		0x0000
+
+/* Analog audio path control register */
+#define TLV320AIC23_STA_REG(x)		((x)<<6)
+#define TLV320AIC23_STE_ENABLED		0x0020
+#define TLV320AIC23_DAC_SELECTED	0x0010
+#define TLV320AIC23_BYPASS_ON		0x0008
+#define TLV320AIC23_INSEL_MIC		0x0004
+#define TLV320AIC23_MICM_MUTED		0x0002
+#define TLV320AIC23_MICB_20DB		0x0001
+
+/* Digital audio path control register */
+#define TLV320AIC23_DACM_MUTE		0x0008
+#define TLV320AIC23_DEEMP_32K		0x0002
+#define TLV320AIC23_DEEMP_44K		0x0004
+#define TLV320AIC23_DEEMP_48K		0x0006
+#define TLV320AIC23_ADCHP_ON		0x0001
+
+/* Power control down register */
+#define TLV320AIC23_DEVICE_PWR_OFF  	0x0080
+#define TLV320AIC23_CLK_OFF		0x0040
+#define TLV320AIC23_OSC_OFF		0x0020
+#define TLV320AIC23_OUT_OFF		0x0010
+#define TLV320AIC23_DAC_OFF		0x0008
+#define TLV320AIC23_ADC_OFF		0x0004
+#define TLV320AIC23_MIC_OFF		0x0002
+#define TLV320AIC23_LINE_OFF		0x0001
+
+/* Digital audio interface register */
+#define TLV320AIC23_MS_MASTER		0x0040
+#define TLV320AIC23_LRSWAP_ON		0x0020
+#define TLV320AIC23_LRP_ON		0x0010
+#define TLV320AIC23_IWL_16		0x0000
+#define TLV320AIC23_IWL_20		0x0004
+#define TLV320AIC23_IWL_24		0x0008
+#define TLV320AIC23_IWL_32		0x000C
+#define TLV320AIC23_FOR_I2S		0x0002
+#define TLV320AIC23_FOR_DSP		0x0003
+#define TLV320AIC23_FOR_LJUST		0x0001
+
+/* Sample rate control register */
+#define TLV320AIC23_CLKOUT_HALF		0x0080
+#define TLV320AIC23_CLKIN_HALF		0x0040
+#define TLV320AIC23_BOSR_384fs		0x0002	/* BOSR_272fs in USB mode */
+#define TLV320AIC23_USB_CLK_ON		0x0001
+#define TLV320AIC23_SR_MASK             0xf
+#define TLV320AIC23_CLKOUT_SHIFT        7
+#define TLV320AIC23_CLKIN_SHIFT         6
+#define TLV320AIC23_SR_SHIFT            2
+#define TLV320AIC23_BOSR_SHIFT          1
+
+/* Digital interface register */
+#define TLV320AIC23_ACT_ON		0x0001
+
+/*
+ * AUDIO related MACROS
+ */
+
+#define TLV320AIC23_DEFAULT_OUT_VOL	0x70
+#define TLV320AIC23_DEFAULT_IN_VOLUME	0x10
+
+#define TLV320AIC23_OUT_VOL_MIN		TLV320AIC23_LHV_MIN
+#define TLV320AIC23_OUT_VOL_MAX		TLV320AIC23_LHV_MAX
+#define TLV320AIC23_OUT_VO_RANGE	(TLV320AIC23_OUT_VOL_MAX - \
+					TLV320AIC23_OUT_VOL_MIN)
+#define TLV320AIC23_OUT_VOL_MASK	TLV320AIC23_OUT_VOL_MAX
+
+#define TLV320AIC23_IN_VOL_MIN		TLV320AIC23_LIV_MIN
+#define TLV320AIC23_IN_VOL_MAX		TLV320AIC23_LIV_MAX
+#define TLV320AIC23_IN_VOL_RANGE	(TLV320AIC23_IN_VOL_MAX - \
+					TLV320AIC23_IN_VOL_MIN)
+#define TLV320AIC23_IN_VOL_MASK		TLV320AIC23_IN_VOL_MAX
+
+#define TLV320AIC23_SIDETONE_MASK	0x1c0
+#define TLV320AIC23_SIDETONE_0		0x100
+#define TLV320AIC23_SIDETONE_6		0x000
+#define TLV320AIC23_SIDETONE_9		0x040
+#define TLV320AIC23_SIDETONE_12		0x080
+#define TLV320AIC23_SIDETONE_18		0x0c0
+
+extern struct snd_soc_dai tlv320aic23_dai;
+extern struct snd_soc_codec_device soc_codec_dev_tlv320aic23;
+
+#endif /* _TLV320AIC23_H */
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 566a427c928f..05336ed7e493 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -48,7 +48,6 @@
 
 #include "tlv320aic3x.h"
 
-#define AUDIO_NAME "aic3x"
 #define AIC3X_VERSION "0.2"
 
 /* codec private data */
@@ -991,7 +990,7 @@ EXPORT_SYMBOL_GPL(aic3x_headset_detected);
 			 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
 
 struct snd_soc_dai aic3x_dai = {
-	.name = "aic3x",
+	.name = "tlv320aic3x",
 	.playback = {
 		.stream_name = "Playback",
 		.channels_min = 1,
@@ -1055,7 +1054,7 @@ static int aic3x_init(struct snd_soc_device *socdev)
 	struct aic3x_setup_data *setup = socdev->codec_data;
 	int reg, ret = 0;
 
-	codec->name = "aic3x";
+	codec->name = "tlv320aic3x";
 	codec->owner = THIS_MODULE;
 	codec->read = aic3x_read_reg_cache;
 	codec->write = aic3x_write;
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index d206d7f892b6..a69ee72a7af5 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -36,7 +36,6 @@
 #include "uda1380.h"
 
 #define UDA1380_VERSION "0.6"
-#define AUDIO_NAME "uda1380"
 
 /*
  * uda1380 register cache
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 9a37c8d95ed2..d8ca2da8d634 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -3,7 +3,7 @@
  *
  * Copyright 2006 Wolfson Microelectronics PLC.
  *
- * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -18,6 +18,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
+#include <linux/spi/spi.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -27,7 +28,6 @@
 
 #include "wm8510.h"
 
-#define AUDIO_NAME "wm8510"
 #define WM8510_VERSION "0.6"
 
 struct snd_soc_codec_device soc_codec_dev_wm8510;
@@ -55,6 +55,9 @@ static const u16 wm8510_reg[WM8510_CACHEREGNUM] = {
 	0x0001,
 };
 
+#define WM8510_POWER1_BIASEN  0x08
+#define WM8510_POWER1_BUFIOEN 0x10
+
 /*
  * read wm8510 register cache
  */
@@ -224,9 +227,9 @@ SND_SOC_DAPM_PGA("SpkN Out", WM8510_POWER3, 5, 0, NULL, 0),
 SND_SOC_DAPM_PGA("SpkP Out", WM8510_POWER3, 6, 0, NULL, 0),
 SND_SOC_DAPM_PGA("Mono Out", WM8510_POWER3, 7, 0, NULL, 0),
 
-SND_SOC_DAPM_PGA("Mic PGA", WM8510_POWER2, 2, 0,
-		 &wm8510_micpga_controls[0],
-		 ARRAY_SIZE(wm8510_micpga_controls)),
+SND_SOC_DAPM_MIXER("Mic PGA", WM8510_POWER2, 2, 0,
+		   &wm8510_micpga_controls[0],
+		   ARRAY_SIZE(wm8510_micpga_controls)),
 SND_SOC_DAPM_MIXER("Boost Mixer", WM8510_POWER2, 4, 0,
 	&wm8510_boost_controls[0],
 	ARRAY_SIZE(wm8510_boost_controls)),
@@ -526,23 +529,35 @@ static int wm8510_mute(struct snd_soc_dai *dai, int mute)
 static int wm8510_set_bias_level(struct snd_soc_codec *codec,
 	enum snd_soc_bias_level level)
 {
+	u16 power1 = wm8510_read_reg_cache(codec, WM8510_POWER1) & ~0x3;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-		wm8510_write(codec, WM8510_POWER1, 0x1ff);
-		wm8510_write(codec, WM8510_POWER2, 0x1ff);
-		wm8510_write(codec, WM8510_POWER3, 0x1ff);
-		break;
 	case SND_SOC_BIAS_PREPARE:
+		power1 |= 0x1;  /* VMID 50k */
+		wm8510_write(codec, WM8510_POWER1, power1);
+		break;
+
 	case SND_SOC_BIAS_STANDBY:
+		power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN;
+
+		if (codec->bias_level == SND_SOC_BIAS_OFF) {
+			/* Initial cap charge at VMID 5k */
+			wm8510_write(codec, WM8510_POWER1, power1 | 0x3);
+			mdelay(100);
+		}
+
+		power1 |= 0x2;  /* VMID 500k */
+		wm8510_write(codec, WM8510_POWER1, power1);
 		break;
+
 	case SND_SOC_BIAS_OFF:
-		/* everything off, dac mute, inactive */
-		wm8510_write(codec, WM8510_POWER1, 0x0);
-		wm8510_write(codec, WM8510_POWER2, 0x0);
-		wm8510_write(codec, WM8510_POWER3, 0x0);
+		wm8510_write(codec, WM8510_POWER1, 0);
+		wm8510_write(codec, WM8510_POWER2, 0);
+		wm8510_write(codec, WM8510_POWER3, 0);
 		break;
 	}
+
 	codec->bias_level = level;
 	return 0;
 }
@@ -640,6 +655,7 @@ static int wm8510_init(struct snd_soc_device *socdev)
 	}
 
 	/* power on device */
+	codec->bias_level = SND_SOC_BIAS_OFF;
 	wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 	wm8510_add_controls(codec);
 	wm8510_add_widgets(codec);
@@ -747,6 +763,62 @@ err_driver:
 }
 #endif
 
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8510_spi_probe(struct spi_device *spi)
+{
+	struct snd_soc_device *socdev = wm8510_socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	int ret;
+
+	codec->control_data = spi;
+
+	ret = wm8510_init(socdev);
+	if (ret < 0)
+		dev_err(&spi->dev, "failed to initialise WM8510\n");
+
+	return ret;
+}
+
+static int __devexit wm8510_spi_remove(struct spi_device *spi)
+{
+	return 0;
+}
+
+static struct spi_driver wm8510_spi_driver = {
+	.driver = {
+		.name	= "wm8510",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= wm8510_spi_probe,
+	.remove		= __devexit_p(wm8510_spi_remove),
+};
+
+static int wm8510_spi_write(struct spi_device *spi, const char *data, int len)
+{
+	struct spi_transfer t;
+	struct spi_message m;
+	u8 msg[2];
+
+	if (len <= 0)
+		return 0;
+
+	msg[0] = data[0];
+	msg[1] = data[1];
+
+	spi_message_init(&m);
+	memset(&t, 0, (sizeof t));
+
+	t.tx_buf = &msg[0];
+	t.len = len;
+
+	spi_message_add_tail(&t, &m);
+	spi_sync(spi, &m);
+
+	return len;
+}
+#endif /* CONFIG_SPI_MASTER */
+
 static int wm8510_probe(struct platform_device *pdev)
 {
 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
@@ -772,8 +844,14 @@ static int wm8510_probe(struct platform_device *pdev)
 		codec->hw_write = (hw_write_t)i2c_master_send;
 		ret = wm8510_add_i2c_device(pdev, setup);
 	}
-#else
-	/* Add other interfaces here */
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	if (setup->spi) {
+		codec->hw_write = (hw_write_t)wm8510_spi_write;
+		ret = spi_register_driver(&wm8510_spi_driver);
+		if (ret != 0)
+			printk(KERN_ERR "can't add spi driver");
+	}
 #endif
 
 	if (ret != 0)
@@ -796,6 +874,9 @@ static int wm8510_remove(struct platform_device *pdev)
 	i2c_unregister_device(codec->control_data);
 	i2c_del_driver(&wm8510_i2c_driver);
 #endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8510_spi_driver);
+#endif
 	kfree(codec);
 
 	return 0;
diff --git a/sound/soc/codecs/wm8510.h b/sound/soc/codecs/wm8510.h
index c53683960456..bdefcf5c69ff 100644
--- a/sound/soc/codecs/wm8510.h
+++ b/sound/soc/codecs/wm8510.h
@@ -94,6 +94,7 @@
 #define WM8510_MCLKDIV_12	(7 << 5)
 
 struct wm8510_setup_data {
+	int spi;
 	int i2c_bus;
 	unsigned short i2c_address;
 };
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index df1ffbe305bf..627ebfb4209b 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -18,7 +18,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
@@ -36,7 +35,6 @@
 
 #include "wm8580.h"
 
-#define AUDIO_NAME "wm8580"
 #define WM8580_VERSION "0.1"
 
 struct pll_state {
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 7b64d9a7ff76..7f8a7e36b33e 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -29,7 +29,6 @@
 
 #include "wm8731.h"
 
-#define AUDIO_NAME "wm8731"
 #define WM8731_VERSION "0.13"
 
 struct snd_soc_codec_device soc_codec_dev_wm8731;
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index 4892e398a598..9b7296ee5b08 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -29,7 +29,6 @@
 
 #include "wm8750.h"
 
-#define AUDIO_NAME "WM8750"
 #define WM8750_VERSION "0.12"
 
 /* codec private data */
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index 8c4df44f3345..d426eaa22185 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -2,8 +2,7 @@
  * wm8753.c  --  WM8753 ALSA Soc Audio driver
  *
  * Copyright 2003 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -40,6 +39,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
+#include <linux/spi/spi.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -51,7 +51,6 @@
 
 #include "wm8753.h"
 
-#define AUDIO_NAME "wm8753"
 #define WM8753_VERSION "0.16"
 
 static int caps_charge = 2000;
@@ -1719,6 +1718,63 @@ err_driver:
 }
 #endif
 
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8753_spi_probe(struct spi_device *spi)
+{
+	struct snd_soc_device *socdev = wm8753_socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	int ret;
+
+	codec->control_data = spi;
+
+	ret = wm8753_init(socdev);
+	if (ret < 0)
+		dev_err(&spi->dev, "failed to initialise WM8753\n");
+
+	return ret;
+}
+
+static int __devexit wm8753_spi_remove(struct spi_device *spi)
+{
+	return 0;
+}
+
+static struct spi_driver wm8753_spi_driver = {
+	.driver = {
+		.name	= "wm8753",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= wm8753_spi_probe,
+	.remove		= __devexit_p(wm8753_spi_remove),
+};
+
+static int wm8753_spi_write(struct spi_device *spi, const char *data, int len)
+{
+	struct spi_transfer t;
+	struct spi_message m;
+	u8 msg[2];
+
+	if (len <= 0)
+		return 0;
+
+	msg[0] = data[0];
+	msg[1] = data[1];
+
+	spi_message_init(&m);
+	memset(&t, 0, (sizeof t));
+
+	t.tx_buf = &msg[0];
+	t.len = len;
+
+	spi_message_add_tail(&t, &m);
+	spi_sync(spi, &m);
+
+	return len;
+}
+#endif
+
+
 static int wm8753_probe(struct platform_device *pdev)
 {
 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
@@ -1753,8 +1809,14 @@ static int wm8753_probe(struct platform_device *pdev)
 		codec->hw_write = (hw_write_t)i2c_master_send;
 		ret = wm8753_add_i2c_device(pdev, setup);
 	}
-#else
-		/* Add other interfaces here */
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	if (setup->spi) {
+		codec->hw_write = (hw_write_t)wm8753_spi_write;
+		ret = spi_register_driver(&wm8753_spi_driver);
+		if (ret != 0)
+			printk(KERN_ERR "can't add spi driver");
+	}
 #endif
 
 	if (ret != 0) {
@@ -1798,6 +1860,9 @@ static int wm8753_remove(struct platform_device *pdev)
 	i2c_unregister_device(codec->control_data);
 	i2c_del_driver(&wm8753_i2c_driver);
 #endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8753_spi_driver);
+#endif
 	kfree(codec->private_data);
 	kfree(codec);
 
diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h
index 7defde069f1d..f55704ce931b 100644
--- a/sound/soc/codecs/wm8753.h
+++ b/sound/soc/codecs/wm8753.h
@@ -2,8 +2,7 @@
  * wm8753.h  --  audio driver for WM8753
  *
  * Copyright 2003 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -79,6 +78,7 @@
 #define WM8753_ADCTL2		0x3f
 
 struct wm8753_setup_data {
+	int spi;
 	int i2c_bus;
 	unsigned short i2c_address;
 };
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index 0b8c6d38b48f..3b326c9b5586 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -18,7 +18,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index a3f54ec4226e..ce40d7877605 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -653,14 +653,14 @@ static const struct snd_kcontrol_new wm8903_snd_controls[] = {
 
 /* Input PGAs - No TLV since the scale depends on PGA mode */
 SOC_SINGLE("Left Input PGA Switch", WM8903_ANALOGUE_LEFT_INPUT_0,
-	   7, 1, 0),
+	   7, 1, 1),
 SOC_SINGLE("Left Input PGA Volume", WM8903_ANALOGUE_LEFT_INPUT_0,
 	   0, 31, 0),
 SOC_SINGLE("Left Input PGA Common Mode Switch", WM8903_ANALOGUE_LEFT_INPUT_1,
 	   6, 1, 0),
 
 SOC_SINGLE("Right Input PGA Switch", WM8903_ANALOGUE_RIGHT_INPUT_0,
-	   7, 1, 0),
+	   7, 1, 1),
 SOC_SINGLE("Right Input PGA Volume", WM8903_ANALOGUE_RIGHT_INPUT_0,
 	   0, 31, 0),
 SOC_SINGLE("Right Input PGA Common Mode Switch", WM8903_ANALOGUE_RIGHT_INPUT_1,
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index 974a4cd0f3fd..f41a578ddd4f 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -29,7 +29,6 @@
 
 #include "wm8971.h"
 
-#define AUDIO_NAME "wm8971"
 #define WM8971_VERSION "0.9"
 
 #define	WM8971_REG_COUNT		43
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index 63410d7b5efb..572d22b0880b 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -30,7 +30,6 @@
 
 #include "wm8990.h"
 
-#define AUDIO_NAME "wm8990"
 #define WM8990_VERSION "0.2"
 
 /* codec private data */
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index 2f1c91b1d556..ffb471e420e2 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -2,8 +2,7 @@
  * wm9712.c  --  ALSA Soc WM9712 codec support
  *
  * Copyright 2006 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 441d0580db1f..aba402b3c999 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -2,8 +2,7 @@
  * wm9713.c  --  ALSA Soc WM9713 codec support
  *
  * Copyright 2006 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index aea27e70043c..8b7766b998d7 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -13,3 +13,11 @@ config SND_OMAP_SOC_N810
 	select SND_SOC_TLV320AIC3X
 	help
 	  Say Y if you want to add support for SoC audio on Nokia N810.
+
+config SND_OMAP_SOC_OSK5912
+	tristate "SoC Audio support for omap osk5912"
+	depends on SND_OMAP_SOC && MACH_OMAP_OSK
+	select SND_OMAP_SOC_MCBSP
+	select SND_SOC_TLV320AIC23
+	help
+	  Say Y if you want to add support for SoC audio on osk5912.
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index d8d8d58075e3..e09d1f297f64 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -7,5 +7,7 @@ obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
 
 # OMAP Machine Support
 snd-soc-n810-objs := n810.o
+snd-soc-osk5912-objs := osk5912.o
 
 obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
+obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index d166b6b2a60d..fae3ad36e0bf 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -247,9 +247,9 @@ static int n810_aic33_init(struct snd_soc_codec *codec)
 	int i, err;
 
 	/* Not connected */
-	snd_soc_dapm_disable_pin(codec, "MONO_LOUT");
-	snd_soc_dapm_disable_pin(codec, "HPLCOM");
-	snd_soc_dapm_disable_pin(codec, "HPRCOM");
+	snd_soc_dapm_nc_pin(codec, "MONO_LOUT");
+	snd_soc_dapm_nc_pin(codec, "HPLCOM");
+	snd_soc_dapm_nc_pin(codec, "HPRCOM");
 
 	/* Add N810 specific controls */
 	for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) {
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 35310e16d7f3..0a063a98a661 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -59,12 +59,7 @@ static struct omap_mcbsp_data mcbsp_data[NUM_LINKS];
  * Stream DMA parameters. DMA request line and port address are set runtime
  * since they are different between OMAP1 and later OMAPs
  */
-static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2] = {
-{
-	{ .name		= "I2S PCM Stereo out", },
-	{ .name		= "I2S PCM Stereo in", },
-},
-};
+static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2];
 
 #if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
 static const int omap1_dma_reqs[][2] = {
@@ -84,11 +79,22 @@ static const unsigned long omap1_mcbsp_port[][2] = {
 static const int omap1_dma_reqs[][2] = {};
 static const unsigned long omap1_mcbsp_port[][2] = {};
 #endif
-#if defined(CONFIG_ARCH_OMAP2420)
-static const int omap2420_dma_reqs[][2] = {
+
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+static const int omap24xx_dma_reqs[][2] = {
 	{ OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX },
 	{ OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX },
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
+	{ OMAP24XX_DMA_MCBSP3_TX, OMAP24XX_DMA_MCBSP3_RX },
+	{ OMAP24XX_DMA_MCBSP4_TX, OMAP24XX_DMA_MCBSP4_RX },
+	{ OMAP24XX_DMA_MCBSP5_TX, OMAP24XX_DMA_MCBSP5_RX },
+#endif
 };
+#else
+static const int omap24xx_dma_reqs[][2] = {};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP2420)
 static const unsigned long omap2420_mcbsp_port[][2] = {
 	{ OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1,
 	  OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1 },
@@ -96,10 +102,43 @@ static const unsigned long omap2420_mcbsp_port[][2] = {
 	  OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1 },
 };
 #else
-static const int omap2420_dma_reqs[][2] = {};
 static const unsigned long omap2420_mcbsp_port[][2] = {};
 #endif
 
+#if defined(CONFIG_ARCH_OMAP2430)
+static const unsigned long omap2430_mcbsp_port[][2] = {
+	{ OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR,
+	  OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR },
+	{ OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR,
+	  OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR },
+	{ OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DXR,
+	  OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DRR },
+	{ OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DXR,
+	  OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DRR },
+	{ OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DXR,
+	  OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DRR },
+};
+#else
+static const unsigned long omap2430_mcbsp_port[][2] = {};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP34XX)
+static const unsigned long omap34xx_mcbsp_port[][2] = {
+	{ OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR,
+	  OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR },
+	{ OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR,
+	  OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR },
+	{ OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DXR,
+	  OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DRR },
+	{ OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DXR,
+	  OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DRR },
+	{ OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DXR,
+	  OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DRR },
+};
+#else
+static const unsigned long omap34xx_mcbsp_port[][2] = {};
+#endif
+
 static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -167,14 +206,19 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
 		dma = omap1_dma_reqs[bus_id][substream->stream];
 		port = omap1_mcbsp_port[bus_id][substream->stream];
 	} else if (cpu_is_omap2420()) {
-		dma = omap2420_dma_reqs[bus_id][substream->stream];
+		dma = omap24xx_dma_reqs[bus_id][substream->stream];
 		port = omap2420_mcbsp_port[bus_id][substream->stream];
+	} else if (cpu_is_omap2430()) {
+		dma = omap24xx_dma_reqs[bus_id][substream->stream];
+		port = omap2430_mcbsp_port[bus_id][substream->stream];
+	} else if (cpu_is_omap343x()) {
+		dma = omap24xx_dma_reqs[bus_id][substream->stream];
+		port = omap34xx_mcbsp_port[bus_id][substream->stream];
 	} else {
-		/*
-		 * TODO: Add support for 2430 and 3430
-		 */
 		return -ENODEV;
 	}
+	omap_mcbsp_dai_dma_params[id][substream->stream].name =
+		substream->stream ? "Audio Capture" : "Audio Playback";
 	omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma;
 	omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port;
 	cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream];
@@ -245,6 +289,11 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 		regs->rcr2	|= RDATDLY(1);
 		regs->xcr2	|= XDATDLY(1);
 		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		/* 0-bit data delay */
+		regs->rcr2      |= RDATDLY(0);
+		regs->xcr2      |= XDATDLY(0);
+		break;
 	default:
 		/* Unsupported data format */
 		return -EINVAL;
@@ -310,7 +359,7 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
 				       int clk_id)
 {
 	int sel_bit;
-	u16 reg;
+	u16 reg, reg_devconf1 = OMAP243X_CONTROL_DEVCONF1;
 
 	if (cpu_class_is_omap1()) {
 		/* OMAP1's can use only external source clock */
@@ -320,6 +369,12 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
 			return 0;
 	}
 
+	if (cpu_is_omap2420() && mcbsp_data->bus_id > 1)
+		return -EINVAL;
+
+	if (cpu_is_omap343x())
+		reg_devconf1 = OMAP343X_CONTROL_DEVCONF1;
+
 	switch (mcbsp_data->bus_id) {
 	case 0:
 		reg = OMAP2_CONTROL_DEVCONF0;
@@ -329,20 +384,26 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
 		reg = OMAP2_CONTROL_DEVCONF0;
 		sel_bit = 6;
 		break;
-	/* TODO: Support for ports 3 - 5 in OMAP2430 and OMAP34xx */
+	case 2:
+		reg = reg_devconf1;
+		sel_bit = 0;
+		break;
+	case 3:
+		reg = reg_devconf1;
+		sel_bit = 2;
+		break;
+	case 4:
+		reg = reg_devconf1;
+		sel_bit = 4;
+		break;
 	default:
 		return -EINVAL;
 	}
 
-	if (cpu_class_is_omap2()) {
-		if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK) {
-			omap_ctrl_writel(omap_ctrl_readl(reg) &
-					 ~(1 << sel_bit), reg);
-		} else {
-			omap_ctrl_writel(omap_ctrl_readl(reg) |
-					 (1 << sel_bit), reg);
-		}
-	}
+	if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK)
+		omap_ctrl_writel(omap_ctrl_readl(reg) & ~(1 << sel_bit), reg);
+	else
+		omap_ctrl_writel(omap_ctrl_readl(reg) | (1 << sel_bit), reg);
 
 	return 0;
 }
@@ -376,37 +437,49 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
 	return err;
 }
 
-struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS] = {
-{
-	.name = "omap-mcbsp-dai",
-	.id = 0,
-	.type = SND_SOC_DAI_I2S,
-	.playback = {
-		.channels_min = 2,
-		.channels_max = 2,
-		.rates = OMAP_MCBSP_RATES,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-	.capture = {
-		.channels_min = 2,
-		.channels_max = 2,
-		.rates = OMAP_MCBSP_RATES,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-	.ops = {
-		.startup = omap_mcbsp_dai_startup,
-		.shutdown = omap_mcbsp_dai_shutdown,
-		.trigger = omap_mcbsp_dai_trigger,
-		.hw_params = omap_mcbsp_dai_hw_params,
-	},
-	.dai_ops = {
-		.set_fmt = omap_mcbsp_dai_set_dai_fmt,
-		.set_clkdiv = omap_mcbsp_dai_set_clkdiv,
-		.set_sysclk = omap_mcbsp_dai_set_dai_sysclk,
-	},
-	.private_data = &mcbsp_data[0].bus_id,
-},
+#define OMAP_MCBSP_DAI_BUILDER(link_id)				\
+{								\
+	.name = "omap-mcbsp-dai-(link_id)",			\
+	.id = (link_id),					\
+	.type = SND_SOC_DAI_I2S,				\
+	.playback = {						\
+		.channels_min = 2,				\
+		.channels_max = 2,				\
+		.rates = OMAP_MCBSP_RATES,			\
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,		\
+	},							\
+	.capture = {						\
+		.channels_min = 2,				\
+		.channels_max = 2,				\
+		.rates = OMAP_MCBSP_RATES,			\
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,		\
+	},							\
+	.ops = {						\
+		.startup = omap_mcbsp_dai_startup,		\
+		.shutdown = omap_mcbsp_dai_shutdown,		\
+		.trigger = omap_mcbsp_dai_trigger,		\
+		.hw_params = omap_mcbsp_dai_hw_params,		\
+	},							\
+	.dai_ops = {						\
+		.set_fmt = omap_mcbsp_dai_set_dai_fmt,		\
+		.set_clkdiv = omap_mcbsp_dai_set_clkdiv,	\
+		.set_sysclk = omap_mcbsp_dai_set_dai_sysclk,	\
+	},							\
+	.private_data = &mcbsp_data[(link_id)].bus_id,		\
+}
+
+struct snd_soc_dai omap_mcbsp_dai[] = {
+	OMAP_MCBSP_DAI_BUILDER(0),
+	OMAP_MCBSP_DAI_BUILDER(1),
+#if NUM_LINKS >= 3
+	OMAP_MCBSP_DAI_BUILDER(2),
+#endif
+#if NUM_LINKS == 5
+	OMAP_MCBSP_DAI_BUILDER(3),
+	OMAP_MCBSP_DAI_BUILDER(4),
+#endif
 };
+
 EXPORT_SYMBOL_GPL(omap_mcbsp_dai);
 
 MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>");
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h
index ed8afb550671..df7ad13ba73d 100644
--- a/sound/soc/omap/omap-mcbsp.h
+++ b/sound/soc/omap/omap-mcbsp.h
@@ -38,11 +38,17 @@ enum omap_mcbsp_div {
 	OMAP_MCBSP_CLKGDV,		/* Sample rate generator divider */
 };
 
-/*
- * REVISIT: Preparation for the ASoC v2. Let the number of available links to
- * be same than number of McBSP ports found in OMAP(s) we are compiling for.
- */
-#define NUM_LINKS	1
+#if defined(CONFIG_ARCH_OMAP2420)
+#define NUM_LINKS	2
+#endif
+#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
+#undef  NUM_LINKS
+#define NUM_LINKS	3
+#endif
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
+#undef  NUM_LINKS
+#define NUM_LINKS	5
+#endif
 
 extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS];
 
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index 690bfeaec4a0..e9084fdd2082 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -97,7 +97,7 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
 	prtd->dma_data = dma_data;
 	err = omap_request_dma(dma_data->dma_req, dma_data->name,
 			       omap_pcm_dma_irq, substream, &prtd->dma_ch);
-	if (!cpu_is_omap1510()) {
+	if (!err & !cpu_is_omap1510()) {
 		/*
 		 * Link channel with itself so DMA doesn't need any
 		 * reprogramming while looping the buffer
@@ -147,12 +147,14 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream)
 		dma_params.src_or_dst_synch	= OMAP_DMA_DST_SYNC;
 		dma_params.src_start		= runtime->dma_addr;
 		dma_params.dst_start		= dma_data->port_addr;
+		dma_params.dst_port		= OMAP_DMA_PORT_MPUI;
 	} else {
 		dma_params.src_amode		= OMAP_DMA_AMODE_CONSTANT;
 		dma_params.dst_amode		= OMAP_DMA_AMODE_POST_INC;
 		dma_params.src_or_dst_synch	= OMAP_DMA_SRC_SYNC;
 		dma_params.src_start		= dma_data->port_addr;
 		dma_params.dst_start		= runtime->dma_addr;
+		dma_params.src_port		= OMAP_DMA_PORT_MPUI;
 	}
 	/*
 	 * Set DMA transfer frame size equal to ALSA period size and frame
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c
new file mode 100644
index 000000000000..0fe733796898
--- /dev/null
+++ b/sound/soc/omap/osk5912.c
@@ -0,0 +1,232 @@
+/*
+ * osk5912.c  --  SoC audio for OSK 5912
+ *
+ * Copyright (C) 2008 Mistral Solutions
+ *
+ * Contact: Arun KS  <arunks@mistralsolutions.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <linux/gpio.h>
+#include <mach/mcbsp.h>
+
+#include "omap-mcbsp.h"
+#include "omap-pcm.h"
+#include "../codecs/tlv320aic23.h"
+
+#define CODEC_CLOCK 	12000000
+
+static struct clk *tlv320aic23_mclk;
+
+static int osk_startup(struct snd_pcm_substream *substream)
+{
+	return clk_enable(tlv320aic23_mclk);
+}
+
+static void osk_shutdown(struct snd_pcm_substream *substream)
+{
+	clk_disable(tlv320aic23_mclk);
+}
+
+static int osk_hw_params(struct snd_pcm_substream *substream,
+			 struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	int err;
+
+	/* Set codec DAI configuration */
+	err = snd_soc_dai_set_fmt(codec_dai,
+				  SND_SOC_DAIFMT_DSP_A |
+				  SND_SOC_DAIFMT_NB_IF |
+				  SND_SOC_DAIFMT_CBM_CFM);
+	if (err < 0) {
+		printk(KERN_ERR "can't set codec DAI configuration\n");
+		return err;
+	}
+
+	/* Set cpu DAI configuration */
+	err = snd_soc_dai_set_fmt(cpu_dai,
+				  SND_SOC_DAIFMT_DSP_A |
+				  SND_SOC_DAIFMT_NB_IF |
+				  SND_SOC_DAIFMT_CBM_CFM);
+	if (err < 0) {
+		printk(KERN_ERR "can't set cpu DAI configuration\n");
+		return err;
+	}
+
+	/* Set the codec system clock for DAC and ADC */
+	err =
+	    snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN);
+
+	if (err < 0) {
+		printk(KERN_ERR "can't set codec system clock\n");
+		return err;
+	}
+
+	return err;
+}
+
+static struct snd_soc_ops osk_ops = {
+	.startup = osk_startup,
+	.hw_params = osk_hw_params,
+	.shutdown = osk_shutdown,
+};
+
+static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_LINE("Line In", NULL),
+	SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	{"Headphone Jack", NULL, "LHPOUT"},
+	{"Headphone Jack", NULL, "RHPOUT"},
+
+	{"LLINEIN", NULL, "Line In"},
+	{"RLINEIN", NULL, "Line In"},
+
+	{"MICIN", NULL, "Mic Jack"},
+};
+
+static int osk_tlv320aic23_init(struct snd_soc_codec *codec)
+{
+
+	/* Add osk5912 specific widgets */
+	snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
+				  ARRAY_SIZE(tlv320aic23_dapm_widgets));
+
+	/* Set up osk5912 specific audio path audio_map */
+	snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+	snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+	snd_soc_dapm_enable_pin(codec, "Line In");
+	snd_soc_dapm_enable_pin(codec, "Mic Jack");
+
+	snd_soc_dapm_sync(codec);
+
+	return 0;
+}
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link osk_dai = {
+	.name = "TLV320AIC23",
+	.stream_name = "AIC23",
+	.cpu_dai = &omap_mcbsp_dai[0],
+	.codec_dai = &tlv320aic23_dai,
+	.init = osk_tlv320aic23_init,
+	.ops = &osk_ops,
+};
+
+/* Audio machine driver */
+static struct snd_soc_machine snd_soc_machine_osk = {
+	.name = "OSK5912",
+	.dai_link = &osk_dai,
+	.num_links = 1,
+};
+
+/* Audio subsystem */
+static struct snd_soc_device osk_snd_devdata = {
+	.machine = &snd_soc_machine_osk,
+	.platform = &omap_soc_platform,
+	.codec_dev = &soc_codec_dev_tlv320aic23,
+};
+
+static struct platform_device *osk_snd_device;
+
+static int __init osk_soc_init(void)
+{
+	int err;
+	u32 curRate;
+	struct device *dev;
+
+	if (!(machine_is_omap_osk()))
+		return -ENODEV;
+
+	osk_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!osk_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(osk_snd_device, &osk_snd_devdata);
+	osk_snd_devdata.dev = &osk_snd_device->dev;
+	*(unsigned int *)osk_dai.cpu_dai->private_data = 0;	/* McBSP1 */
+	err = platform_device_add(osk_snd_device);
+	if (err)
+		goto err1;
+
+	dev = &osk_snd_device->dev;
+
+	tlv320aic23_mclk = clk_get(dev, "mclk");
+	if (IS_ERR(tlv320aic23_mclk)) {
+		printk(KERN_ERR "Could not get mclk clock\n");
+		return -ENODEV;
+	}
+
+	if (clk_get_usecount(tlv320aic23_mclk) > 0) {
+		/* MCLK is already in use */
+		printk(KERN_WARNING
+		       "MCLK in use at %d Hz. We change it to %d Hz\n",
+		       (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK);
+	}
+
+	/*
+	 * Configure 12 MHz output on MCLK.
+	 */
+	curRate = (uint) clk_get_rate(tlv320aic23_mclk);
+	if (curRate != CODEC_CLOCK) {
+		if (clk_set_rate(tlv320aic23_mclk, CODEC_CLOCK)) {
+			printk(KERN_ERR "Cannot set MCLK for AIC23 CODEC\n");
+			err = -ECANCELED;
+			goto err1;
+		}
+	}
+
+	printk(KERN_INFO "MCLK = %d [%d], usecount = %d\n",
+	       (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK,
+	       clk_get_usecount(tlv320aic23_mclk));
+
+	return 0;
+err1:
+	clk_put(tlv320aic23_mclk);
+	platform_device_del(osk_snd_device);
+	platform_device_put(osk_snd_device);
+
+	return err;
+
+}
+
+static void __exit osk_soc_exit(void)
+{
+	platform_device_unregister(osk_snd_device);
+}
+
+module_init(osk_soc_init);
+module_exit(osk_soc_exit);
+
+MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
+MODULE_DESCRIPTION("ALSA SoC OSK 5912");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c
index 1a8373de7f3a..2718eaf7895f 100644
--- a/sound/soc/pxa/corgi.c
+++ b/sound/soc/pxa/corgi.c
@@ -4,7 +4,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
  *          Richard Purdie <richard@openedhand.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -281,8 +281,8 @@ static int corgi_wm8731_init(struct snd_soc_codec *codec)
 {
 	int i, err;
 
-	snd_soc_dapm_disable_pin(codec, "LLINEIN");
-	snd_soc_dapm_disable_pin(codec, "RLINEIN");
+	snd_soc_dapm_nc_pin(codec, "LLINEIN");
+	snd_soc_dapm_nc_pin(codec, "RLINEIN");
 
 	/* Add corgi specific controls */
 	for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) {
diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c
index d9c3f7b28be2..e6ff6929ab4b 100644
--- a/sound/soc/pxa/em-x270.c
+++ b/sound/soc/pxa/em-x270.c
@@ -9,7 +9,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
  *          Richard Purdie <richard@openedhand.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
index f84f7d8db09a..4d9930c52789 100644
--- a/sound/soc/pxa/poodle.c
+++ b/sound/soc/pxa/poodle.c
@@ -4,7 +4,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
  *          Richard Purdie <richard@openedhand.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -242,8 +242,8 @@ static int poodle_wm8731_init(struct snd_soc_codec *codec)
 {
 	int i, err;
 
-	snd_soc_dapm_disable_pin(codec, "LLINEIN");
-	snd_soc_dapm_disable_pin(codec, "RLINEIN");
+	snd_soc_dapm_nc_pin(codec, "LLINEIN");
+	snd_soc_dapm_nc_pin(codec, "RLINEIN");
 	snd_soc_dapm_enable_pin(codec, "MICIN");
 
 	/* Add poodle specific controls */
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index 2fb58298513b..e758034db5c3 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -3,7 +3,7 @@
  *
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *         lrg@slimlogic.co.uk
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -405,6 +405,6 @@ module_init(pxa2xx_i2s_init);
 module_exit(pxa2xx_i2s_exit);
 
 /* Module information */
-MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
 MODULE_DESCRIPTION("pxa2xx I2S SoC Interface");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c
index 9a70b00fc30e..d307b6757e95 100644
--- a/sound/soc/pxa/spitz.c
+++ b/sound/soc/pxa/spitz.c
@@ -4,7 +4,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
  *          Richard Purdie <richard@openedhand.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -281,13 +281,13 @@ static int spitz_wm8750_init(struct snd_soc_codec *codec)
 	int i, err;
 
 	/* NC codec pins */
-	snd_soc_dapm_disable_pin(codec, "RINPUT1");
-	snd_soc_dapm_disable_pin(codec, "LINPUT2");
-	snd_soc_dapm_disable_pin(codec, "RINPUT2");
-	snd_soc_dapm_disable_pin(codec, "LINPUT3");
-	snd_soc_dapm_disable_pin(codec, "RINPUT3");
-	snd_soc_dapm_disable_pin(codec, "OUT3");
-	snd_soc_dapm_disable_pin(codec, "MONO1");
+	snd_soc_dapm_nc_pin(codec, "RINPUT1");
+	snd_soc_dapm_nc_pin(codec, "LINPUT2");
+	snd_soc_dapm_nc_pin(codec, "RINPUT2");
+	snd_soc_dapm_nc_pin(codec, "LINPUT3");
+	snd_soc_dapm_nc_pin(codec, "RINPUT3");
+	snd_soc_dapm_nc_pin(codec, "OUT3");
+	snd_soc_dapm_nc_pin(codec, "MONO1");
 
 	/* Add spitz specific controls */
 	for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) {
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c
index 2baaa750f123..afefe41b8c46 100644
--- a/sound/soc/pxa/tosa.c
+++ b/sound/soc/pxa/tosa.c
@@ -4,7 +4,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
  *          Richard Purdie <richard@openedhand.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -190,8 +190,8 @@ static int tosa_ac97_init(struct snd_soc_codec *codec)
 {
 	int i, err;
 
-	snd_soc_dapm_disable_pin(codec, "OUT3");
-	snd_soc_dapm_disable_pin(codec, "MONOOUT");
+	snd_soc_dapm_nc_pin(codec, "OUT3");
+	snd_soc_dapm_nc_pin(codec, "MONOOUT");
 
 	/* add tosa specific controls */
 	for (i = 0; i < ARRAY_SIZE(tosa_controls); i++) {
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
index 73a50e93a9a2..87ddfefcc2fb 100644
--- a/sound/soc/s3c24xx/neo1973_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_wm8753.c
@@ -511,21 +511,20 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec)
 	DBG("Entered %s\n", __func__);
 
 	/* set up NC codec pins */
-	snd_soc_dapm_disable_pin(codec, "LOUT2");
-	snd_soc_dapm_disable_pin(codec, "ROUT2");
-	snd_soc_dapm_disable_pin(codec, "OUT3");
-	snd_soc_dapm_disable_pin(codec, "OUT4");
-	snd_soc_dapm_disable_pin(codec, "LINE1");
-	snd_soc_dapm_disable_pin(codec, "LINE2");
-
-
-	/* set endpoints to default mode */
-	set_scenario_endpoints(codec, NEO_AUDIO_OFF);
+	snd_soc_dapm_nc_pin(codec, "LOUT2");
+	snd_soc_dapm_nc_pin(codec, "ROUT2");
+	snd_soc_dapm_nc_pin(codec, "OUT3");
+	snd_soc_dapm_nc_pin(codec, "OUT4");
+	snd_soc_dapm_nc_pin(codec, "LINE1");
+	snd_soc_dapm_nc_pin(codec, "LINE2");
 
 	/* Add neo1973 specific widgets */
 	snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets,
 				  ARRAY_SIZE(wm8753_dapm_widgets));
 
+	/* set endpoints to default mode */
+	set_scenario_endpoints(codec, NEO_AUDIO_OFF);
+
 	/* add neo1973 specific controls */
 	for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) {
 		err = snd_ctl_add(codec->card,
@@ -603,6 +602,8 @@ static int lm4857_i2c_probe(struct i2c_client *client,
 {
 	DBG("Entered %s\n", __func__);
 
+	i2c = client;
+
 	lm4857_write_regs();
 	return 0;
 }
@@ -611,6 +612,8 @@ static int lm4857_i2c_remove(struct i2c_client *client)
 {
 	DBG("Entered %s\n", __func__);
 
+	i2c = NULL;
+
 	return 0;
 }
 
@@ -650,7 +653,7 @@ static void lm4857_shutdown(struct i2c_client *dev)
 }
 
 static const struct i2c_device_id lm4857_i2c_id[] = {
-	{ "neo1973_lm4857", 0 }
+	{ "neo1973_lm4857", 0 },
 	{ }
 };
 
@@ -668,48 +671,6 @@ static struct i2c_driver lm4857_i2c_driver = {
 };
 
 static struct platform_device *neo1973_snd_device;
-static struct i2c_client *lm4857_client;
-
-static int __init neo1973_add_lm4857_device(struct platform_device *pdev,
-					    int i2c_bus,
-					    unsigned short i2c_address)
-{
-	struct i2c_board_info info;
-	struct i2c_adapter *adapter;
-	struct i2c_client *client;
-	int ret;
-
-	ret = i2c_add_driver(&lm4857_i2c_driver);
-	if (ret != 0) {
-		dev_err(&pdev->dev, "can't add lm4857 driver\n");
-		return ret;
-	}
-
-	memset(&info, 0, sizeof(struct i2c_board_info));
-	info.addr = i2c_address;
-	strlcpy(info.type, "neo1973_lm4857", I2C_NAME_SIZE);
-
-	adapter = i2c_get_adapter(i2c_bus);
-	if (!adapter) {
-		dev_err(&pdev->dev, "can't get i2c adapter %d\n", i2c_bus);
-		goto err_driver;
-	}
-
-	client = i2c_new_device(adapter, &info);
-	i2c_put_adapter(adapter);
-	if (!client) {
-		dev_err(&pdev->dev, "can't add lm4857 device at 0x%x\n",
-			(unsigned int)info.addr);
-		goto err_driver;
-	}
-
-	lm4857_client = client;
-	return 0;
-
-err_driver:
-	i2c_del_driver(&lm4857_i2c_driver);
-	return -ENODEV;
-}
 
 static int __init neo1973_init(void)
 {
@@ -736,8 +697,8 @@ static int __init neo1973_init(void)
 		return ret;
 	}
 
-	ret = neo1973_add_lm4857_device(neo1973_snd_device,
-					neo1973_wm8753_setup, 0x7C);
+	ret = i2c_add_driver(&lm4857_i2c_driver);
+
 	if (ret != 0)
 		platform_device_unregister(neo1973_snd_device);
 
@@ -748,7 +709,6 @@ static void __exit neo1973_exit(void)
 {
 	DBG("Entered %s\n", __func__);
 
-	i2c_unregister_device(lm4857_client);
 	i2c_del_driver(&lm4857_i2c_driver);
 	platform_device_unregister(neo1973_snd_device);
 }
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index ad381138fc2e..462e635dfc74 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -4,8 +4,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *         with code, comments and ideas from :-
  *         Richard Purdie <richard@openedhand.com>
  *
@@ -1886,7 +1885,7 @@ module_init(snd_soc_init);
 module_exit(snd_soc_exit);
 
 /* Module information */
-MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
 MODULE_DESCRIPTION("ALSA SoC Core");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:soc-audio");
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 9ca9c08610fa..efbd0b37810a 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2,8 +2,7 @@
  * soc-dapm.c  --  ALSA SoC Dynamic Audio Power Management
  *
  * Copyright 2005 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -1484,6 +1483,26 @@ int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin)
 EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
 
 /**
+ * snd_soc_dapm_nc_pin - permanently disable pin.
+ * @codec: SoC codec
+ * @pin: pin name
+ *
+ * Marks the specified pin as being not connected, disabling it along
+ * any parent or child widgets.  At present this is identical to
+ * snd_soc_dapm_disable_pin() but in future it will be extended to do
+ * additional things such as disabling controls which only affect
+ * paths through the pin.
+ *
+ * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
+ * do any widget power switching.
+ */
+int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, char *pin)
+{
+	return snd_soc_dapm_set_pin(codec, pin, 0);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
+
+/**
  * snd_soc_dapm_get_pin_status - get audio pin status
  * @codec: audio codec
  * @pin: audio signal pin endpoint (or start point)
@@ -1521,6 +1540,6 @@ void snd_soc_dapm_free(struct snd_soc_device *socdev)
 EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
 
 /* Module information */
-MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
 MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
 MODULE_LICENSE("GPL");